]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java
Set libsignal network proxy to match java proxy
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / internal / SignalDependencies.java
1 package org.asamk.signal.manager.internal;
2
3 import org.asamk.signal.manager.config.ServiceConfig;
4 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
5 import org.asamk.signal.manager.util.Utils;
6 import org.signal.libsignal.metadata.certificate.CertificateValidator;
7 import org.signal.libsignal.net.Network;
8 import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 import org.whispersystems.signalservice.api.SignalServiceAccountManager;
12 import org.whispersystems.signalservice.api.SignalServiceDataStore;
13 import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
14 import org.whispersystems.signalservice.api.SignalServiceMessageSender;
15 import org.whispersystems.signalservice.api.SignalSessionLock;
16 import org.whispersystems.signalservice.api.SignalWebSocket;
17 import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
18 import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
19 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
20 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
21 import org.whispersystems.signalservice.api.link.LinkDeviceApi;
22 import org.whispersystems.signalservice.api.push.ServiceIdType;
23 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
24 import org.whispersystems.signalservice.api.registration.RegistrationApi;
25 import org.whispersystems.signalservice.api.services.ProfileService;
26 import org.whispersystems.signalservice.api.storage.StorageServiceApi;
27 import org.whispersystems.signalservice.api.storage.StorageServiceRepository;
28 import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
29 import org.whispersystems.signalservice.api.util.CredentialsProvider;
30 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
31 import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
32 import org.whispersystems.signalservice.internal.push.ProvisioningSocket;
33 import org.whispersystems.signalservice.internal.push.PushServiceSocket;
34 import org.whispersystems.signalservice.internal.websocket.OkHttpWebSocketConnection;
35 import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
36
37 import java.io.IOException;
38 import java.net.InetSocketAddress;
39 import java.net.Proxy;
40 import java.util.List;
41 import java.util.Optional;
42 import java.util.concurrent.ExecutorService;
43 import java.util.function.Supplier;
44
45 public class SignalDependencies {
46
47 private static final Logger logger = LoggerFactory.getLogger(SignalDependencies.class);
48
49 private final Object LOCK = new Object();
50
51 private final ServiceEnvironmentConfig serviceEnvironmentConfig;
52 private final String userAgent;
53 private final CredentialsProvider credentialsProvider;
54 private final SignalServiceDataStore dataStore;
55 private final ExecutorService executor;
56 private final SignalSessionLock sessionLock;
57
58 private boolean allowStories = true;
59
60 private SignalServiceAccountManager accountManager;
61 private GroupsV2Api groupsV2Api;
62 private RegistrationApi registrationApi;
63 private LinkDeviceApi linkDeviceApi;
64 private StorageServiceApi storageServiceApi;
65 private GroupsV2Operations groupsV2Operations;
66 private ClientZkOperations clientZkOperations;
67
68 private PushServiceSocket pushServiceSocket;
69 private ProvisioningSocket provisioningSocket;
70 private Network libSignalNetwork;
71 private SignalWebSocket signalWebSocket;
72 private SignalServiceMessageReceiver messageReceiver;
73 private SignalServiceMessageSender messageSender;
74
75 private List<SecureValueRecovery> secureValueRecovery;
76 private ProfileService profileService;
77
78 SignalDependencies(
79 final ServiceEnvironmentConfig serviceEnvironmentConfig,
80 final String userAgent,
81 final CredentialsProvider credentialsProvider,
82 final SignalServiceDataStore dataStore,
83 final ExecutorService executor,
84 final SignalSessionLock sessionLock
85 ) {
86 this.serviceEnvironmentConfig = serviceEnvironmentConfig;
87 this.userAgent = userAgent;
88 this.credentialsProvider = credentialsProvider;
89 this.dataStore = dataStore;
90 this.executor = executor;
91 this.sessionLock = sessionLock;
92 }
93
94 public void resetAfterAddressChange() {
95 if (this.pushServiceSocket != null) {
96 this.pushServiceSocket.close();
97 this.pushServiceSocket = null;
98 this.accountManager = null;
99 this.messageReceiver = null;
100 this.messageSender = null;
101 this.profileService = null;
102 this.groupsV2Api = null;
103 this.registrationApi = null;
104 this.secureValueRecovery = null;
105 }
106 getSignalWebSocket().forceNewWebSockets();
107 }
108
109 /**
110 * This method needs to be called before the first websocket is created
111 */
112 public void setAllowStories(final boolean allowStories) {
113 this.allowStories = allowStories;
114 }
115
116 public ServiceEnvironmentConfig getServiceEnvironmentConfig() {
117 return serviceEnvironmentConfig;
118 }
119
120 public SignalSessionLock getSessionLock() {
121 return sessionLock;
122 }
123
124 public PushServiceSocket getPushServiceSocket() {
125 return getOrCreate(() -> pushServiceSocket,
126 () -> pushServiceSocket = new PushServiceSocket(serviceEnvironmentConfig.signalServiceConfiguration(),
127 credentialsProvider,
128 userAgent,
129 getClientZkProfileOperations(),
130 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
131 }
132
133 public ProvisioningSocket getProvisioningSocket() {
134 return getOrCreate(() -> provisioningSocket,
135 () -> provisioningSocket = new ProvisioningSocket(getServiceEnvironmentConfig().signalServiceConfiguration(),
136 userAgent));
137 }
138
139 public Network getLibSignalNetwork() {
140 return getOrCreate(() -> libSignalNetwork, () -> {
141 libSignalNetwork = new Network(serviceEnvironmentConfig.netEnvironment(), userAgent);
142 setSignalNetworkProxy(libSignalNetwork);
143 });
144 }
145
146 private void setSignalNetworkProxy(Network libSignalNetwork) {
147 final var proxy = Utils.getHttpsProxy();
148 if (proxy.address() instanceof InetSocketAddress addr) {
149 switch (proxy.type()) {
150 case Proxy.Type.DIRECT -> {
151 }
152 case Proxy.Type.HTTP -> {
153 try {
154 libSignalNetwork.setProxy("http", addr.getHostName(), addr.getPort(), null, null);
155 } catch (IOException e) {
156 logger.warn("Failed to set http proxy", e);
157 }
158 }
159 case Proxy.Type.SOCKS -> {
160 try {
161 libSignalNetwork.setProxy("socks", addr.getHostName(), addr.getPort(), null, null);
162 } catch (IOException e) {
163 logger.warn("Failed to set socks proxy", e);
164 }
165 }
166 }
167 }
168 }
169
170 public SignalServiceAccountManager getAccountManager() {
171 return getOrCreate(() -> accountManager,
172 () -> accountManager = new SignalServiceAccountManager(getPushServiceSocket(),
173 getProvisioningSocket(),
174 getGroupsV2Operations()));
175 }
176
177 public SignalServiceAccountManager createUnauthenticatedAccountManager(String number, String password) {
178 return SignalServiceAccountManager.createWithStaticCredentials(getServiceEnvironmentConfig().signalServiceConfiguration(),
179 null,
180 null,
181 number,
182 SignalServiceAddress.DEFAULT_DEVICE_ID,
183 password,
184 userAgent,
185 ServiceConfig.AUTOMATIC_NETWORK_RETRY,
186 ServiceConfig.GROUP_MAX_SIZE);
187 }
188
189 public GroupsV2Api getGroupsV2Api() {
190 return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
191 }
192
193 public RegistrationApi getRegistrationApi() {
194 return getOrCreate(() -> registrationApi, () -> registrationApi = getAccountManager().getRegistrationApi());
195 }
196
197 public LinkDeviceApi getLinkDeviceApi() {
198 return getOrCreate(() -> linkDeviceApi, () -> linkDeviceApi = new LinkDeviceApi(getPushServiceSocket()));
199 }
200
201 private StorageServiceApi getStorageServiceApi() {
202 return getOrCreate(() -> storageServiceApi,
203 () -> storageServiceApi = new StorageServiceApi(getPushServiceSocket()));
204 }
205
206 public StorageServiceRepository getStorageServiceRepository() {
207 return new StorageServiceRepository(getStorageServiceApi());
208 }
209
210 public GroupsV2Operations getGroupsV2Operations() {
211 return getOrCreate(() -> groupsV2Operations,
212 () -> groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()),
213 ServiceConfig.GROUP_MAX_SIZE));
214 }
215
216 private ClientZkOperations getClientZkOperations() {
217 return getOrCreate(() -> clientZkOperations,
218 () -> clientZkOperations = ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()));
219 }
220
221 private ClientZkProfileOperations getClientZkProfileOperations() {
222 final var clientZkOperations = getClientZkOperations();
223 return clientZkOperations.getProfileOperations();
224 }
225
226 public SignalWebSocket getSignalWebSocket() {
227 return getOrCreate(() -> signalWebSocket, () -> {
228 final var timer = new UptimeSleepTimer();
229 final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
230 final var webSocketFactory = new WebSocketFactory() {
231 @Override
232 public WebSocketConnection createWebSocket() {
233 return new OkHttpWebSocketConnection("normal",
234 serviceEnvironmentConfig.signalServiceConfiguration(),
235 Optional.of(credentialsProvider),
236 userAgent,
237 healthMonitor,
238 allowStories);
239 }
240
241 @Override
242 public WebSocketConnection createUnidentifiedWebSocket() {
243 return new OkHttpWebSocketConnection("unidentified",
244 serviceEnvironmentConfig.signalServiceConfiguration(),
245 Optional.empty(),
246 userAgent,
247 healthMonitor,
248 allowStories);
249 }
250 };
251 signalWebSocket = new SignalWebSocket(webSocketFactory);
252 healthMonitor.monitor(signalWebSocket);
253 });
254 }
255
256 public SignalServiceMessageReceiver getMessageReceiver() {
257 return getOrCreate(() -> messageReceiver,
258 () -> messageReceiver = new SignalServiceMessageReceiver(getPushServiceSocket()));
259 }
260
261 public SignalServiceMessageSender getMessageSender() {
262 return getOrCreate(() -> messageSender,
263 () -> messageSender = new SignalServiceMessageSender(getPushServiceSocket(),
264 dataStore,
265 sessionLock,
266 getSignalWebSocket(),
267 Optional.empty(),
268 executor,
269 ServiceConfig.MAX_ENVELOPE_SIZE));
270 }
271
272 public List<SecureValueRecovery> getSecureValueRecovery() {
273 return getOrCreate(() -> secureValueRecovery,
274 () -> secureValueRecovery = serviceEnvironmentConfig.svr2Mrenclaves()
275 .stream()
276 .map(mr -> (SecureValueRecovery) getAccountManager().getSecureValueRecoveryV2(mr))
277 .toList());
278 }
279
280 public ProfileService getProfileService() {
281 return getOrCreate(() -> profileService,
282 () -> profileService = new ProfileService(getClientZkProfileOperations(),
283 getMessageReceiver(),
284 getSignalWebSocket()));
285 }
286
287 public SignalServiceCipher getCipher(ServiceIdType serviceIdType) {
288 final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.unidentifiedSenderTrustRoot());
289 final var address = new SignalServiceAddress(credentialsProvider.getAci(), credentialsProvider.getE164());
290 final var deviceId = credentialsProvider.getDeviceId();
291 return new SignalServiceCipher(address,
292 deviceId,
293 serviceIdType == ServiceIdType.ACI ? dataStore.aci() : dataStore.pni(),
294 sessionLock,
295 certificateValidator);
296 }
297
298 private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
299 var value = supplier.get();
300 if (value != null) {
301 return value;
302 }
303
304 synchronized (LOCK) {
305 value = supplier.get();
306 if (value != null) {
307 return value;
308 }
309 creator.call();
310 return supplier.get();
311 }
312 }
313
314 private interface Callable {
315
316 void call();
317 }
318 }