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
.SignalServiceMessagePipe
;
6 import org
.whispersystems
.signalservice
.api
.SignalServiceMessageReceiver
;
7 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccess
;
8 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccessPair
;
9 import org
.whispersystems
.signalservice
.api
.profiles
.ProfileAndCredential
;
10 import org
.whispersystems
.signalservice
.api
.profiles
.SignalServiceProfile
;
11 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
12 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.NotFoundException
;
13 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.PushNetworkException
;
14 import org
.whispersystems
.signalservice
.internal
.util
.concurrent
.CascadingFuture
;
15 import org
.whispersystems
.signalservice
.internal
.util
.concurrent
.ListenableFuture
;
17 import java
.io
.IOException
;
18 import java
.util
.Arrays
;
19 import java
.util
.concurrent
.ExecutionException
;
20 import java
.util
.concurrent
.TimeUnit
;
21 import java
.util
.concurrent
.TimeoutException
;
23 public final class ProfileHelper
{
25 private final ProfileKeyProvider profileKeyProvider
;
27 private final UnidentifiedAccessProvider unidentifiedAccessProvider
;
29 private final MessagePipeProvider messagePipeProvider
;
31 private final MessageReceiverProvider messageReceiverProvider
;
34 final ProfileKeyProvider profileKeyProvider
,
35 final UnidentifiedAccessProvider unidentifiedAccessProvider
,
36 final MessagePipeProvider messagePipeProvider
,
37 final MessageReceiverProvider messageReceiverProvider
39 this.profileKeyProvider
= profileKeyProvider
;
40 this.unidentifiedAccessProvider
= unidentifiedAccessProvider
;
41 this.messagePipeProvider
= messagePipeProvider
;
42 this.messageReceiverProvider
= messageReceiverProvider
;
45 public ProfileAndCredential
retrieveProfileSync(
46 SignalServiceAddress recipient
, SignalServiceProfile
.RequestType requestType
47 ) throws IOException
{
49 return retrieveProfile(recipient
, requestType
).get(10, TimeUnit
.SECONDS
);
50 } catch (ExecutionException e
) {
51 if (e
.getCause() instanceof PushNetworkException
) {
52 throw (PushNetworkException
) e
.getCause();
53 } else if (e
.getCause() instanceof NotFoundException
) {
54 throw (NotFoundException
) e
.getCause();
56 throw new IOException(e
);
58 } catch (InterruptedException
| TimeoutException e
) {
59 throw new PushNetworkException(e
);
63 public ListenableFuture
<ProfileAndCredential
> retrieveProfile(
64 SignalServiceAddress address
, SignalServiceProfile
.RequestType requestType
66 Optional
<UnidentifiedAccess
> unidentifiedAccess
= getUnidentifiedAccess(address
);
67 Optional
<ProfileKey
> profileKey
= Optional
.fromNullable(profileKeyProvider
.getProfileKey(address
));
69 if (unidentifiedAccess
.isPresent()) {
70 return new CascadingFuture
<>(Arrays
.asList(() -> getPipeRetrievalFuture(address
,
74 () -> getSocketRetrievalFuture(address
, profileKey
, unidentifiedAccess
, requestType
),
75 () -> getPipeRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
),
76 () -> getSocketRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
)),
77 e
-> !(e
instanceof NotFoundException
));
79 return new CascadingFuture
<>(Arrays
.asList(() -> getPipeRetrievalFuture(address
,
82 requestType
), () -> getSocketRetrievalFuture(address
, profileKey
, Optional
.absent(), requestType
)),
83 e
-> !(e
instanceof NotFoundException
));
87 private ListenableFuture
<ProfileAndCredential
> getPipeRetrievalFuture(
88 SignalServiceAddress address
,
89 Optional
<ProfileKey
> profileKey
,
90 Optional
<UnidentifiedAccess
> unidentifiedAccess
,
91 SignalServiceProfile
.RequestType requestType
92 ) throws IOException
{
93 SignalServiceMessagePipe unidentifiedPipe
= messagePipeProvider
.getMessagePipe(true);
94 SignalServiceMessagePipe pipe
= unidentifiedPipe
!= null && unidentifiedAccess
.isPresent()
96 : messagePipeProvider
.getMessagePipe(false);
99 return pipe
.getProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
100 } catch (NoClassDefFoundError e
) {
101 // Native zkgroup lib not available for ProfileKey
102 if (!address
.getNumber().isPresent()) {
103 throw new NotFoundException("Can't request profile without number");
105 SignalServiceAddress addressWithoutUuid
= new SignalServiceAddress(Optional
.absent(),
106 address
.getNumber());
107 return pipe
.getProfile(addressWithoutUuid
, profileKey
, unidentifiedAccess
, requestType
);
111 throw new IOException("No pipe available!");
114 private ListenableFuture
<ProfileAndCredential
> getSocketRetrievalFuture(
115 SignalServiceAddress address
,
116 Optional
<ProfileKey
> profileKey
,
117 Optional
<UnidentifiedAccess
> unidentifiedAccess
,
118 SignalServiceProfile
.RequestType requestType
119 ) throws NotFoundException
{
120 SignalServiceMessageReceiver receiver
= messageReceiverProvider
.getMessageReceiver();
122 return receiver
.retrieveProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
123 } catch (NoClassDefFoundError e
) {
124 // Native zkgroup lib not available for ProfileKey
125 if (!address
.getNumber().isPresent()) {
126 throw new NotFoundException("Can't request profile without number");
128 SignalServiceAddress addressWithoutUuid
= new SignalServiceAddress(Optional
.absent(), address
.getNumber());
129 return receiver
.retrieveProfile(addressWithoutUuid
, profileKey
, unidentifiedAccess
, requestType
);
133 private Optional
<UnidentifiedAccess
> getUnidentifiedAccess(SignalServiceAddress recipient
) {
134 Optional
<UnidentifiedAccessPair
> unidentifiedAccess
= unidentifiedAccessProvider
.getAccessFor(recipient
);
136 if (unidentifiedAccess
.isPresent()) {
137 return unidentifiedAccess
.get().getTargetUnidentifiedAccess();
140 return Optional
.absent();