1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.signal
.zkgroup
.profiles
.ProfileKey
;
4 import org
.whispersystems
.libsignal
.util
.guava
.Optional
;
5 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccess
;
6 import org
.whispersystems
.signalservice
.api
.profiles
.ProfileAndCredential
;
7 import org
.whispersystems
.signalservice
.api
.profiles
.SignalServiceProfile
;
8 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
9 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.NotFoundException
;
10 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.PushNetworkException
;
11 import org
.whispersystems
.signalservice
.internal
.util
.concurrent
.CascadingFuture
;
12 import org
.whispersystems
.signalservice
.internal
.util
.concurrent
.ListenableFuture
;
14 import java
.io
.IOException
;
15 import java
.util
.Arrays
;
16 import java
.util
.concurrent
.ExecutionException
;
17 import java
.util
.concurrent
.TimeUnit
;
18 import java
.util
.concurrent
.TimeoutException
;
20 public final class ProfileHelper
{
22 private final ProfileKeyProvider profileKeyProvider
;
24 private final UnidentifiedAccessProvider unidentifiedAccessProvider
;
26 private final MessagePipeProvider messagePipeProvider
;
28 private final MessageReceiverProvider messageReceiverProvider
;
31 final ProfileKeyProvider profileKeyProvider
,
32 final UnidentifiedAccessProvider unidentifiedAccessProvider
,
33 final MessagePipeProvider messagePipeProvider
,
34 final MessageReceiverProvider messageReceiverProvider
36 this.profileKeyProvider
= profileKeyProvider
;
37 this.unidentifiedAccessProvider
= unidentifiedAccessProvider
;
38 this.messagePipeProvider
= messagePipeProvider
;
39 this.messageReceiverProvider
= messageReceiverProvider
;
42 public ProfileAndCredential
retrieveProfileSync(
43 SignalServiceAddress recipient
, SignalServiceProfile
.RequestType requestType
44 ) throws IOException
{
46 return retrieveProfile(recipient
, requestType
).get(10, TimeUnit
.SECONDS
);
47 } catch (ExecutionException e
) {
48 if (e
.getCause() instanceof PushNetworkException
) {
49 throw (PushNetworkException
) e
.getCause();
50 } else if (e
.getCause() instanceof NotFoundException
) {
51 throw (NotFoundException
) e
.getCause();
53 throw new IOException(e
);
55 } catch (InterruptedException
| TimeoutException e
) {
56 throw new PushNetworkException(e
);
60 public ListenableFuture
<ProfileAndCredential
> retrieveProfile(
61 SignalServiceAddress address
, SignalServiceProfile
.RequestType requestType
63 var unidentifiedAccess
= getUnidentifiedAccess(address
);
64 var profileKey
= Optional
.fromNullable(profileKeyProvider
.getProfileKey(address
));
66 if (unidentifiedAccess
.isPresent()) {
67 return new CascadingFuture
<>(Arrays
.asList(() -> getPipeRetrievalFuture(address
,
71 () -> getSocketRetrievalFuture(address
, profileKey
, unidentifiedAccess
, requestType
),
72 () -> getPipeRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
),
73 () -> getSocketRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
)),
74 e
-> !(e
instanceof NotFoundException
));
76 return new CascadingFuture
<>(Arrays
.asList(() -> getPipeRetrievalFuture(address
,
79 requestType
), () -> getSocketRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
)),
80 e
-> !(e
instanceof NotFoundException
));
84 private ListenableFuture
<ProfileAndCredential
> getPipeRetrievalFuture(
85 SignalServiceAddress address
,
86 Optional
<ProfileKey
> profileKey
,
87 Optional
<UnidentifiedAccess
> unidentifiedAccess
,
88 SignalServiceProfile
.RequestType requestType
89 ) throws IOException
{
90 var unidentifiedPipe
= messagePipeProvider
.getMessagePipe(true);
91 var pipe
= unidentifiedPipe
!= null && unidentifiedAccess
.isPresent()
93 : messagePipeProvider
.getMessagePipe(false);
96 return pipe
.getProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
97 } catch (NoClassDefFoundError e
) {
98 // Native zkgroup lib not available for ProfileKey
99 if (!address
.getNumber().isPresent()) {
100 throw new NotFoundException("Can't request profile without number");
102 var addressWithoutUuid
= new SignalServiceAddress(Optional
.absent(), address
.getNumber());
103 return pipe
.getProfile(addressWithoutUuid
, profileKey
, unidentifiedAccess
, requestType
);
107 throw new IOException("No pipe available!");
110 private ListenableFuture
<ProfileAndCredential
> getSocketRetrievalFuture(
111 SignalServiceAddress address
,
112 Optional
<ProfileKey
> profileKey
,
113 Optional
<UnidentifiedAccess
> unidentifiedAccess
,
114 SignalServiceProfile
.RequestType requestType
115 ) throws NotFoundException
{
116 var receiver
= messageReceiverProvider
.getMessageReceiver();
118 return receiver
.retrieveProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
119 } catch (NoClassDefFoundError e
) {
120 // Native zkgroup lib not available for ProfileKey
121 if (!address
.getNumber().isPresent()) {
122 throw new NotFoundException("Can't request profile without number");
124 var addressWithoutUuid
= new SignalServiceAddress(Optional
.absent(), address
.getNumber());
125 return receiver
.retrieveProfile(addressWithoutUuid
, profileKey
, unidentifiedAccess
, requestType
);
129 private Optional
<UnidentifiedAccess
> getUnidentifiedAccess(SignalServiceAddress recipient
) {
130 var unidentifiedAccess
= unidentifiedAccessProvider
.getAccessFor(recipient
);
132 if (unidentifiedAccess
.isPresent()) {
133 return unidentifiedAccess
.get().getTargetUnidentifiedAccess();
136 return Optional
.absent();