1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.signal
.libsignal
.metadata
.certificate
.InvalidCertificateException
;
4 import org
.whispersystems
.libsignal
.util
.guava
.Optional
;
5 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccess
;
6 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccessPair
;
7 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
9 import java
.util
.Collection
;
10 import java
.util
.List
;
11 import java
.util
.stream
.Collectors
;
13 import static org
.whispersystems
.signalservice
.internal
.util
.Util
.getSecretBytes
;
15 public class UnidentifiedAccessHelper
{
17 private final SelfProfileKeyProvider selfProfileKeyProvider
;
19 private final ProfileKeyProvider profileKeyProvider
;
21 private final ProfileProvider profileProvider
;
23 private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
;
25 public UnidentifiedAccessHelper(
26 final SelfProfileKeyProvider selfProfileKeyProvider
,
27 final ProfileKeyProvider profileKeyProvider
,
28 final ProfileProvider profileProvider
,
29 final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
31 this.selfProfileKeyProvider
= selfProfileKeyProvider
;
32 this.profileKeyProvider
= profileKeyProvider
;
33 this.profileProvider
= profileProvider
;
34 this.senderCertificateProvider
= senderCertificateProvider
;
37 private byte[] getSelfUnidentifiedAccessKey() {
38 return UnidentifiedAccess
.deriveAccessKeyFrom(selfProfileKeyProvider
.getProfileKey());
41 public byte[] getTargetUnidentifiedAccessKey(SignalServiceAddress recipient
) {
42 var theirProfileKey
= profileKeyProvider
.getProfileKey(recipient
);
43 if (theirProfileKey
== null) {
47 var targetProfile
= profileProvider
.getProfile(recipient
);
48 if (targetProfile
== null || targetProfile
.getUnidentifiedAccess() == null) {
52 if (targetProfile
.isUnrestrictedUnidentifiedAccess()) {
53 return createUnrestrictedUnidentifiedAccess();
56 return UnidentifiedAccess
.deriveAccessKeyFrom(theirProfileKey
);
59 public Optional
<UnidentifiedAccessPair
> getAccessForSync() {
60 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
61 var selfUnidentifiedAccessCertificate
= senderCertificateProvider
.getSenderCertificate();
63 if (selfUnidentifiedAccessKey
== null || selfUnidentifiedAccessCertificate
== null) {
64 return Optional
.absent();
68 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey
,
69 selfUnidentifiedAccessCertificate
),
70 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
71 } catch (InvalidCertificateException e
) {
72 return Optional
.absent();
76 public List
<Optional
<UnidentifiedAccessPair
>> getAccessFor(Collection
<SignalServiceAddress
> recipients
) {
77 return recipients
.stream().map(this::getAccessFor
).collect(Collectors
.toList());
80 public Optional
<UnidentifiedAccessPair
> getAccessFor(SignalServiceAddress recipient
) {
81 var recipientUnidentifiedAccessKey
= getTargetUnidentifiedAccessKey(recipient
);
82 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
83 var selfUnidentifiedAccessCertificate
= senderCertificateProvider
.getSenderCertificate();
85 if (recipientUnidentifiedAccessKey
== null
86 || selfUnidentifiedAccessKey
== null
87 || selfUnidentifiedAccessCertificate
== null) {
88 return Optional
.absent();
92 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey
,
93 selfUnidentifiedAccessCertificate
),
94 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
95 } catch (InvalidCertificateException e
) {
96 return Optional
.absent();
100 private static byte[] createUnrestrictedUnidentifiedAccess() {
101 return getSecretBytes(16);