1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.asamk
.signal
.manager
.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
.slf4j
.Logger
;
8 import org
.slf4j
.LoggerFactory
;
9 import org
.whispersystems
.libsignal
.IdentityKey
;
10 import org
.whispersystems
.libsignal
.fingerprint
.Fingerprint
;
11 import org
.whispersystems
.libsignal
.fingerprint
.FingerprintParsingException
;
12 import org
.whispersystems
.libsignal
.fingerprint
.FingerprintVersionMismatchException
;
13 import org
.whispersystems
.libsignal
.fingerprint
.ScannableFingerprint
;
14 import org
.whispersystems
.signalservice
.api
.messages
.SendMessageResult
;
15 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
17 import java
.io
.IOException
;
18 import java
.util
.Arrays
;
19 import java
.util
.Date
;
20 import java
.util
.function
.Function
;
22 import static org
.asamk
.signal
.manager
.config
.ServiceConfig
.capabilities
;
24 public class IdentityHelper
{
26 private final static Logger logger
= LoggerFactory
.getLogger(IdentityHelper
.class);
28 private final SignalAccount account
;
29 private final Context context
;
31 public IdentityHelper(final Context context
) {
32 this.account
= context
.getAccount();
33 this.context
= context
;
36 public boolean trustIdentityVerified(RecipientId recipientId
, byte[] fingerprint
) {
37 return trustIdentity(recipientId
,
38 identityKey
-> Arrays
.equals(identityKey
.serialize(), fingerprint
),
39 TrustLevel
.TRUSTED_VERIFIED
);
42 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, String safetyNumber
) {
43 return trustIdentity(recipientId
,
44 identityKey
-> safetyNumber
.equals(computeSafetyNumber(recipientId
, identityKey
)),
45 TrustLevel
.TRUSTED_VERIFIED
);
48 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, byte[] safetyNumber
) {
49 return trustIdentity(recipientId
, identityKey
-> {
50 final var fingerprint
= computeSafetyNumberForScanning(recipientId
, identityKey
);
52 return fingerprint
!= null && fingerprint
.compareTo(safetyNumber
);
53 } catch (FingerprintVersionMismatchException
| FingerprintParsingException e
) {
56 }, TrustLevel
.TRUSTED_VERIFIED
);
59 public boolean trustIdentityAllKeys(RecipientId recipientId
) {
60 return trustIdentity(recipientId
, identityKey
-> true, TrustLevel
.TRUSTED_UNVERIFIED
);
63 public String
computeSafetyNumber(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
64 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
65 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
66 return fingerprint
== null ?
null : fingerprint
.getDisplayableFingerprint().getDisplayText();
69 public ScannableFingerprint
computeSafetyNumberForScanning(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
70 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
71 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
72 return fingerprint
== null ?
null : fingerprint
.getScannableFingerprint();
75 private Fingerprint
computeSafetyNumberFingerprint(
76 final SignalServiceAddress theirAddress
, final IdentityKey theirIdentityKey
78 return Utils
.computeSafetyNumber(capabilities
.isUuid(),
79 account
.getSelfAddress(),
80 account
.getIdentityKeyPair().getPublicKey(),
85 private boolean trustIdentity(
86 RecipientId recipientId
, Function
<IdentityKey
, Boolean
> verifier
, TrustLevel trustLevel
88 var identity
= account
.getIdentityKeyStore().getIdentity(recipientId
);
89 if (identity
== null) {
93 if (!verifier
.apply(identity
.getIdentityKey())) {
97 account
.getIdentityKeyStore().setIdentityTrustLevel(recipientId
, identity
.getIdentityKey(), trustLevel
);
99 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
100 context
.getSyncHelper().sendVerifiedMessage(address
, identity
.getIdentityKey(), trustLevel
);
101 } catch (IOException e
) {
102 logger
.warn("Failed to send verification sync message: {}", e
.getMessage());
108 public void handleIdentityFailure(
109 final RecipientId recipientId
, final SendMessageResult
.IdentityFailure identityFailure
111 final var identityKey
= identityFailure
.getIdentityKey();
112 if (identityKey
!= null) {
113 final var newIdentity
= account
.getIdentityKeyStore().saveIdentity(recipientId
, identityKey
, new Date());
115 account
.getSessionStore().archiveSessions(recipientId
);
116 account
.getSenderKeyStore().deleteSharedWith(recipientId
);
119 // Retrieve profile to get the current identity key from the server
120 context
.getProfileHelper().refreshRecipientProfile(recipientId
);