]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/UnidentifiedAccessHelper.java
3930154cf0ba4c43d8527f6996c8448a09e89b21
[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.profiles.SignalProfile;
4 import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
5 import org.signal.zkgroup.profiles.ProfileKey;
6 import org.whispersystems.libsignal.util.guava.Optional;
7 import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
8 import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
9 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
10
11 import java.util.Collection;
12 import java.util.List;
13 import java.util.stream.Collectors;
14
15 import static org.whispersystems.signalservice.internal.util.Util.getSecretBytes;
16
17 public class UnidentifiedAccessHelper {
18
19 private final SelfProfileKeyProvider selfProfileKeyProvider;
20
21 private final ProfileKeyProvider profileKeyProvider;
22
23 private final ProfileProvider profileProvider;
24
25 private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider;
26
27 public UnidentifiedAccessHelper(
28 final SelfProfileKeyProvider selfProfileKeyProvider,
29 final ProfileKeyProvider profileKeyProvider,
30 final ProfileProvider profileProvider,
31 final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
32 ) {
33 this.selfProfileKeyProvider = selfProfileKeyProvider;
34 this.profileKeyProvider = profileKeyProvider;
35 this.profileProvider = profileProvider;
36 this.senderCertificateProvider = senderCertificateProvider;
37 }
38
39 private byte[] getSelfUnidentifiedAccessKey() {
40 return UnidentifiedAccess.deriveAccessKeyFrom(selfProfileKeyProvider.getProfileKey());
41 }
42
43 public byte[] getTargetUnidentifiedAccessKey(SignalServiceAddress recipient) {
44 ProfileKey theirProfileKey = profileKeyProvider.getProfileKey(recipient);
45 if (theirProfileKey == null) {
46 return null;
47 }
48
49 SignalProfile targetProfile = profileProvider.getProfile(recipient);
50 if (targetProfile == null || targetProfile.getUnidentifiedAccess() == null) {
51 return null;
52 }
53
54 if (targetProfile.isUnrestrictedUnidentifiedAccess()) {
55 return createUnrestrictedUnidentifiedAccess();
56 }
57
58 return UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
59 }
60
61 public Optional<UnidentifiedAccessPair> getAccessForSync() {
62 byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
63 byte[] 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(Collection<SignalServiceAddress> recipients) {
79 return recipients.stream().map(this::getAccessFor).collect(Collectors.toList());
80 }
81
82 public Optional<UnidentifiedAccessPair> getAccessFor(SignalServiceAddress recipient) {
83 byte[] recipientUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
84 byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
85 byte[] 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 }