]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java
Update libsignal-service-java
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / IdentityHelper.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.manager.api.TrustLevel;
4 import org.asamk.signal.manager.storage.SignalAccount;
5 import org.asamk.signal.manager.storage.recipients.RecipientId;
6 import org.asamk.signal.manager.util.Utils;
7 import org.signal.libsignal.protocol.IdentityKey;
8 import org.signal.libsignal.protocol.fingerprint.Fingerprint;
9 import org.signal.libsignal.protocol.fingerprint.FingerprintParsingException;
10 import org.signal.libsignal.protocol.fingerprint.FingerprintVersionMismatchException;
11 import org.signal.libsignal.protocol.fingerprint.ScannableFingerprint;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.whispersystems.signalservice.api.messages.SendMessageResult;
15 import org.whispersystems.signalservice.api.push.ServiceId;
16
17 import java.util.Arrays;
18 import java.util.function.BiFunction;
19
20 public class IdentityHelper {
21
22 private static final Logger logger = LoggerFactory.getLogger(IdentityHelper.class);
23
24 private final SignalAccount account;
25 private final Context context;
26
27 public IdentityHelper(final Context context) {
28 this.account = context.getAccount();
29 this.context = context;
30 }
31
32 public boolean trustIdentityVerified(RecipientId recipientId, byte[] fingerprint) {
33 return trustIdentity(recipientId,
34 (serviceId, identityKey) -> Arrays.equals(identityKey.serialize(), fingerprint),
35 TrustLevel.TRUSTED_VERIFIED);
36 }
37
38 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId, String safetyNumber) {
39 return trustIdentity(recipientId,
40 (serviceId, identityKey) -> safetyNumber.equals(computeSafetyNumber(serviceId, identityKey)),
41 TrustLevel.TRUSTED_VERIFIED);
42 }
43
44 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId, byte[] safetyNumber) {
45 return trustIdentity(recipientId, (serviceId, identityKey) -> {
46 final var fingerprint = computeSafetyNumberForScanning(serviceId, identityKey);
47 try {
48 return fingerprint != null && fingerprint.compareTo(safetyNumber);
49 } catch (FingerprintVersionMismatchException | FingerprintParsingException e) {
50 return false;
51 }
52 }, TrustLevel.TRUSTED_VERIFIED);
53 }
54
55 public boolean trustIdentityAllKeys(RecipientId recipientId) {
56 return trustIdentity(recipientId, (serviceId, identityKey) -> true, TrustLevel.TRUSTED_UNVERIFIED);
57 }
58
59 public String computeSafetyNumber(ServiceId serviceId, IdentityKey theirIdentityKey) {
60 final var fingerprint = computeSafetyNumberFingerprint(serviceId, theirIdentityKey);
61 return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText();
62 }
63
64 public ScannableFingerprint computeSafetyNumberForScanning(ServiceId serviceId, IdentityKey theirIdentityKey) {
65 var fingerprint = computeSafetyNumberFingerprint(serviceId, theirIdentityKey);
66 return fingerprint == null ? null : fingerprint.getScannableFingerprint();
67 }
68
69 private Fingerprint computeSafetyNumberFingerprint(
70 final ServiceId serviceId, final IdentityKey theirIdentityKey
71 ) {
72 if (!serviceId.isUnknown()) {
73 return Utils.computeSafetyNumberForUuid(account.getAci(),
74 account.getAciIdentityKeyPair().getPublicKey(),
75 serviceId,
76 theirIdentityKey);
77 }
78
79 final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
80 final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId);
81
82 if (address.number().isEmpty()) {
83 return null;
84 }
85 return Utils.computeSafetyNumberForNumber(account.getNumber(),
86 account.getAciIdentityKeyPair().getPublicKey(),
87 address.number().get(),
88 theirIdentityKey);
89 }
90
91 private boolean trustIdentity(
92 RecipientId recipientId, BiFunction<ServiceId, IdentityKey, Boolean> verifier, TrustLevel trustLevel
93 ) {
94 final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId);
95 final var serviceId = address.serviceId().orElse(null);
96 if (serviceId == null) {
97 return false;
98 }
99 var identity = account.getIdentityKeyStore().getIdentityInfo(serviceId);
100 if (identity == null) {
101 return false;
102 }
103
104 if (!verifier.apply(serviceId, identity.getIdentityKey())) {
105 return false;
106 }
107
108 account.getIdentityKeyStore().setIdentityTrustLevel(serviceId, identity.getIdentityKey(), trustLevel);
109 context.getSyncHelper()
110 .sendVerifiedMessage(address.toSignalServiceAddress(), identity.getIdentityKey(), trustLevel);
111
112 return true;
113 }
114
115 public void handleIdentityFailure(
116 final RecipientId recipientId,
117 final ServiceId serviceId,
118 final SendMessageResult.IdentityFailure identityFailure
119 ) {
120 final var identityKey = identityFailure.getIdentityKey();
121 if (identityKey != null) {
122 account.getIdentityKeyStore().saveIdentity(serviceId, identityKey);
123 } else {
124 // Retrieve profile to get the current identity key from the server
125 context.getProfileHelper().refreshRecipientProfile(recipientId);
126 }
127 }
128 }