]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/UnidentifiedAccessHelper.java
Move all message decryption to IncomingMessageHandler
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / UnidentifiedAccessHelper.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.manager.storage.recipients.RecipientId;
4 import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
5 import org.whispersystems.libsignal.util.guava.Optional;
6 import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
7 import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
8
9 import java.util.List;
10 import java.util.stream.Collectors;
11
12 import static org.whispersystems.signalservice.internal.util.Util.getSecretBytes;
13
14 public class UnidentifiedAccessHelper {
15
16 private final SelfProfileKeyProvider selfProfileKeyProvider;
17
18 private final ProfileKeyProvider profileKeyProvider;
19
20 private final ProfileProvider profileProvider;
21
22 private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider;
23
24 public UnidentifiedAccessHelper(
25 final SelfProfileKeyProvider selfProfileKeyProvider,
26 final ProfileKeyProvider profileKeyProvider,
27 final ProfileProvider profileProvider,
28 final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
29 ) {
30 this.selfProfileKeyProvider = selfProfileKeyProvider;
31 this.profileKeyProvider = profileKeyProvider;
32 this.profileProvider = profileProvider;
33 this.senderCertificateProvider = senderCertificateProvider;
34 }
35
36 private byte[] getSelfUnidentifiedAccessKey() {
37 return UnidentifiedAccess.deriveAccessKeyFrom(selfProfileKeyProvider.getProfileKey());
38 }
39
40 public byte[] getTargetUnidentifiedAccessKey(RecipientId recipient) {
41 var targetProfile = profileProvider.getProfile(recipient);
42 if (targetProfile == null) {
43 return null;
44 }
45
46 switch (targetProfile.getUnidentifiedAccessMode()) {
47 case ENABLED:
48 var theirProfileKey = profileKeyProvider.getProfileKey(recipient);
49 if (theirProfileKey == null) {
50 return null;
51 }
52
53 return UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
54 case UNRESTRICTED:
55 return createUnrestrictedUnidentifiedAccess();
56 default:
57 return null;
58 }
59 }
60
61 public Optional<UnidentifiedAccessPair> getAccessForSync() {
62 var selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
63 var selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate();
64
65 if (selfUnidentifiedAccessKey == null || selfUnidentifiedAccessCertificate == null) {
66 return Optional.absent();
67 }
68
69 try {
70 return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey,
71 selfUnidentifiedAccessCertificate),
72 new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)));
73 } catch (InvalidCertificateException e) {
74 return Optional.absent();
75 }
76 }
77
78 public List<Optional<UnidentifiedAccessPair>> getAccessFor(List<RecipientId> recipients) {
79 return recipients.stream().map(this::getAccessFor).collect(Collectors.toList());
80 }
81
82 public Optional<UnidentifiedAccessPair> getAccessFor(RecipientId recipient) {
83 var recipientUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
84 var selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
85 var selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate();
86
87 if (recipientUnidentifiedAccessKey == null
88 || selfUnidentifiedAccessKey == null
89 || selfUnidentifiedAccessCertificate == null) {
90 return Optional.absent();
91 }
92
93 try {
94 return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey,
95 selfUnidentifiedAccessCertificate),
96 new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)));
97 } catch (InvalidCertificateException e) {
98 return Optional.absent();
99 }
100 }
101
102 private static byte[] createUnrestrictedUnidentifiedAccess() {
103 return getSecretBytes(16);
104 }
105 }