]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java
Update libsignal-service-java
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / ProfileHelper.java
1 package org.asamk.signal.manager.helper;
2
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;
14
15 import java.io.IOException;
16
17 import io.reactivex.rxjava3.core.Single;
18
19 public final class ProfileHelper {
20
21 private final ProfileKeyProvider profileKeyProvider;
22
23 private final UnidentifiedAccessProvider unidentifiedAccessProvider;
24
25 private final ProfileServiceProvider profileServiceProvider;
26
27 private final MessageReceiverProvider messageReceiverProvider;
28
29 private final SignalServiceAddressResolver addressResolver;
30
31 public ProfileHelper(
32 final ProfileKeyProvider profileKeyProvider,
33 final UnidentifiedAccessProvider unidentifiedAccessProvider,
34 final ProfileServiceProvider profileServiceProvider,
35 final MessageReceiverProvider messageReceiverProvider,
36 final SignalServiceAddressResolver addressResolver
37 ) {
38 this.profileKeyProvider = profileKeyProvider;
39 this.unidentifiedAccessProvider = unidentifiedAccessProvider;
40 this.profileServiceProvider = profileServiceProvider;
41 this.messageReceiverProvider = messageReceiverProvider;
42 this.addressResolver = addressResolver;
43 }
44
45 public ProfileAndCredential retrieveProfileSync(
46 RecipientId recipientId, SignalServiceProfile.RequestType requestType
47 ) throws IOException {
48 try {
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();
55 } else {
56 throw new IOException(e);
57 }
58 }
59 }
60
61 public SignalServiceProfile retrieveProfileSync(String username) throws IOException {
62 return messageReceiverProvider.getMessageReceiver().retrieveProfileByUsername(username, Optional.absent());
63 }
64
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));
70
71 final var address = addressResolver.resolveSignalServiceAddress(recipientId);
72 return retrieveProfile(address, profileKey, unidentifiedAccess, requestType);
73 }
74
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();
82
83 Single<ServiceResponse<ProfileAndCredential>> responseSingle;
84 try {
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");
90 }
91 var addressWithoutUuid = new SignalServiceAddress(Optional.absent(), address.getNumber());
92 responseSingle = profileService.getProfile(addressWithoutUuid, profileKey, unidentifiedAccess, requestType);
93 }
94
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");
101 } else {
102 throw pair.getExecutionError()
103 .or(pair.getApplicationError())
104 .or(new IOException("Unknown error while retrieving profile"));
105 }
106 });
107 }
108
109 private Optional<UnidentifiedAccess> getUnidentifiedAccess(RecipientId recipientId) {
110 var unidentifiedAccess = unidentifiedAccessProvider.getAccessFor(recipientId);
111
112 if (unidentifiedAccess.isPresent()) {
113 return unidentifiedAccess.get().getTargetUnidentifiedAccess();
114 }
115
116 return Optional.absent();
117 }
118 }