Add json output listIdentities command

This commit is contained in:
AsamK 2021-08-21 18:37:51 +02:00
parent 70fc2381d3
commit 11c90fa032
5 changed files with 94 additions and 25 deletions

View file

@ -2664,14 +2664,22 @@ public class Manager implements Closeable {
} }
} }
public String computeSafetyNumber( public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) {
SignalServiceAddress theirAddress, IdentityKey theirIdentityKey final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(),
) {
return Utils.computeSafetyNumber(ServiceConfig.capabilities.isUuid(),
account.getSelfAddress(), account.getSelfAddress(),
getIdentityKeyPair().getPublicKey(), getIdentityKeyPair().getPublicKey(),
theirAddress, theirAddress,
theirIdentityKey); theirIdentityKey);
return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText();
}
public byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) {
final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(),
account.getSelfAddress(),
getIdentityKeyPair().getPublicKey(),
theirAddress,
theirIdentityKey);
return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized();
} }
@Deprecated @Deprecated

View file

@ -1,6 +1,7 @@
package org.asamk.signal.manager.util; package org.asamk.signal.manager.util;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.fingerprint.Fingerprint;
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator; import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.StreamDetails;
@ -36,7 +37,7 @@ public class Utils {
return new StreamDetails(stream, mime, size); return new StreamDetails(stream, mime, size);
} }
public static String computeSafetyNumber( public static Fingerprint computeSafetyNumber(
boolean isUuidCapable, boolean isUuidCapable,
SignalServiceAddress ownAddress, SignalServiceAddress ownAddress,
IdentityKey ownIdentityKey, IdentityKey ownIdentityKey,
@ -56,18 +57,17 @@ public class Utils {
// Version 1: E164 user // Version 1: E164 user
version = 1; version = 1;
if (!ownAddress.getNumber().isPresent() || !theirAddress.getNumber().isPresent()) { if (!ownAddress.getNumber().isPresent() || !theirAddress.getNumber().isPresent()) {
return "INVALID ID"; return null;
} }
ownId = ownAddress.getNumber().get().getBytes(); ownId = ownAddress.getNumber().get().getBytes();
theirId = theirAddress.getNumber().get().getBytes(); theirId = theirAddress.getNumber().get().getBytes();
} }
var fingerprint = new NumericFingerprintGenerator(5200).createFor(version, return new NumericFingerprintGenerator(5200).createFor(version,
ownId, ownId,
ownIdentityKey, ownIdentityKey,
theirId, theirId,
theirIdentityKey); theirIdentityKey);
return fingerprint.getDisplayableFingerprint().getDisplayText();
} }
public static SignalServiceAddress getSignalServiceAddressFromIdentifier(final String identifier) { public static SignalServiceAddress getSignalServiceAddressFromIdentifier(final String identifier) {

View file

@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser; import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputWriter; import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriter; import org.asamk.signal.PlainTextWriter;
import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.CommandException;
@ -16,9 +17,12 @@ import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class ListIdentitiesCommand implements LocalCommand { public class ListIdentitiesCommand implements JsonRpcLocalCommand {
private final static Logger logger = LoggerFactory.getLogger(ListIdentitiesCommand.class); private final static Logger logger = LoggerFactory.getLogger(ListIdentitiesCommand.class);
@ -48,26 +52,71 @@ public class ListIdentitiesCommand implements LocalCommand {
public void handleCommand( public void handleCommand(
final Namespace ns, final Manager m, final OutputWriter outputWriter final Namespace ns, final Manager m, final OutputWriter outputWriter
) throws CommandException { ) throws CommandException {
final var writer = (PlainTextWriter) outputWriter;
var number = ns.getString("number"); var number = ns.getString("number");
if (number == null) {
for (var identity : m.getIdentities()) {
printIdentityFingerprint(writer, m, identity);
}
return;
}
List<IdentityInfo> identities; List<IdentityInfo> identities;
try { if (number == null) {
identities = m.getIdentities(number); identities = m.getIdentities();
} catch (InvalidNumberException e) { } else {
throw new UserErrorException("Invalid number: " + e.getMessage()); try {
identities = m.getIdentities(number);
} catch (InvalidNumberException e) {
throw new UserErrorException("Invalid number: " + e.getMessage());
}
} }
for (var id : identities) { if (outputWriter instanceof PlainTextWriter) {
printIdentityFingerprint(writer, m, id); final var writer = (PlainTextWriter) outputWriter;
for (var id : identities) {
printIdentityFingerprint(writer, m, id);
}
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonIdentities = identities.stream().map(id -> {
final var address = m.resolveSignalServiceAddress(id.getRecipientId());
var safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(address, id.getIdentityKey()));
var scannableSafetyNumber = m.computeSafetyNumberForScanning(address, id.getIdentityKey());
return new JsonIdentity(address.getNumber().orNull(),
address.getUuid().transform(UUID::toString).orNull(),
Hex.toString(id.getFingerprint()),
safetyNumber,
scannableSafetyNumber == null
? null
: Base64.getEncoder().encodeToString(scannableSafetyNumber),
id.getTrustLevel().name(),
id.getDateAdded().getTime());
}).collect(Collectors.toList());
writer.write(jsonIdentities);
}
}
private static final class JsonIdentity {
public final String number;
public final String uuid;
public final String fingerprint;
public final String safetyNumber;
public final String scannableSafetyNumber;
public final String trustLevel;
public final long addedTimestamp;
private JsonIdentity(
final String number,
final String uuid,
final String fingerprint,
final String safetyNumber,
final String scannableSafetyNumber,
final String trustLevel,
final long addedTimestamp
) {
this.number = number;
this.uuid = uuid;
this.fingerprint = fingerprint;
this.safetyNumber = safetyNumber;
this.scannableSafetyNumber = scannableSafetyNumber;
this.trustLevel = trustLevel;
this.addedTimestamp = addedTimestamp;
} }
} }
} }

View file

@ -8,11 +8,16 @@ public class Hex {
} }
public static String toString(byte[] bytes) { public static String toString(byte[] bytes) {
if (bytes.length == 0) {
return "";
}
var buf = new StringBuffer(); var buf = new StringBuffer();
for (final var aByte : bytes) { for (final var aByte : bytes) {
appendHexChar(buf, aByte); appendHexChar(buf, aByte);
buf.append(" "); buf.append(" ");
} }
buf.deleteCharAt(buf.length() - 1);
return buf.toString(); return buf.toString();
} }

View file

@ -45,11 +45,18 @@ public class Util {
} }
public static String formatSafetyNumber(String digits) { public static String formatSafetyNumber(String digits) {
if (digits == null) {
return null;
}
final var partCount = 12; final var partCount = 12;
var partSize = digits.length() / partCount; var partSize = digits.length() / partCount;
var f = new StringBuilder(digits.length() + partCount); var f = new StringBuilder(digits.length() + partCount);
for (var i = 0; i < partCount; i++) { for (var i = 0; i < partCount; i++) {
f.append(digits, i * partSize, (i * partSize) + partSize).append(" "); f.append(digits, i * partSize, (i * partSize) + partSize);
if (i != partCount - 1) {
f.append(" ");
}
} }
return f.toString(); return f.toString();
} }