1 package org
.asamk
.signal
.manager
.helper
;
3 import org
.asamk
.signal
.manager
.storage
.recipients
.RecipientId
;
4 import org
.signal
.zkgroup
.profiles
.ProfileKey
;
5 import org
.whispersystems
.libsignal
.util
.guava
.Optional
;
6 import org
.whispersystems
.signalservice
.api
.crypto
.UnidentifiedAccess
;
7 import org
.whispersystems
.signalservice
.api
.profiles
.ProfileAndCredential
;
8 import org
.whispersystems
.signalservice
.api
.profiles
.SignalServiceProfile
;
9 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
10 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.NotFoundException
;
11 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.PushNetworkException
;
12 import org
.whispersystems
.signalservice
.api
.services
.ProfileService
;
13 import org
.whispersystems
.signalservice
.internal
.ServiceResponse
;
15 import java
.io
.IOException
;
17 import io
.reactivex
.rxjava3
.core
.Single
;
19 public final class ProfileHelper
{
21 private final ProfileKeyProvider profileKeyProvider
;
23 private final UnidentifiedAccessProvider unidentifiedAccessProvider
;
25 private final ProfileServiceProvider profileServiceProvider
;
27 private final MessageReceiverProvider messageReceiverProvider
;
29 private final SignalServiceAddressResolver addressResolver
;
32 final ProfileKeyProvider profileKeyProvider
,
33 final UnidentifiedAccessProvider unidentifiedAccessProvider
,
34 final ProfileServiceProvider profileServiceProvider
,
35 final MessageReceiverProvider messageReceiverProvider
,
36 final SignalServiceAddressResolver addressResolver
38 this.profileKeyProvider
= profileKeyProvider
;
39 this.unidentifiedAccessProvider
= unidentifiedAccessProvider
;
40 this.profileServiceProvider
= profileServiceProvider
;
41 this.messageReceiverProvider
= messageReceiverProvider
;
42 this.addressResolver
= addressResolver
;
45 public ProfileAndCredential
retrieveProfileSync(
46 RecipientId recipientId
, SignalServiceProfile
.RequestType requestType
47 ) throws IOException
{
49 return retrieveProfile(recipientId
, requestType
).blockingGet();
50 } catch (RuntimeException 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
);
61 public SignalServiceProfile
retrieveProfileSync(String username
) throws IOException
{
62 return messageReceiverProvider
.getMessageReceiver().retrieveProfileByUsername(username
, Optional
.absent());
65 public Single
<ProfileAndCredential
> retrieveProfile(
66 RecipientId recipientId
, SignalServiceProfile
.RequestType requestType
67 ) throws IOException
{
68 var unidentifiedAccess
= getUnidentifiedAccess(recipientId
);
69 var profileKey
= Optional
.fromNullable(profileKeyProvider
.getProfileKey(recipientId
));
71 final var address
= addressResolver
.resolveSignalServiceAddress(recipientId
);
72 return retrieveProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
75 private Single
<ProfileAndCredential
> retrieveProfile(
76 SignalServiceAddress address
,
77 Optional
<ProfileKey
> profileKey
,
78 Optional
<UnidentifiedAccess
> unidentifiedAccess
,
79 SignalServiceProfile
.RequestType requestType
80 ) throws IOException
{
81 var profileService
= profileServiceProvider
.getProfileService();
83 Single
<ServiceResponse
<ProfileAndCredential
>> responseSingle
;
85 responseSingle
= profileService
.getProfile(address
, profileKey
, unidentifiedAccess
, requestType
);
86 } catch (NoClassDefFoundError e
) {
87 // Native zkgroup lib not available for ProfileKey
88 if (!address
.getNumber().isPresent()) {
89 throw new NotFoundException("Can't request profile without number");
91 var addressWithoutUuid
= new SignalServiceAddress(Optional
.absent(), address
.getNumber());
92 responseSingle
= profileService
.getProfile(addressWithoutUuid
, profileKey
, unidentifiedAccess
, requestType
);
95 return responseSingle
.map(pair
-> {
96 var processor
= new ProfileService
.ProfileResponseProcessor(pair
);
97 if (processor
.hasResult()) {
98 return processor
.getResult();
99 } else if (processor
.notFound()) {
100 throw new NotFoundException("Profile not found");
102 throw pair
.getExecutionError()
103 .or(pair
.getApplicationError())
104 .or(new IOException("Unknown error while retrieving profile"));
109 private Optional
<UnidentifiedAccess
> getUnidentifiedAccess(RecipientId recipientId
) {
110 var unidentifiedAccess
= unidentifiedAccessProvider
.getAccessFor(recipientId
);
112 if (unidentifiedAccess
.isPresent()) {
113 return unidentifiedAccess
.get().getTargetUnidentifiedAccess();
116 return Optional
.absent();