From 11c90fa0324347bf2b7ba56855ccd45898141569 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 21 Aug 2021 18:37:51 +0200 Subject: [PATCH] Add json output listIdentities command --- .../org/asamk/signal/manager/Manager.java | 16 +++- .../org/asamk/signal/manager/util/Utils.java | 8 +- .../commands/ListIdentitiesCommand.java | 75 +++++++++++++++---- src/main/java/org/asamk/signal/util/Hex.java | 5 ++ src/main/java/org/asamk/signal/util/Util.java | 9 ++- 5 files changed, 91 insertions(+), 22 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index c4b69665..e2306dec 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -2664,14 +2664,22 @@ public class Manager implements Closeable { } } - public String computeSafetyNumber( - SignalServiceAddress theirAddress, IdentityKey theirIdentityKey - ) { - return Utils.computeSafetyNumber(ServiceConfig.capabilities.isUuid(), + public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { + final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(), + account.getSelfAddress(), + getIdentityKeyPair().getPublicKey(), + theirAddress, + 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 diff --git a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java index b0a9bbb1..a2466311 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java @@ -1,6 +1,7 @@ package org.asamk.signal.manager.util; import org.whispersystems.libsignal.IdentityKey; +import org.whispersystems.libsignal.fingerprint.Fingerprint; import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.StreamDetails; @@ -36,7 +37,7 @@ public class Utils { return new StreamDetails(stream, mime, size); } - public static String computeSafetyNumber( + public static Fingerprint computeSafetyNumber( boolean isUuidCapable, SignalServiceAddress ownAddress, IdentityKey ownIdentityKey, @@ -56,18 +57,17 @@ public class Utils { // Version 1: E164 user version = 1; if (!ownAddress.getNumber().isPresent() || !theirAddress.getNumber().isPresent()) { - return "INVALID ID"; + return null; } ownId = ownAddress.getNumber().get().getBytes(); theirId = theirAddress.getNumber().get().getBytes(); } - var fingerprint = new NumericFingerprintGenerator(5200).createFor(version, + return new NumericFingerprintGenerator(5200).createFor(version, ownId, ownIdentityKey, theirId, theirIdentityKey); - return fingerprint.getDisplayableFingerprint().getDisplayText(); } public static SignalServiceAddress getSignalServiceAddressFromIdentifier(final String identifier) { diff --git a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java index f996f3b5..49ca2546 100644 --- a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java @@ -3,6 +3,7 @@ package org.asamk.signal.commands; import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; +import org.asamk.signal.JsonWriter; import org.asamk.signal.OutputWriter; import org.asamk.signal.PlainTextWriter; 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.util.InvalidNumberException; +import java.util.Base64; 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); @@ -48,26 +52,71 @@ public class ListIdentitiesCommand implements LocalCommand { public void handleCommand( final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { - final var writer = (PlainTextWriter) outputWriter; - var number = ns.getString("number"); + List identities; if (number == null) { - for (var identity : m.getIdentities()) { - printIdentityFingerprint(writer, m, identity); + identities = m.getIdentities(); + } else { + try { + identities = m.getIdentities(number); + } catch (InvalidNumberException e) { + throw new UserErrorException("Invalid number: " + e.getMessage()); } - return; } - List identities; - try { - identities = m.getIdentities(number); - } catch (InvalidNumberException e) { - throw new UserErrorException("Invalid number: " + e.getMessage()); + if (outputWriter instanceof PlainTextWriter) { + 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; - for (var id : identities) { - printIdentityFingerprint(writer, m, id); + 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; } } } diff --git a/src/main/java/org/asamk/signal/util/Hex.java b/src/main/java/org/asamk/signal/util/Hex.java index f5f7a6ad..596f23a9 100644 --- a/src/main/java/org/asamk/signal/util/Hex.java +++ b/src/main/java/org/asamk/signal/util/Hex.java @@ -8,11 +8,16 @@ public class Hex { } public static String toString(byte[] bytes) { + if (bytes.length == 0) { + return ""; + } + var buf = new StringBuffer(); for (final var aByte : bytes) { appendHexChar(buf, aByte); buf.append(" "); } + buf.deleteCharAt(buf.length() - 1); return buf.toString(); } diff --git a/src/main/java/org/asamk/signal/util/Util.java b/src/main/java/org/asamk/signal/util/Util.java index 31c6b68e..0afe0910 100644 --- a/src/main/java/org/asamk/signal/util/Util.java +++ b/src/main/java/org/asamk/signal/util/Util.java @@ -45,11 +45,18 @@ public class Util { } public static String formatSafetyNumber(String digits) { + if (digits == null) { + return null; + } + final var partCount = 12; var partSize = digits.length() / partCount; var f = new StringBuilder(digits.length() + partCount); 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(); } -- 2.50.1