1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.asamk
.signal
.manager
.SignalDependencies
;
4 import org
.asamk
.signal
.manager
.TrustLevel
;
5 import org
.asamk
.signal
.manager
.storage
.SignalAccount
;
6 import org
.asamk
.signal
.manager
.storage
.recipients
.RecipientId
;
7 import org
.asamk
.signal
.manager
.util
.Utils
;
8 import org
.slf4j
.Logger
;
9 import org
.slf4j
.LoggerFactory
;
10 import org
.whispersystems
.libsignal
.IdentityKey
;
11 import org
.whispersystems
.libsignal
.fingerprint
.Fingerprint
;
12 import org
.whispersystems
.libsignal
.fingerprint
.FingerprintParsingException
;
13 import org
.whispersystems
.libsignal
.fingerprint
.FingerprintVersionMismatchException
;
14 import org
.whispersystems
.libsignal
.fingerprint
.ScannableFingerprint
;
15 import org
.whispersystems
.signalservice
.api
.messages
.SendMessageResult
;
16 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
18 import java
.io
.IOException
;
19 import java
.util
.Arrays
;
20 import java
.util
.Date
;
21 import java
.util
.function
.Function
;
23 import static org
.asamk
.signal
.manager
.config
.ServiceConfig
.capabilities
;
25 public class IdentityHelper
{
27 private final static Logger logger
= LoggerFactory
.getLogger(IdentityHelper
.class);
29 private final SignalAccount account
;
30 private final SignalDependencies dependencies
;
31 private final SignalServiceAddressResolver addressResolver
;
32 private final SyncHelper syncHelper
;
33 private final ProfileHelper profileHelper
;
35 public IdentityHelper(
36 final SignalAccount account
,
37 final SignalDependencies dependencies
,
38 final SignalServiceAddressResolver addressResolver
,
39 final SyncHelper syncHelper
,
40 final ProfileHelper profileHelper
42 this.account
= account
;
43 this.dependencies
= dependencies
;
44 this.addressResolver
= addressResolver
;
45 this.syncHelper
= syncHelper
;
46 this.profileHelper
= profileHelper
;
49 public boolean trustIdentityVerified(RecipientId recipientId
, byte[] fingerprint
) {
50 return trustIdentity(recipientId
,
51 identityKey
-> Arrays
.equals(identityKey
.serialize(), fingerprint
),
52 TrustLevel
.TRUSTED_VERIFIED
);
55 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, String safetyNumber
) {
56 return trustIdentity(recipientId
,
57 identityKey
-> safetyNumber
.equals(computeSafetyNumber(recipientId
, identityKey
)),
58 TrustLevel
.TRUSTED_VERIFIED
);
61 public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId
, byte[] safetyNumber
) {
62 return trustIdentity(recipientId
, identityKey
-> {
63 final var fingerprint
= computeSafetyNumberForScanning(recipientId
, identityKey
);
65 return fingerprint
!= null && fingerprint
.compareTo(safetyNumber
);
66 } catch (FingerprintVersionMismatchException
| FingerprintParsingException e
) {
69 }, TrustLevel
.TRUSTED_VERIFIED
);
72 public boolean trustIdentityAllKeys(RecipientId recipientId
) {
73 return trustIdentity(recipientId
, identityKey
-> true, TrustLevel
.TRUSTED_UNVERIFIED
);
76 public String
computeSafetyNumber(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
77 var address
= addressResolver
.resolveSignalServiceAddress(recipientId
);
78 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
79 return fingerprint
== null ?
null : fingerprint
.getDisplayableFingerprint().getDisplayText();
82 public ScannableFingerprint
computeSafetyNumberForScanning(RecipientId recipientId
, IdentityKey theirIdentityKey
) {
83 var address
= addressResolver
.resolveSignalServiceAddress(recipientId
);
84 final Fingerprint fingerprint
= computeSafetyNumberFingerprint(address
, theirIdentityKey
);
85 return fingerprint
== null ?
null : fingerprint
.getScannableFingerprint();
88 private Fingerprint
computeSafetyNumberFingerprint(
89 final SignalServiceAddress theirAddress
, final IdentityKey theirIdentityKey
91 return Utils
.computeSafetyNumber(capabilities
.isUuid(),
92 account
.getSelfAddress(),
93 account
.getIdentityKeyPair().getPublicKey(),
98 private boolean trustIdentity(
99 RecipientId recipientId
, Function
<IdentityKey
, Boolean
> verifier
, TrustLevel trustLevel
101 var identity
= account
.getIdentityKeyStore().getIdentity(recipientId
);
102 if (identity
== null) {
106 if (!verifier
.apply(identity
.getIdentityKey())) {
110 account
.getIdentityKeyStore().setIdentityTrustLevel(recipientId
, identity
.getIdentityKey(), trustLevel
);
112 var address
= addressResolver
.resolveSignalServiceAddress(recipientId
);
113 syncHelper
.sendVerifiedMessage(address
, identity
.getIdentityKey(), trustLevel
);
114 } catch (IOException e
) {
115 logger
.warn("Failed to send verification sync message: {}", e
.getMessage());
121 public void handleIdentityFailure(
122 final RecipientId recipientId
, final SendMessageResult
.IdentityFailure identityFailure
124 final var identityKey
= identityFailure
.getIdentityKey();
125 if (identityKey
!= null) {
126 final var newIdentity
= account
.getIdentityKeyStore().saveIdentity(recipientId
, identityKey
, new Date());
128 account
.getSessionStore().archiveSessions(recipientId
);
131 // Retrieve profile to get the current identity key from the server
132 profileHelper
.refreshRecipientProfile(recipientId
);