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
.SignalServiceAddress
;
17 import java
.io
.IOException
;
18 import java
.util
.Arrays
;
19 import java
.util
.function
.Function
;
21 import static org
.asamk
.signal
.manager
.config
.ServiceConfig
.capabilities
;
23 public class IdentityHelper
{
25 private final static Logger logger
= LoggerFactory
.getLogger(IdentityHelper
.class);
27 private final SignalAccount account
;
28 private final Context context
;
30 public IdentityHelper(final Context context
) {
31 this.account
= context
.getAccount();
32 this.context
= context
;
35 public boolean trustIdentityVerified(RecipientId recipientId
, byte[] fingerprint
) {
36 return trustIdentity(recipientId
,
37 identityKey
-> Arrays
.equals(identityKey
.serialize(), fingerprint
),
38 TrustLevel
.TRUSTED_VERIFIED
);
41 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, String safetyNumber
) {
42 return trustIdentity(recipientId
,
43 identityKey
-> safetyNumber
.equals(computeSafetyNumber(recipientId
, identityKey
)),
44 TrustLevel
.TRUSTED_VERIFIED
);
47 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, byte[] safetyNumber
) {
48 return trustIdentity(recipientId
, identityKey
-> {
49 final var fingerprint
= computeSafetyNumberForScanning(recipientId
, identityKey
);
51 return fingerprint
!= null && fingerprint
.compareTo(safetyNumber
);
52 } catch (FingerprintVersionMismatchException
| FingerprintParsingException e
) {
55 }, TrustLevel
.TRUSTED_VERIFIED
);
58 public boolean trustIdentityAllKeys(RecipientId recipientId
) {
59 return trustIdentity(recipientId
, identityKey
-> true, TrustLevel
.TRUSTED_UNVERIFIED
);
62 public String
computeSafetyNumber(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
63 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
64 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
65 return fingerprint
== null ?
null : fingerprint
.getDisplayableFingerprint().getDisplayText();
68 public ScannableFingerprint
computeSafetyNumberForScanning(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
69 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
70 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
71 return fingerprint
== null ?
null : fingerprint
.getScannableFingerprint();
74 private Fingerprint
computeSafetyNumberFingerprint(
75 final SignalServiceAddress theirAddress
, final IdentityKey theirIdentityKey
77 return Utils
.computeSafetyNumber(capabilities
.isUuid(),
78 account
.getSelfAddress(),
79 account
.getAciIdentityKeyPair().getPublicKey(),
84 private boolean trustIdentity(
85 RecipientId recipientId
, Function
<IdentityKey
, Boolean
> verifier
, TrustLevel trustLevel
87 var identity
= account
.getIdentityKeyStore().getIdentityInfo(recipientId
);
88 if (identity
== null) {
92 if (!verifier
.apply(identity
.getIdentityKey())) {
96 account
.getIdentityKeyStore().setIdentityTrustLevel(recipientId
, identity
.getIdentityKey(), trustLevel
);
98 var address
= context
.getRecipientHelper().resolveSignalServiceAddress(recipientId
);
99 context
.getSyncHelper().sendVerifiedMessage(address
, identity
.getIdentityKey(), trustLevel
);
100 } catch (IOException e
) {
101 logger
.warn("Failed to send verification sync message: {}", e
.getMessage());
107 public void handleIdentityFailure(
108 final RecipientId recipientId
, final SendMessageResult
.IdentityFailure identityFailure
110 final var identityKey
= identityFailure
.getIdentityKey();
111 if (identityKey
!= null) {
112 account
.getIdentityKeyStore().saveIdentity(recipientId
, identityKey
);
114 // Retrieve profile to get the current identity key from the server
115 context
.getProfileHelper().refreshRecipientProfile(recipientId
);