]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java
Use var instead of explicit types
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / ProfileHelper.java
1 package org.asamk.signal.manager.helper;
2
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;
13
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;
19
20 public final class ProfileHelper {
21
22 private final ProfileKeyProvider profileKeyProvider;
23
24 private final UnidentifiedAccessProvider unidentifiedAccessProvider;
25
26 private final MessagePipeProvider messagePipeProvider;
27
28 private final MessageReceiverProvider messageReceiverProvider;
29
30 public ProfileHelper(
31 final ProfileKeyProvider profileKeyProvider,
32 final UnidentifiedAccessProvider unidentifiedAccessProvider,
33 final MessagePipeProvider messagePipeProvider,
34 final MessageReceiverProvider messageReceiverProvider
35 ) {
36 this.profileKeyProvider = profileKeyProvider;
37 this.unidentifiedAccessProvider = unidentifiedAccessProvider;
38 this.messagePipeProvider = messagePipeProvider;
39 this.messageReceiverProvider = messageReceiverProvider;
40 }
41
42 public ProfileAndCredential retrieveProfileSync(
43 SignalServiceAddress recipient, SignalServiceProfile.RequestType requestType
44 ) throws IOException {
45 try {
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();
52 } else {
53 throw new IOException(e);
54 }
55 } catch (InterruptedException | TimeoutException e) {
56 throw new PushNetworkException(e);
57 }
58 }
59
60 public ListenableFuture<ProfileAndCredential> retrieveProfile(
61 SignalServiceAddress address, SignalServiceProfile.RequestType requestType
62 ) {
63 var unidentifiedAccess = getUnidentifiedAccess(address);
64 var profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(address));
65
66 if (unidentifiedAccess.isPresent()) {
67 return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address,
68 profileKey,
69 unidentifiedAccess,
70 requestType),
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));
75 } else {
76 return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address,
77 profileKey,
78 Optional.absent(),
79 requestType), () -> getSocketRetrievalFuture(address, profileKey, Optional.absent(), requestType)),
80 e -> !(e instanceof NotFoundException));
81 }
82 }
83
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()
92 ? unidentifiedPipe
93 : messagePipeProvider.getMessagePipe(false);
94 if (pipe != null) {
95 try {
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");
101 }
102 var addressWithoutUuid = new SignalServiceAddress(Optional.absent(), address.getNumber());
103 return pipe.getProfile(addressWithoutUuid, profileKey, unidentifiedAccess, requestType);
104 }
105 }
106
107 throw new IOException("No pipe available!");
108 }
109
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();
117 try {
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");
123 }
124 var addressWithoutUuid = new SignalServiceAddress(Optional.absent(), address.getNumber());
125 return receiver.retrieveProfile(addressWithoutUuid, profileKey, unidentifiedAccess, requestType);
126 }
127 }
128
129 private Optional<UnidentifiedAccess> getUnidentifiedAccess(SignalServiceAddress recipient) {
130 var unidentifiedAccess = unidentifiedAccessProvider.getAccessFor(recipient);
131
132 if (unidentifiedAccess.isPresent()) {
133 return unidentifiedAccess.get().getTargetUnidentifiedAccess();
134 }
135
136 return Optional.absent();
137 }
138 }