1 package org
.asamk
.signal
.manager
.helper
;
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
;
10 import java
.util
.stream
.Collectors
;
12 import static org
.whispersystems
.signalservice
.internal
.util
.Util
.getSecretBytes
;
14 public class UnidentifiedAccessHelper
{
16 private final SelfProfileKeyProvider selfProfileKeyProvider
;
18 private final ProfileKeyProvider profileKeyProvider
;
20 private final ProfileProvider profileProvider
;
22 private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
;
24 public UnidentifiedAccessHelper(
25 final SelfProfileKeyProvider selfProfileKeyProvider
,
26 final ProfileKeyProvider profileKeyProvider
,
27 final ProfileProvider profileProvider
,
28 final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
30 this.selfProfileKeyProvider
= selfProfileKeyProvider
;
31 this.profileKeyProvider
= profileKeyProvider
;
32 this.profileProvider
= profileProvider
;
33 this.senderCertificateProvider
= senderCertificateProvider
;
36 private byte[] getSelfUnidentifiedAccessKey() {
37 return UnidentifiedAccess
.deriveAccessKeyFrom(selfProfileKeyProvider
.getProfileKey());
40 public byte[] getTargetUnidentifiedAccessKey(RecipientId recipient
) {
41 var targetProfile
= profileProvider
.getProfile(recipient
);
42 if (targetProfile
== null) {
46 switch (targetProfile
.getUnidentifiedAccessMode()) {
48 var theirProfileKey
= profileKeyProvider
.getProfileKey(recipient
);
49 if (theirProfileKey
== null) {
53 return UnidentifiedAccess
.deriveAccessKeyFrom(theirProfileKey
);
55 return createUnrestrictedUnidentifiedAccess();
61 public Optional
<UnidentifiedAccessPair
> getAccessForSync() {
62 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
63 var selfUnidentifiedAccessCertificate
= senderCertificateProvider
.getSenderCertificate();
65 if (selfUnidentifiedAccessKey
== null || selfUnidentifiedAccessCertificate
== null) {
66 return Optional
.absent();
70 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey
,
71 selfUnidentifiedAccessCertificate
),
72 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
73 } catch (InvalidCertificateException e
) {
74 return Optional
.absent();
78 public List
<Optional
<UnidentifiedAccessPair
>> getAccessFor(List
<RecipientId
> recipients
) {
79 return recipients
.stream().map(this::getAccessFor
).collect(Collectors
.toList());
82 public Optional
<UnidentifiedAccessPair
> getAccessFor(RecipientId recipient
) {
83 var recipientUnidentifiedAccessKey
= getTargetUnidentifiedAccessKey(recipient
);
84 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
85 var selfUnidentifiedAccessCertificate
= senderCertificateProvider
.getSenderCertificate();
87 if (recipientUnidentifiedAccessKey
== null
88 || selfUnidentifiedAccessKey
== null
89 || selfUnidentifiedAccessCertificate
== null) {
90 return Optional
.absent();
94 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey
,
95 selfUnidentifiedAccessCertificate
),
96 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
97 } catch (InvalidCertificateException e
) {
98 return Optional
.absent();
102 private static byte[] createUnrestrictedUnidentifiedAccess() {
103 return getSecretBytes(16);