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