Command to check if number is registered (#391)

* Added the isRegistered command

* Minor fixes

* Corrected description

* Added AsamK's suggestions

Fixes #178
This commit is contained in:
Atomic-Bean 2021-01-04 06:32:34 +10:30 committed by GitHub
parent a475bc50e9
commit 1c5de83370
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 0 deletions

View file

@ -124,6 +124,15 @@ Only works, if this is the master device.
Specify the device you want to remove. Specify the device you want to remove.
Use listDevices to see the deviceIds. Use listDevices to see the deviceIds.
=== getUserStatus
Uses a list of phone numbers to determine the statuses of those users. Shows if they are registered on the Signal Servers or not.
[NUMBER [NUMBER ...]]::
One or more numbers to check.
*--json*::
Output the statuses as an array of json objects.
=== send === send
Send a message to another user or group. Send a message to another user or group.

View file

@ -11,6 +11,7 @@ public class Commands {
addCommand("addDevice", new AddDeviceCommand()); addCommand("addDevice", new AddDeviceCommand());
addCommand("block", new BlockCommand()); addCommand("block", new BlockCommand());
addCommand("daemon", new DaemonCommand()); addCommand("daemon", new DaemonCommand());
addCommand("getUserStatus", new GetUserStatusCommand());
addCommand("link", new LinkCommand()); addCommand("link", new LinkCommand());
addCommand("listContacts", new ListContactsCommand()); addCommand("listContacts", new ListContactsCommand());
addCommand("listDevices", new ListDevicesCommand()); addCommand("listDevices", new ListDevicesCommand());

View file

@ -0,0 +1,87 @@
package org.asamk.signal.commands;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.manager.Manager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.List;
public class GetUserStatusCommand implements LocalCommand {
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("number").help("Phone number").nargs("+");
subparser.help("Check if the specified phone number/s have been registered");
subparser.addArgument("--json")
.help("Output received messages in json format, one json object per line.")
.action(Arguments.storeTrue());
}
@Override
public int handleCommand(final Namespace ns, final Manager m) {
if (!m.isRegistered()) {
System.err.println("User is not registered.");
return 1;
}
// Setup the json object mapper
ObjectMapper jsonProcessor = new ObjectMapper();
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // disable autodetect
jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
// Get a map of registration statuses
Map<String, Boolean> registered;
try {
registered = m.areUsersRegistered(new HashSet<>(ns.<String>getList("number")));
} catch (IOException e) {
System.err.println("Unable to check if users are registered");
return 1;
}
// Output
if (ns.getBoolean("json")) {
List<JsonIsRegistered> objects = new ArrayList<>();
for (Map.Entry<String, Boolean> entry : registered.entrySet()) {
objects.add(new JsonIsRegistered(entry.getKey(), entry.getValue()));
}
try {
System.out.println(jsonProcessor.writeValueAsString(objects));
} catch (IOException e) {
System.err.println(e.getMessage());
}
} else {
for (Map.Entry<String, Boolean> entry : registered.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
return 0;
}
private class JsonIsRegistered {
String name;
boolean isRegistered;
public JsonIsRegistered(String name, boolean isRegistered) {
this.name = name;
this.isRegistered = isRegistered;
}
}
}

View file

@ -383,6 +383,28 @@ public class Manager implements Closeable {
return account.isRegistered(); return account.isRegistered();
} }
/**
* This is used for checking a set of phone numbers for registration on Signal
*
* @param numbers The set of phone number in question
* @return A map of numbers to booleans. True if registered, false otherwise. Should never be null
* @throws IOException if its unable to check if the users are registered
*/
public Map<String, Boolean> areUsersRegistered(Set<String> numbers) throws IOException {
// Note "contactDetails" has no optionals. It only gives us info on users who are registered
List<ContactTokenDetails> contactDetails = this.accountManager.getContacts(numbers);
// Make the initial map with all numbers set to false for now
Map<String, Boolean> usersRegistered = numbers.stream().collect(Collectors.toMap(x -> x, x -> false));
// Override the contacts we did obtain
for (ContactTokenDetails contactDetail : contactDetails) {
usersRegistered.put(contactDetail.getNumber(), true);
}
return usersRegistered;
}
public void register(boolean voiceVerification, String captcha) throws IOException { public void register(boolean voiceVerification, String captcha) throws IOException {
account.setPassword(KeyUtils.createPassword()); account.setPassword(KeyUtils.createPassword());