1 package org
.asamk
.signal
.commands
;
3 import net
.sourceforge
.argparse4j
.inf
.Namespace
;
4 import net
.sourceforge
.argparse4j
.inf
.Subparser
;
6 import org
.asamk
.signal
.JsonWriter
;
7 import org
.asamk
.signal
.OutputWriter
;
8 import org
.asamk
.signal
.PlainTextWriter
;
9 import org
.asamk
.signal
.commands
.exceptions
.CommandException
;
10 import org
.asamk
.signal
.commands
.exceptions
.UserErrorException
;
11 import org
.asamk
.signal
.manager
.Manager
;
12 import org
.asamk
.signal
.manager
.storage
.identities
.IdentityInfo
;
13 import org
.asamk
.signal
.util
.Hex
;
14 import org
.asamk
.signal
.util
.Util
;
15 import org
.slf4j
.Logger
;
16 import org
.slf4j
.LoggerFactory
;
17 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
18 import org
.whispersystems
.signalservice
.api
.util
.InvalidNumberException
;
20 import java
.util
.Base64
;
21 import java
.util
.List
;
22 import java
.util
.UUID
;
23 import java
.util
.stream
.Collectors
;
25 public class ListIdentitiesCommand
implements JsonRpcLocalCommand
{
27 private final static Logger logger
= LoggerFactory
.getLogger(ListIdentitiesCommand
.class);
30 public String
getName() {
31 return "listIdentities";
34 private static void printIdentityFingerprint(PlainTextWriter writer
, Manager m
, IdentityInfo theirId
) {
35 final SignalServiceAddress address
= m
.resolveSignalServiceAddress(theirId
.getRecipientId());
36 var digits
= Util
.formatSafetyNumber(m
.computeSafetyNumber(address
, theirId
.getIdentityKey()));
37 writer
.println("{}: {} Added: {} Fingerprint: {} Safety Number: {}",
38 address
.getNumber().orNull(),
39 theirId
.getTrustLevel(),
40 theirId
.getDateAdded(),
41 Hex
.toString(theirId
.getFingerprint()),
46 public void attachToSubparser(final Subparser subparser
) {
47 subparser
.help("List all known identity keys and their trust status, fingerprint and safety number.");
48 subparser
.addArgument("-n", "--number").help("Only show identity keys for the given phone number.");
52 public void handleCommand(
53 final Namespace ns
, final Manager m
, final OutputWriter outputWriter
54 ) throws CommandException
{
55 var number
= ns
.getString("number");
57 List
<IdentityInfo
> identities
;
59 identities
= m
.getIdentities();
62 identities
= m
.getIdentities(number
);
63 } catch (InvalidNumberException e
) {
64 throw new UserErrorException("Invalid number: " + e
.getMessage());
68 if (outputWriter
instanceof PlainTextWriter
) {
69 final var writer
= (PlainTextWriter
) outputWriter
;
70 for (var id
: identities
) {
71 printIdentityFingerprint(writer
, m
, id
);
74 final var writer
= (JsonWriter
) outputWriter
;
75 final var jsonIdentities
= identities
.stream().map(id
-> {
76 final var address
= m
.resolveSignalServiceAddress(id
.getRecipientId());
77 var safetyNumber
= Util
.formatSafetyNumber(m
.computeSafetyNumber(address
, id
.getIdentityKey()));
78 var scannableSafetyNumber
= m
.computeSafetyNumberForScanning(address
, id
.getIdentityKey());
79 return new JsonIdentity(address
.getNumber().orNull(),
80 address
.getUuid().transform(UUID
::toString
).orNull(),
81 Hex
.toString(id
.getFingerprint()),
83 scannableSafetyNumber
== null
85 : Base64
.getEncoder().encodeToString(scannableSafetyNumber
),
86 id
.getTrustLevel().name(),
87 id
.getDateAdded().getTime());
88 }).collect(Collectors
.toList());
90 writer
.write(jsonIdentities
);
94 private static final class JsonIdentity
{
96 public final String number
;
97 public final String uuid
;
98 public final String fingerprint
;
99 public final String safetyNumber
;
100 public final String scannableSafetyNumber
;
101 public final String trustLevel
;
102 public final long addedTimestamp
;
104 private JsonIdentity(
107 final String fingerprint
,
108 final String safetyNumber
,
109 final String scannableSafetyNumber
,
110 final String trustLevel
,
111 final long addedTimestamp
113 this.number
= number
;
115 this.fingerprint
= fingerprint
;
116 this.safetyNumber
= safetyNumber
;
117 this.scannableSafetyNumber
= scannableSafetyNumber
;
118 this.trustLevel
= trustLevel
;
119 this.addedTimestamp
= addedTimestamp
;