1 package org
.asamk
.signal
.manager
.helper
;
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
;
17 import java
.util
.Arrays
;
18 import java
.util
.function
.BiFunction
;
20 public class IdentityHelper
{
22 private static final Logger logger
= LoggerFactory
.getLogger(IdentityHelper
.class);
24 private final SignalAccount account
;
25 private final Context context
;
27 public IdentityHelper(final Context context
) {
28 this.account
= context
.getAccount();
29 this.context
= context
;
32 public boolean trustIdentityVerified(RecipientId recipientId
, byte[] fingerprint
) {
33 return trustIdentity(recipientId
,
34 (serviceId
, identityKey
) -> Arrays
.equals(identityKey
.serialize(), fingerprint
),
35 TrustLevel
.TRUSTED_VERIFIED
);
38 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, String safetyNumber
) {
39 return trustIdentity(recipientId
,
40 (serviceId
, identityKey
) -> safetyNumber
.equals(computeSafetyNumber(serviceId
, identityKey
)),
41 TrustLevel
.TRUSTED_VERIFIED
);
44 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, byte[] safetyNumber
) {
45 return trustIdentity(recipientId
, (serviceId
, identityKey
) -> {
46 final var fingerprint
= computeSafetyNumberForScanning(serviceId
, identityKey
);
48 return fingerprint
!= null && fingerprint
.compareTo(safetyNumber
);
49 } catch (FingerprintVersionMismatchException
| FingerprintParsingException e
) {
52 }, TrustLevel
.TRUSTED_VERIFIED
);
55 public boolean trustIdentityAllKeys(RecipientId recipientId
) {
56 return trustIdentity(recipientId
, (serviceId
, identityKey
) -> true, TrustLevel
.TRUSTED_UNVERIFIED
);
59 public String
computeSafetyNumber(ServiceId serviceId
, IdentityKey theirIdentityKey
) {
60 final var fingerprint
= computeSafetyNumberFingerprint(serviceId
, theirIdentityKey
);
61 return fingerprint
== null ?
null : fingerprint
.getDisplayableFingerprint().getDisplayText();
64 public ScannableFingerprint
computeSafetyNumberForScanning(ServiceId serviceId
, IdentityKey theirIdentityKey
) {
65 var fingerprint
= computeSafetyNumberFingerprint(serviceId
, theirIdentityKey
);
66 return fingerprint
== null ?
null : fingerprint
.getScannableFingerprint();
69 private Fingerprint
computeSafetyNumberFingerprint(
70 final ServiceId serviceId
, final IdentityKey theirIdentityKey
72 if (!serviceId
.isUnknown()) {
73 return Utils
.computeSafetyNumberForUuid(account
.getAci(),
74 account
.getAciIdentityKeyPair().getPublicKey(),
79 final var recipientId
= account
.getRecipientResolver().resolveRecipient(serviceId
);
80 final var address
= account
.getRecipientAddressResolver().resolveRecipientAddress(recipientId
);
82 if (address
.number().isEmpty()) {
85 return Utils
.computeSafetyNumberForNumber(account
.getNumber(),
86 account
.getAciIdentityKeyPair().getPublicKey(),
87 address
.number().get(),
91 private boolean trustIdentity(
92 RecipientId recipientId
, BiFunction
<ServiceId
, IdentityKey
, Boolean
> verifier
, TrustLevel trustLevel
94 final var address
= account
.getRecipientAddressResolver().resolveRecipientAddress(recipientId
);
95 final var serviceId
= address
.serviceId().orElse(null);
96 if (serviceId
== null) {
99 var identity
= account
.getIdentityKeyStore().getIdentityInfo(serviceId
);
100 if (identity
== null) {
104 if (!verifier
.apply(serviceId
, identity
.getIdentityKey())) {
108 account
.getIdentityKeyStore().setIdentityTrustLevel(serviceId
, identity
.getIdentityKey(), trustLevel
);
109 context
.getSyncHelper()
110 .sendVerifiedMessage(address
.toSignalServiceAddress(), identity
.getIdentityKey(), trustLevel
);
115 public void handleIdentityFailure(
116 final RecipientId recipientId
,
117 final ServiceId serviceId
,
118 final SendMessageResult
.IdentityFailure identityFailure
120 final var identityKey
= identityFailure
.getIdentityKey();
121 if (identityKey
!= null) {
122 account
.getIdentityKeyStore().saveIdentity(serviceId
, identityKey
);
124 // Retrieve profile to get the current identity key from the server
125 context
.getProfileHelper().refreshRecipientProfile(recipientId
);