]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java
Improve handling of group join messages
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / SignalDependencies.java
1 package org.asamk.signal.manager;
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 import static org.asamk.signal.manager.config.ServiceConfig.capabilities;
31
32 public class SignalDependencies {
33
34 private final Object LOCK = new Object();
35
36 private final ServiceEnvironmentConfig serviceEnvironmentConfig;
37 private final String userAgent;
38 private final CredentialsProvider credentialsProvider;
39 private final SignalServiceDataStore dataStore;
40 private final ExecutorService executor;
41 private final SignalSessionLock sessionLock;
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 }
76
77 public ServiceEnvironmentConfig getServiceEnvironmentConfig() {
78 return serviceEnvironmentConfig;
79 }
80
81 public SignalServiceAccountManager getAccountManager() {
82 return getOrCreate(() -> accountManager,
83 () -> accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
84 credentialsProvider,
85 userAgent,
86 getGroupsV2Operations(),
87 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
88 }
89
90 public SignalServiceAccountManager createUnauthenticatedAccountManager(String number, String password) {
91 return new SignalServiceAccountManager(getServiceEnvironmentConfig().getSignalServiceConfiguration(),
92 null,
93 null,
94 number,
95 SignalServiceAddress.DEFAULT_DEVICE_ID,
96 password,
97 userAgent,
98 ServiceConfig.AUTOMATIC_NETWORK_RETRY,
99 ServiceConfig.GROUP_MAX_SIZE);
100 }
101
102 public GroupsV2Api getGroupsV2Api() {
103 return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
104 }
105
106 public GroupsV2Operations getGroupsV2Operations() {
107 return getOrCreate(() -> groupsV2Operations,
108 () -> groupsV2Operations = capabilities.isGv2()
109 ? new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration()),
110 ServiceConfig.GROUP_MAX_SIZE)
111 : null);
112 }
113
114 private ClientZkOperations getClientZkOperations() {
115 return getOrCreate(() -> clientZkOperations,
116 () -> clientZkOperations = capabilities.isGv2()
117 ? ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration())
118 : null);
119 }
120
121 private ClientZkProfileOperations getClientZkProfileOperations() {
122 final var clientZkOperations = getClientZkOperations();
123 return clientZkOperations == null ? null : clientZkOperations.getProfileOperations();
124 }
125
126 public SignalWebSocket getSignalWebSocket() {
127 return getOrCreate(() -> signalWebSocket, () -> {
128 final var timer = new UptimeSleepTimer();
129 final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
130 final var webSocketFactory = new WebSocketFactory() {
131 @Override
132 public WebSocketConnection createWebSocket() {
133 return new WebSocketConnection("normal",
134 serviceEnvironmentConfig.getSignalServiceConfiguration(),
135 Optional.of(credentialsProvider),
136 userAgent,
137 healthMonitor,
138 true);
139 }
140
141 @Override
142 public WebSocketConnection createUnidentifiedWebSocket() {
143 return new WebSocketConnection("unidentified",
144 serviceEnvironmentConfig.getSignalServiceConfiguration(),
145 Optional.empty(),
146 userAgent,
147 healthMonitor,
148 true);
149 }
150 };
151 signalWebSocket = new SignalWebSocket(webSocketFactory);
152 healthMonitor.monitor(signalWebSocket);
153 });
154 }
155
156 public SignalServiceMessageReceiver getMessageReceiver() {
157 return getOrCreate(() -> messageReceiver,
158 () -> messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
159 credentialsProvider,
160 userAgent,
161 getClientZkProfileOperations(),
162 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
163 }
164
165 public SignalServiceMessageSender getMessageSender() {
166 return getOrCreate(() -> messageSender,
167 () -> messageSender = new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
168 credentialsProvider,
169 dataStore,
170 sessionLock,
171 userAgent,
172 getSignalWebSocket(),
173 Optional.empty(),
174 getClientZkProfileOperations(),
175 executor,
176 ServiceConfig.MAX_ENVELOPE_SIZE,
177 ServiceConfig.AUTOMATIC_NETWORK_RETRY));
178 }
179
180 public KeyBackupService getKeyBackupService() {
181 return getOrCreate(() -> keyBackupService,
182 () -> keyBackupService = getAccountManager().getKeyBackupService(ServiceConfig.getIasKeyStore(),
183 serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
184 serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
185 serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
186 10));
187 }
188
189 public Collection<KeyBackupService> getFallbackKeyBackupServices() {
190 return serviceEnvironmentConfig.getFallbackKeyBackupConfigs()
191 .stream()
192 .map(config -> getAccountManager().getKeyBackupService(ServiceConfig.getIasKeyStore(),
193 config.getEnclaveName(),
194 config.getServiceId(),
195 config.getMrenclave(),
196 10))
197 .toList();
198 }
199
200 public ProfileService getProfileService() {
201 return getOrCreate(() -> profileService,
202 () -> profileService = new ProfileService(getClientZkProfileOperations(),
203 getMessageReceiver(),
204 getSignalWebSocket()));
205 }
206
207 public SignalServiceCipher getCipher() {
208 return getOrCreate(() -> cipher, () -> {
209 final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
210 final var address = new SignalServiceAddress(credentialsProvider.getAci(), credentialsProvider.getE164());
211 final var deviceId = credentialsProvider.getDeviceId();
212 cipher = new SignalServiceCipher(address, deviceId, dataStore.aci(), sessionLock, certificateValidator);
213 });
214 }
215
216 private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
217 var value = supplier.get();
218 if (value != null) {
219 return value;
220 }
221
222 synchronized (LOCK) {
223 value = supplier.get();
224 if (value != null) {
225 return value;
226 }
227 creator.call();
228 return supplier.get();
229 }
230 }
231
232 private interface Callable {
233
234 void call();
235 }
236 }