]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java
abdebd9a574b6ca9307f88a3fefe7d93fcb56c9c
[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.account.AccountApi;
17 import org.whispersystems.signalservice.api.attachment.AttachmentApi;
18 import org.whispersystems.signalservice.api.cds.CdsApi;
19 import org.whispersystems.signalservice.api.certificate.CertificateApi;
20 import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
21 import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
22 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
23 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
24 import org.whispersystems.signalservice.api.keys.KeysApi;
25 import org.whispersystems.signalservice.api.link.LinkDeviceApi;
26 import org.whispersystems.signalservice.api.message.MessageApi;
27 import org.whispersystems.signalservice.api.profiles.ProfileApi;
28 import org.whispersystems.signalservice.api.push.ServiceIdType;
29 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
30 import org.whispersystems.signalservice.api.ratelimit.RateLimitChallengeApi;
31 import org.whispersystems.signalservice.api.registration.RegistrationApi;
32 import org.whispersystems.signalservice.api.services.ProfileService;
33 import org.whispersystems.signalservice.api.storage.StorageServiceApi;
34 import org.whispersystems.signalservice.api.storage.StorageServiceRepository;
35 import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
36 import org.whispersystems.signalservice.api.username.UsernameApi;
37 import org.whispersystems.signalservice.api.util.CredentialsProvider;
38 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
39 import org.whispersystems.signalservice.api.websocket.SignalWebSocket;
40 import org.whispersystems.signalservice.internal.push.PushServiceSocket;
41 import org.whispersystems.signalservice.internal.websocket.OkHttpWebSocketConnection;
42
43 import java.io.IOException;
44 import java.net.InetSocketAddress;
45 import java.net.Proxy;
46 import java.util.List;
47 import java.util.Optional;
48 import java.util.concurrent.ExecutorService;
49 import java.util.concurrent.TimeUnit;
50 import java.util.function.Supplier;
51
52 public class SignalDependencies {
53
54 private static final Logger logger = LoggerFactory.getLogger(SignalDependencies.class);
55
56 private final Object LOCK = new Object();
57
58 private final ServiceEnvironmentConfig serviceEnvironmentConfig;
59 private final String userAgent;
60 private final CredentialsProvider credentialsProvider;
61 private final SignalServiceDataStore dataStore;
62 private final ExecutorService executor;
63 private final SignalSessionLock sessionLock;
64
65 private boolean allowStories = true;
66
67 private SignalServiceAccountManager accountManager;
68 private AccountApi accountApi;
69 private RateLimitChallengeApi rateLimitChallengeApi;
70 private CdsApi cdsApi;
71 private UsernameApi usernameApi;
72 private GroupsV2Api groupsV2Api;
73 private RegistrationApi registrationApi;
74 private LinkDeviceApi linkDeviceApi;
75 private StorageServiceApi storageServiceApi;
76 private CertificateApi certificateApi;
77 private AttachmentApi attachmentApi;
78 private MessageApi messageApi;
79 private KeysApi keysApi;
80 private GroupsV2Operations groupsV2Operations;
81 private ClientZkOperations clientZkOperations;
82
83 private PushServiceSocket pushServiceSocket;
84 private Network libSignalNetwork;
85 private SignalWebSocket.AuthenticatedWebSocket authenticatedSignalWebSocket;
86 private SignalWebSocket.UnauthenticatedWebSocket unauthenticatedSignalWebSocket;
87 private SignalServiceMessageReceiver messageReceiver;
88 private SignalServiceMessageSender messageSender;
89
90 private List<SecureValueRecovery> secureValueRecovery;
91 private ProfileService profileService;
92 private ProfileApi profileApi;
93
94 SignalDependencies(
95 final ServiceEnvironmentConfig serviceEnvironmentConfig,
96 final String userAgent,
97 final CredentialsProvider credentialsProvider,
98 final SignalServiceDataStore dataStore,
99 final ExecutorService executor,
100 final SignalSessionLock sessionLock
101 ) {
102 this.serviceEnvironmentConfig = serviceEnvironmentConfig;
103 this.userAgent = userAgent;
104 this.credentialsProvider = credentialsProvider;
105 this.dataStore = dataStore;
106 this.executor = executor;
107 this.sessionLock = sessionLock;
108 }
109
110 public void resetAfterAddressChange() {
111 if (this.pushServiceSocket != null) {
112 this.pushServiceSocket.close();
113 this.pushServiceSocket = null;
114 this.accountManager = null;
115 this.messageReceiver = null;
116 this.messageSender = null;
117 this.profileService = null;
118 this.groupsV2Api = null;
119 this.registrationApi = null;
120 this.secureValueRecovery = null;
121 }
122 if (this.authenticatedSignalWebSocket != null) {
123 this.authenticatedSignalWebSocket.forceNewWebSocket();
124 }
125 if (this.unauthenticatedSignalWebSocket != null) {
126 this.unauthenticatedSignalWebSocket.forceNewWebSocket();
127 }
128 }
129
130 /**
131 * This method needs to be called before the first websocket is created
132 */
133 public void setAllowStories(final boolean allowStories) {
134 this.allowStories = allowStories;
135 }
136
137 public ServiceEnvironmentConfig getServiceEnvironmentConfig() {
138 return serviceEnvironmentConfig;
139 }
140
141 public SignalSessionLock getSessionLock() {
142 return sessionLock;
143 }
144
145 public PushServiceSocket getPushServiceSocket() {
146 return getOrCreate(() -> pushServiceSocket,
147 () -> pushServiceSocket = new PushServiceSocket(serviceEnvironmentConfig.signalServiceConfiguration(),
148 credentialsProvider,
149 userAgent,
150 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
151 }
152
153 public Network getLibSignalNetwork() {
154 return getOrCreate(() -> libSignalNetwork, () -> {
155 libSignalNetwork = new Network(serviceEnvironmentConfig.netEnvironment(), userAgent);
156 setSignalNetworkProxy(libSignalNetwork);
157 });
158 }
159
160 private void setSignalNetworkProxy(Network libSignalNetwork) {
161 final var proxy = Utils.getHttpsProxy();
162 if (proxy.address() instanceof InetSocketAddress addr) {
163 switch (proxy.type()) {
164 case Proxy.Type.DIRECT -> {
165 }
166 case Proxy.Type.HTTP -> {
167 try {
168 libSignalNetwork.setProxy("http", addr.getHostName(), addr.getPort(), null, null);
169 } catch (IOException e) {
170 logger.warn("Failed to set http proxy", e);
171 }
172 }
173 case Proxy.Type.SOCKS -> {
174 try {
175 libSignalNetwork.setProxy("socks", addr.getHostName(), addr.getPort(), null, null);
176 } catch (IOException e) {
177 logger.warn("Failed to set socks proxy", e);
178 }
179 }
180 }
181 }
182 }
183
184 public SignalServiceAccountManager getAccountManager() {
185 return getOrCreate(() -> accountManager,
186 () -> accountManager = new SignalServiceAccountManager(getAuthenticatedSignalWebSocket(),
187 getAccountApi(),
188 getPushServiceSocket(),
189 getGroupsV2Operations()));
190 }
191
192 public SignalServiceAccountManager createUnauthenticatedAccountManager(String number, String password) {
193 return SignalServiceAccountManager.createWithStaticCredentials(getServiceEnvironmentConfig().signalServiceConfiguration(),
194 null,
195 null,
196 number,
197 SignalServiceAddress.DEFAULT_DEVICE_ID,
198 password,
199 userAgent,
200 ServiceConfig.AUTOMATIC_NETWORK_RETRY,
201 ServiceConfig.GROUP_MAX_SIZE);
202 }
203
204 public AccountApi getAccountApi() {
205 return getOrCreate(() -> accountApi, () -> accountApi = new AccountApi(getAuthenticatedSignalWebSocket()));
206 }
207
208 public RateLimitChallengeApi getRateLimitChallengeApi() {
209 return getOrCreate(() -> rateLimitChallengeApi,
210 () -> rateLimitChallengeApi = new RateLimitChallengeApi(getAuthenticatedSignalWebSocket()));
211 }
212
213 public CdsApi getCdsApi() {
214 return getOrCreate(() -> cdsApi, () -> cdsApi = new CdsApi(getAuthenticatedSignalWebSocket()));
215 }
216
217 public UsernameApi getUsernameApi() {
218 return getOrCreate(() -> usernameApi, () -> usernameApi = new UsernameApi(getUnauthenticatedSignalWebSocket()));
219 }
220
221 public GroupsV2Api getGroupsV2Api() {
222 return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
223 }
224
225 public RegistrationApi getRegistrationApi() {
226 return getOrCreate(() -> registrationApi, () -> registrationApi = getAccountManager().getRegistrationApi());
227 }
228
229 public LinkDeviceApi getLinkDeviceApi() {
230 return getOrCreate(() -> linkDeviceApi,
231 () -> linkDeviceApi = new LinkDeviceApi(getAuthenticatedSignalWebSocket()));
232 }
233
234 private StorageServiceApi getStorageServiceApi() {
235 return getOrCreate(() -> storageServiceApi,
236 () -> storageServiceApi = new StorageServiceApi(getAuthenticatedSignalWebSocket(),
237 getPushServiceSocket()));
238 }
239
240 public StorageServiceRepository getStorageServiceRepository() {
241 return new StorageServiceRepository(getStorageServiceApi());
242 }
243
244 public CertificateApi getCertificateApi() {
245 return getOrCreate(() -> certificateApi,
246 () -> certificateApi = new CertificateApi(getAuthenticatedSignalWebSocket()));
247 }
248
249 public AttachmentApi getAttachmentApi() {
250 return getOrCreate(() -> attachmentApi,
251 () -> attachmentApi = new AttachmentApi(getAuthenticatedSignalWebSocket(), getPushServiceSocket()));
252 }
253
254 public MessageApi getMessageApi() {
255 return getOrCreate(() -> messageApi,
256 () -> messageApi = new MessageApi(getAuthenticatedSignalWebSocket(),
257 getUnauthenticatedSignalWebSocket()));
258 }
259
260 public KeysApi getKeysApi() {
261 return getOrCreate(() -> keysApi,
262 () -> keysApi = new KeysApi(getAuthenticatedSignalWebSocket(), getUnauthenticatedSignalWebSocket()));
263 }
264
265 public GroupsV2Operations getGroupsV2Operations() {
266 return getOrCreate(() -> groupsV2Operations,
267 () -> groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()),
268 ServiceConfig.GROUP_MAX_SIZE));
269 }
270
271 private ClientZkOperations getClientZkOperations() {
272 return getOrCreate(() -> clientZkOperations,
273 () -> clientZkOperations = ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()));
274 }
275
276 private ClientZkProfileOperations getClientZkProfileOperations() {
277 final var clientZkOperations = getClientZkOperations();
278 return clientZkOperations.getProfileOperations();
279 }
280
281 public SignalWebSocket.AuthenticatedWebSocket getAuthenticatedSignalWebSocket() {
282 return getOrCreate(() -> authenticatedSignalWebSocket, () -> {
283 final var timer = new UptimeSleepTimer();
284 final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
285
286 authenticatedSignalWebSocket = new SignalWebSocket.AuthenticatedWebSocket(() -> new OkHttpWebSocketConnection(
287 "normal",
288 serviceEnvironmentConfig.signalServiceConfiguration(),
289 Optional.of(credentialsProvider),
290 userAgent,
291 healthMonitor,
292 allowStories), () -> true, timer, TimeUnit.SECONDS.toMillis(10));
293 healthMonitor.monitor(authenticatedSignalWebSocket);
294 });
295 }
296
297 public SignalWebSocket.UnauthenticatedWebSocket getUnauthenticatedSignalWebSocket() {
298 return getOrCreate(() -> unauthenticatedSignalWebSocket, () -> {
299 final var timer = new UptimeSleepTimer();
300 final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
301
302 unauthenticatedSignalWebSocket = new SignalWebSocket.UnauthenticatedWebSocket(() -> new OkHttpWebSocketConnection(
303 "unidentified",
304 serviceEnvironmentConfig.signalServiceConfiguration(),
305 Optional.empty(),
306 userAgent,
307 healthMonitor,
308 allowStories), () -> true, timer, TimeUnit.SECONDS.toMillis(10));
309 healthMonitor.monitor(unauthenticatedSignalWebSocket);
310 });
311 }
312
313 public SignalServiceMessageReceiver getMessageReceiver() {
314 return getOrCreate(() -> messageReceiver,
315 () -> messageReceiver = new SignalServiceMessageReceiver(getPushServiceSocket()));
316 }
317
318 public SignalServiceMessageSender getMessageSender() {
319 return getOrCreate(() -> messageSender,
320 () -> messageSender = new SignalServiceMessageSender(getPushServiceSocket(),
321 dataStore,
322 sessionLock,
323 getAttachmentApi(),
324 getMessageApi(),
325 getKeysApi(),
326 Optional.empty(),
327 executor,
328 ServiceConfig.MAX_ENVELOPE_SIZE));
329 }
330
331 public List<SecureValueRecovery> getSecureValueRecovery() {
332 return getOrCreate(() -> secureValueRecovery,
333 () -> secureValueRecovery = serviceEnvironmentConfig.svr2Mrenclaves()
334 .stream()
335 .map(mr -> (SecureValueRecovery) getAccountManager().getSecureValueRecoveryV2(mr))
336 .toList());
337 }
338
339 public ProfileApi getProfileApi() {
340 return getOrCreate(() -> profileApi,
341 () -> profileApi = new ProfileApi(getAuthenticatedSignalWebSocket(), getPushServiceSocket()));
342 }
343
344 public ProfileService getProfileService() {
345 return getOrCreate(() -> profileService,
346 () -> profileService = new ProfileService(getClientZkProfileOperations(),
347 getAuthenticatedSignalWebSocket(),
348 getUnauthenticatedSignalWebSocket()));
349 }
350
351 public SignalServiceCipher getCipher(ServiceIdType serviceIdType) {
352 final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.unidentifiedSenderTrustRoot());
353 final var address = new SignalServiceAddress(credentialsProvider.getAci(), credentialsProvider.getE164());
354 final var deviceId = credentialsProvider.getDeviceId();
355 return new SignalServiceCipher(address,
356 deviceId,
357 serviceIdType == ServiceIdType.ACI ? dataStore.aci() : dataStore.pni(),
358 sessionLock,
359 certificateValidator);
360 }
361
362 private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
363 var value = supplier.get();
364 if (value != null) {
365 return value;
366 }
367
368 synchronized (LOCK) {
369 value = supplier.get();
370 if (value != null) {
371 return value;
372 }
373 creator.call();
374 return supplier.get();
375 }
376 }
377
378 private interface Callable {
379
380 void call();
381 }
382 }