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