]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/manager/helper/UnidentifiedAccessHelper.java
Implement creating V2 Groups
[signal-cli] / src / main / java / org / asamk / signal / manager / helper / UnidentifiedAccessHelper.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.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(final SelfProfileKeyProvider selfProfileKeyProvider, final ProfileKeyProvider profileKeyProvider, final ProfileProvider profileProvider, final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider) {
28 this.selfProfileKeyProvider = selfProfileKeyProvider;
29 this.profileKeyProvider = profileKeyProvider;
30 this.profileProvider = profileProvider;
31 this.senderCertificateProvider = senderCertificateProvider;
32 }
33
34 public byte[] getSelfUnidentifiedAccessKey() {
35 return UnidentifiedAccess.deriveAccessKeyFrom(selfProfileKeyProvider.getProfileKey());
36 }
37
38 public byte[] getTargetUnidentifiedAccessKey(SignalServiceAddress recipient) {
39 ProfileKey theirProfileKey = profileKeyProvider.getProfileKey(recipient);
40 if (theirProfileKey == null) {
41 return null;
42 }
43
44 SignalProfile targetProfile = profileProvider.getProfile(recipient);
45 if (targetProfile == null || targetProfile.getUnidentifiedAccess() == null) {
46 return null;
47 }
48
49 if (targetProfile.isUnrestrictedUnidentifiedAccess()) {
50 return createUnrestrictedUnidentifiedAccess();
51 }
52
53 return UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
54 }
55
56 public Optional<UnidentifiedAccessPair> getAccessForSync() {
57 byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
58 byte[] selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate();
59
60 if (selfUnidentifiedAccessKey == null || selfUnidentifiedAccessCertificate == null) {
61 return Optional.absent();
62 }
63
64 try {
65 return Optional.of(new UnidentifiedAccessPair(
66 new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate),
67 new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)
68 ));
69 } catch (InvalidCertificateException e) {
70 return Optional.absent();
71 }
72 }
73
74 public List<Optional<UnidentifiedAccessPair>> getAccessFor(Collection<SignalServiceAddress> recipients) {
75 return recipients.stream()
76 .map(this::getAccessFor)
77 .collect(Collectors.toList());
78 }
79
80 public Optional<UnidentifiedAccessPair> getAccessFor(SignalServiceAddress recipient) {
81 byte[] recipientUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
82 byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
83 byte[] selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate();
84
85 if (recipientUnidentifiedAccessKey == null || selfUnidentifiedAccessKey == null || selfUnidentifiedAccessCertificate == null) {
86 return Optional.absent();
87 }
88
89 try {
90 return Optional.of(new UnidentifiedAccessPair(
91 new UnidentifiedAccess(recipientUnidentifiedAccessKey, selfUnidentifiedAccessCertificate),
92 new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)
93 ));
94 } catch (InvalidCertificateException e) {
95 return Optional.absent();
96 }
97 }
98
99 private static byte[] createUnrestrictedUnidentifiedAccess() {
100 return getSecretBytes(16);
101 }
102 }