]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java
37fbb3bb38db71099dda97798773371210165ead
[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.signal.libsignal.metadata.certificate.CertificateValidator;
6 import org.signal.libsignal.net.Network;
7 import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations;
8 import org.whispersystems.signalservice.api.SignalServiceAccountManager;
9 import org.whispersystems.signalservice.api.SignalServiceDataStore;
10 import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
11 import org.whispersystems.signalservice.api.SignalServiceMessageSender;
12 import org.whispersystems.signalservice.api.SignalSessionLock;
13 import org.whispersystems.signalservice.api.SignalWebSocket;
14 import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
15 import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
16 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
17 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
18 import org.whispersystems.signalservice.api.push.ServiceIdType;
19 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
20 import org.whispersystems.signalservice.api.services.ProfileService;
21 import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
22 import org.whispersystems.signalservice.api.util.CredentialsProvider;
23 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
24 import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
25 import org.whispersystems.signalservice.internal.push.ProvisioningSocket;
26 import org.whispersystems.signalservice.internal.push.PushServiceSocket;
27 import org.whispersystems.signalservice.internal.websocket.OkHttpWebSocketConnection;
28 import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
29
30 import java.util.List;
31 import java.util.Optional;
32 import java.util.concurrent.ExecutorService;
33 import java.util.function.Supplier;
34
35 public class SignalDependencies {
36
37 private final Object LOCK = new Object();
38
39 private final ServiceEnvironmentConfig serviceEnvironmentConfig;
40 private final String userAgent;
41 private final CredentialsProvider credentialsProvider;
42 private final SignalServiceDataStore dataStore;
43 private final ExecutorService executor;
44 private final SignalSessionLock sessionLock;
45
46 private boolean allowStories = true;
47
48 private SignalServiceAccountManager accountManager;
49 private GroupsV2Api groupsV2Api;
50 private GroupsV2Operations groupsV2Operations;
51 private ClientZkOperations clientZkOperations;
52
53 private PushServiceSocket pushServiceSocket;
54 private ProvisioningSocket provisioningSocket;
55 private Network libSignalNetwork;
56 private SignalWebSocket signalWebSocket;
57 private SignalServiceMessageReceiver messageReceiver;
58 private SignalServiceMessageSender messageSender;
59
60 private List<SecureValueRecovery> secureValueRecoveryV2;
61 private ProfileService profileService;
62
63 SignalDependencies(
64 final ServiceEnvironmentConfig serviceEnvironmentConfig,
65 final String userAgent,
66 final CredentialsProvider credentialsProvider,
67 final SignalServiceDataStore dataStore,
68 final ExecutorService executor,
69 final SignalSessionLock sessionLock
70 ) {
71 this.serviceEnvironmentConfig = serviceEnvironmentConfig;
72 this.userAgent = userAgent;
73 this.credentialsProvider = credentialsProvider;
74 this.dataStore = dataStore;
75 this.executor = executor;
76 this.sessionLock = sessionLock;
77 }
78
79 public void resetAfterAddressChange() {
80 if (this.pushServiceSocket != null) {
81 this.pushServiceSocket.close();
82 this.pushServiceSocket = null;
83 }
84 this.messageSender = null;
85 getSignalWebSocket().forceNewWebSockets();
86 }
87
88 /**
89 * This method needs to be called before the first websocket is created
90 */
91 public void setAllowStories(final boolean allowStories) {
92 this.allowStories = allowStories;
93 }
94
95 public ServiceEnvironmentConfig getServiceEnvironmentConfig() {
96 return serviceEnvironmentConfig;
97 }
98
99 public SignalSessionLock getSessionLock() {
100 return sessionLock;
101 }
102
103 public PushServiceSocket getPushServiceSocket() {
104 return getOrCreate(() -> pushServiceSocket,
105 () -> pushServiceSocket = new PushServiceSocket(serviceEnvironmentConfig.signalServiceConfiguration(),
106 credentialsProvider,
107 userAgent,
108 getClientZkProfileOperations(),
109 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
110 }
111
112 public ProvisioningSocket getProvisioningSocket() {
113 return getOrCreate(() -> provisioningSocket,
114 () -> provisioningSocket = new ProvisioningSocket(getServiceEnvironmentConfig().signalServiceConfiguration(),
115 userAgent));
116 }
117
118 public Network getLibSignalNetwork() {
119 return getOrCreate(() -> libSignalNetwork,
120 () -> libSignalNetwork = new Network(serviceEnvironmentConfig.netEnvironment(), userAgent));
121 }
122
123 public SignalServiceAccountManager getAccountManager() {
124 return getOrCreate(() -> accountManager,
125 () -> accountManager = new SignalServiceAccountManager(getPushServiceSocket(),
126 getProvisioningSocket(),
127 getGroupsV2Operations()));
128 }
129
130 public SignalServiceAccountManager createUnauthenticatedAccountManager(String number, String password) {
131 return SignalServiceAccountManager.createWithStaticCredentials(getServiceEnvironmentConfig().signalServiceConfiguration(),
132 null,
133 null,
134 number,
135 SignalServiceAddress.DEFAULT_DEVICE_ID,
136 password,
137 userAgent,
138 ServiceConfig.AUTOMATIC_NETWORK_RETRY,
139 ServiceConfig.GROUP_MAX_SIZE);
140 }
141
142 public GroupsV2Api getGroupsV2Api() {
143 return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
144 }
145
146 public GroupsV2Operations getGroupsV2Operations() {
147 return getOrCreate(() -> groupsV2Operations,
148 () -> groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()),
149 ServiceConfig.GROUP_MAX_SIZE));
150 }
151
152 private ClientZkOperations getClientZkOperations() {
153 return getOrCreate(() -> clientZkOperations,
154 () -> clientZkOperations = ClientZkOperations.create(serviceEnvironmentConfig.signalServiceConfiguration()));
155 }
156
157 private ClientZkProfileOperations getClientZkProfileOperations() {
158 final var clientZkOperations = getClientZkOperations();
159 return clientZkOperations.getProfileOperations();
160 }
161
162 public SignalWebSocket getSignalWebSocket() {
163 return getOrCreate(() -> signalWebSocket, () -> {
164 final var timer = new UptimeSleepTimer();
165 final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
166 final var webSocketFactory = new WebSocketFactory() {
167 @Override
168 public WebSocketConnection createWebSocket() {
169 return new OkHttpWebSocketConnection("normal",
170 serviceEnvironmentConfig.signalServiceConfiguration(),
171 Optional.of(credentialsProvider),
172 userAgent,
173 healthMonitor,
174 allowStories);
175 }
176
177 @Override
178 public WebSocketConnection createUnidentifiedWebSocket() {
179 return new OkHttpWebSocketConnection("unidentified",
180 serviceEnvironmentConfig.signalServiceConfiguration(),
181 Optional.empty(),
182 userAgent,
183 healthMonitor,
184 allowStories);
185 }
186 };
187 signalWebSocket = new SignalWebSocket(webSocketFactory);
188 healthMonitor.monitor(signalWebSocket);
189 });
190 }
191
192 public SignalServiceMessageReceiver getMessageReceiver() {
193 return getOrCreate(() -> messageReceiver,
194 () -> messageReceiver = new SignalServiceMessageReceiver(getPushServiceSocket()));
195 }
196
197 public SignalServiceMessageSender getMessageSender() {
198 return getOrCreate(() -> messageSender,
199 () -> messageSender = new SignalServiceMessageSender(getPushServiceSocket(),
200 dataStore,
201 sessionLock,
202 getSignalWebSocket(),
203 Optional.empty(),
204 executor,
205 ServiceConfig.MAX_ENVELOPE_SIZE));
206 }
207
208 public List<SecureValueRecovery> getSecureValueRecoveryV2() {
209 return getOrCreate(() -> secureValueRecoveryV2,
210 () -> secureValueRecoveryV2 = serviceEnvironmentConfig.svr2Mrenclaves()
211 .stream()
212 .map(mr -> (SecureValueRecovery) getAccountManager().getSecureValueRecoveryV2(mr))
213 .toList());
214 }
215
216 public ProfileService getProfileService() {
217 return getOrCreate(() -> profileService,
218 () -> profileService = new ProfileService(getClientZkProfileOperations(),
219 getMessageReceiver(),
220 getSignalWebSocket()));
221 }
222
223 public SignalServiceCipher getCipher(ServiceIdType serviceIdType) {
224 final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.unidentifiedSenderTrustRoot());
225 final var address = new SignalServiceAddress(credentialsProvider.getAci(), credentialsProvider.getE164());
226 final var deviceId = credentialsProvider.getDeviceId();
227 return new SignalServiceCipher(address,
228 deviceId,
229 serviceIdType == ServiceIdType.ACI ? dataStore.aci() : dataStore.pni(),
230 sessionLock,
231 certificateValidator);
232 }
233
234 private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
235 var value = supplier.get();
236 if (value != null) {
237 return value;
238 }
239
240 synchronized (LOCK) {
241 value = supplier.get();
242 if (value != null) {
243 return value;
244 }
245 creator.call();
246 return supplier.get();
247 }
248 }
249
250 private interface Callable {
251
252 void call();
253 }
254 }