1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.asamk
.signal
.manager
.SignalDependencies
;
4 import org
.asamk
.signal
.manager
.storage
.SignalAccount
;
5 import org
.asamk
.signal
.manager
.storage
.recipients
.RecipientId
;
6 import org
.signal
.libsignal
.metadata
.certificate
.InvalidCertificateException
;
7 import org
.slf4j
.Logger
;
8 import org
.slf4j
.LoggerFactory
;
9 import org
.whispersystems
.libsignal
.util
.guava
.Optional
;
10 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccess
;
11 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccessPair
;
13 import java
.io
.IOException
;
14 import java
.util
.List
;
15 import java
.util
.stream
.Collectors
;
17 import static org
.whispersystems
.signalservice
.internal
.util
.Util
.getSecretBytes
;
19 public class UnidentifiedAccessHelper
{
21 private final static Logger logger
= LoggerFactory
.getLogger(UnidentifiedAccessHelper
.class);
23 private final SignalAccount account
;
24 private final SignalDependencies dependencies
;
25 private final SelfProfileKeyProvider selfProfileKeyProvider
;
26 private final ProfileProvider profileProvider
;
28 public UnidentifiedAccessHelper(
29 final SignalAccount account
,
30 final SignalDependencies dependencies
,
31 final SelfProfileKeyProvider selfProfileKeyProvider
,
32 final ProfileProvider profileProvider
34 this.account
= account
;
35 this.dependencies
= dependencies
;
36 this.selfProfileKeyProvider
= selfProfileKeyProvider
;
37 this.profileProvider
= profileProvider
;
40 private byte[] getSenderCertificate() {
43 if (account
.isPhoneNumberShared()) {
44 certificate
= dependencies
.getAccountManager().getSenderCertificate();
46 certificate
= dependencies
.getAccountManager().getSenderCertificateForPhoneNumberPrivacy();
48 } catch (IOException e
) {
49 logger
.warn("Failed to get sender certificate, ignoring: {}", e
.getMessage());
52 // TODO cache for a day
56 private byte[] getSelfUnidentifiedAccessKey() {
57 return UnidentifiedAccess
.deriveAccessKeyFrom(selfProfileKeyProvider
.getProfileKey());
60 public byte[] getTargetUnidentifiedAccessKey(RecipientId recipient
) {
61 var targetProfile
= profileProvider
.getProfile(recipient
);
62 if (targetProfile
== null) {
66 switch (targetProfile
.getUnidentifiedAccessMode()) {
68 var theirProfileKey
= account
.getProfileStore().getProfileKey(recipient
);
69 if (theirProfileKey
== null) {
73 return UnidentifiedAccess
.deriveAccessKeyFrom(theirProfileKey
);
75 return createUnrestrictedUnidentifiedAccess();
81 public Optional
<UnidentifiedAccessPair
> getAccessForSync() {
82 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
83 var selfUnidentifiedAccessCertificate
= getSenderCertificate();
85 if (selfUnidentifiedAccessKey
== null || selfUnidentifiedAccessCertificate
== null) {
86 return Optional
.absent();
90 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey
,
91 selfUnidentifiedAccessCertificate
),
92 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
93 } catch (InvalidCertificateException e
) {
94 return Optional
.absent();
98 public List
<Optional
<UnidentifiedAccessPair
>> getAccessFor(List
<RecipientId
> recipients
) {
99 return recipients
.stream().map(this::getAccessFor
).collect(Collectors
.toList());
102 public Optional
<UnidentifiedAccessPair
> getAccessFor(RecipientId recipient
) {
103 var recipientUnidentifiedAccessKey
= getTargetUnidentifiedAccessKey(recipient
);
104 var selfUnidentifiedAccessKey
= getSelfUnidentifiedAccessKey();
105 var selfUnidentifiedAccessCertificate
= getSenderCertificate();
107 if (recipientUnidentifiedAccessKey
== null
108 || selfUnidentifiedAccessKey
== null
109 || selfUnidentifiedAccessCertificate
== null) {
110 return Optional
.absent();
114 return Optional
.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey
,
115 selfUnidentifiedAccessCertificate
),
116 new UnidentifiedAccess(selfUnidentifiedAccessKey
, selfUnidentifiedAccessCertificate
)));
117 } catch (InvalidCertificateException e
) {
118 return Optional
.absent();
122 private static byte[] createUnrestrictedUnidentifiedAccess() {
123 return getSecretBytes(16);