mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Add json output listIdentities command
This commit is contained in:
parent
70fc2381d3
commit
11c90fa032
5 changed files with 94 additions and 25 deletions
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue