Create libsignal dependencies only when required

This commit is contained in:
AsamK 2021-08-30 15:07:12 +02:00
parent 1f0c2d5c78
commit 626406a43c
7 changed files with 138 additions and 130 deletions

View file

@ -164,8 +164,7 @@ public class Manager implements Closeable {
return LEGACY_LOCK::unlock; return LEGACY_LOCK::unlock;
} }
}; };
this.dependencies = new SignalDependencies(account.getSelfAddress(), this.dependencies = new SignalDependencies(serviceEnvironmentConfig,
serviceEnvironmentConfig,
userAgent, userAgent,
credentialsProvider, credentialsProvider,
account.getSignalProtocolStore(), account.getSignalProtocolStore(),
@ -186,8 +185,6 @@ public class Manager implements Closeable {
avatarStore, avatarStore,
account.getProfileStore()::getProfileKey, account.getProfileStore()::getProfileKey,
unidentifiedAccessHelper::getAccessFor, unidentifiedAccessHelper::getAccessFor,
dependencies::getProfileService,
dependencies::getMessageReceiver,
this::resolveSignalServiceAddress); this::resolveSignalServiceAddress);
final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential, final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential,
this::getRecipientProfile, this::getRecipientProfile,
@ -220,8 +217,7 @@ public class Manager implements Closeable {
this::resolveSignalServiceAddress); this::resolveSignalServiceAddress);
this.context = new Context(account, this.context = new Context(account,
dependencies.getAccountManager(), dependencies,
dependencies.getMessageReceiver(),
stickerPackStore, stickerPackStore,
sendHelper, sendHelper,
groupHelper, groupHelper,
@ -1149,10 +1145,6 @@ public class Manager implements Closeable {
} }
public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) { public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) {
if (address.matches(account.getSelfAddress())) {
return account.getSelfAddress();
}
return resolveSignalServiceAddress(resolveRecipient(address)); return resolveSignalServiceAddress(resolveRecipient(address));
} }

View file

@ -3,7 +3,6 @@ package org.asamk.signal.manager;
import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.signal.libsignal.metadata.certificate.CertificateValidator; import org.signal.libsignal.metadata.certificate.CertificateValidator;
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.KeyBackupService; import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
@ -18,32 +17,41 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer; import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.WebSocketFactory; import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider; import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection; import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
import static org.asamk.signal.manager.config.ServiceConfig.capabilities; import static org.asamk.signal.manager.config.ServiceConfig.capabilities;
public class SignalDependencies { public class SignalDependencies {
private final SignalServiceAccountManager accountManager; private final Object LOCK = new Object();
private final GroupsV2Api groupsV2Api;
private final GroupsV2Operations groupsV2Operations;
private final SignalWebSocket signalWebSocket; private final ServiceEnvironmentConfig serviceEnvironmentConfig;
private final SignalServiceMessageReceiver messageReceiver; private final String userAgent;
private final SignalServiceMessageSender messageSender; private final DynamicCredentialsProvider credentialsProvider;
private final SignalServiceDataStore dataStore;
private final ExecutorService executor;
private final SignalSessionLock sessionLock;
private final KeyBackupService keyBackupService; private SignalServiceAccountManager accountManager;
private final ProfileService profileService; private GroupsV2Api groupsV2Api;
private final SignalServiceCipher cipher; private GroupsV2Operations groupsV2Operations;
private ClientZkOperations clientZkOperations;
private SignalWebSocket signalWebSocket;
private SignalServiceMessageReceiver messageReceiver;
private SignalServiceMessageSender messageSender;
private KeyBackupService keyBackupService;
private ProfileService profileService;
private SignalServiceCipher cipher;
public SignalDependencies( public SignalDependencies(
final SignalServiceAddress selfAddress,
final ServiceEnvironmentConfig serviceEnvironmentConfig, final ServiceEnvironmentConfig serviceEnvironmentConfig,
final String userAgent, final String userAgent,
final DynamicCredentialsProvider credentialsProvider, final DynamicCredentialsProvider credentialsProvider,
@ -51,100 +59,134 @@ public class SignalDependencies {
final ExecutorService executor, final ExecutorService executor,
final SignalSessionLock sessionLock final SignalSessionLock sessionLock
) { ) {
this.groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create( this.serviceEnvironmentConfig = serviceEnvironmentConfig;
serviceEnvironmentConfig.getSignalServiceConfiguration())) : null; this.userAgent = userAgent;
final SleepTimer timer = new UptimeSleepTimer(); this.credentialsProvider = credentialsProvider;
this.accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(), this.dataStore = dataStore;
credentialsProvider, this.executor = executor;
userAgent, this.sessionLock = sessionLock;
groupsV2Operations,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
this.groupsV2Api = accountManager.getGroupsV2Api();
this.keyBackupService = accountManager.getKeyBackupService(ServiceConfig.getIasKeyStore(),
serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
10);
final ClientZkProfileOperations clientZkProfileOperations = capabilities.isGv2() ? ClientZkOperations.create(
serviceEnvironmentConfig.getSignalServiceConfiguration()).getProfileOperations() : null;
this.messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
clientZkProfileOperations,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
final WebSocketFactory webSocketFactory = new WebSocketFactory() {
@Override
public WebSocketConnection createWebSocket() {
return new WebSocketConnection("normal",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.of(credentialsProvider),
userAgent,
healthMonitor);
}
@Override
public WebSocketConnection createUnidentifiedWebSocket() {
return new WebSocketConnection("unidentified",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.absent(),
userAgent,
healthMonitor);
}
};
this.signalWebSocket = new SignalWebSocket(webSocketFactory);
healthMonitor.monitor(signalWebSocket);
this.profileService = new ProfileService(clientZkProfileOperations, messageReceiver, signalWebSocket);
final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
this.cipher = new SignalServiceCipher(selfAddress, dataStore, sessionLock, certificateValidator);
this.messageSender = new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
dataStore,
sessionLock,
userAgent,
signalWebSocket,
Optional.absent(),
clientZkProfileOperations,
executor,
ServiceConfig.MAX_ENVELOPE_SIZE,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
} }
public SignalServiceAccountManager getAccountManager() { public SignalServiceAccountManager getAccountManager() {
return accountManager; return getOrCreate(() -> accountManager,
() -> accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
getGroupsV2Operations(),
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public GroupsV2Api getGroupsV2Api() { public GroupsV2Api getGroupsV2Api() {
return groupsV2Api; return getOrCreate(() -> groupsV2Api, () -> groupsV2Api = getAccountManager().getGroupsV2Api());
} }
public GroupsV2Operations getGroupsV2Operations() { public GroupsV2Operations getGroupsV2Operations() {
return groupsV2Operations; return getOrCreate(() -> groupsV2Operations,
() -> groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create(
serviceEnvironmentConfig.getSignalServiceConfiguration())) : null);
}
private ClientZkOperations getClientZkOperations() {
return getOrCreate(() -> clientZkOperations,
() -> clientZkOperations = capabilities.isGv2()
? ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration())
: null);
} }
public SignalWebSocket getSignalWebSocket() { public SignalWebSocket getSignalWebSocket() {
return signalWebSocket; return getOrCreate(() -> signalWebSocket, () -> {
final var timer = new UptimeSleepTimer();
final var healthMonitor = new SignalWebSocketHealthMonitor(timer);
final var webSocketFactory = new WebSocketFactory() {
@Override
public WebSocketConnection createWebSocket() {
return new WebSocketConnection("normal",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.of(credentialsProvider),
userAgent,
healthMonitor);
}
@Override
public WebSocketConnection createUnidentifiedWebSocket() {
return new WebSocketConnection("unidentified",
serviceEnvironmentConfig.getSignalServiceConfiguration(),
Optional.absent(),
userAgent,
healthMonitor);
}
};
signalWebSocket = new SignalWebSocket(webSocketFactory);
healthMonitor.monitor(signalWebSocket);
});
} }
public SignalServiceMessageReceiver getMessageReceiver() { public SignalServiceMessageReceiver getMessageReceiver() {
return messageReceiver; return getOrCreate(() -> messageReceiver,
() -> messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
userAgent,
getClientZkOperations().getProfileOperations(),
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public SignalServiceMessageSender getMessageSender() { public SignalServiceMessageSender getMessageSender() {
return messageSender; return getOrCreate(() -> messageSender,
() -> messageSender = new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
credentialsProvider,
dataStore,
sessionLock,
userAgent,
getSignalWebSocket(),
Optional.absent(),
getClientZkOperations().getProfileOperations(),
executor,
ServiceConfig.MAX_ENVELOPE_SIZE,
ServiceConfig.AUTOMATIC_NETWORK_RETRY));
} }
public KeyBackupService getKeyBackupService() { public KeyBackupService getKeyBackupService() {
return keyBackupService; return getOrCreate(() -> keyBackupService,
() -> keyBackupService = getAccountManager().getKeyBackupService(ServiceConfig.getIasKeyStore(),
serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
10));
} }
public ProfileService getProfileService() { public ProfileService getProfileService() {
return profileService; return getOrCreate(() -> profileService,
() -> profileService = new ProfileService(getClientZkOperations().getProfileOperations(),
getMessageReceiver(),
getSignalWebSocket()));
} }
public SignalServiceCipher getCipher() { public SignalServiceCipher getCipher() {
return cipher; return getOrCreate(() -> cipher, () -> {
final var certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
final var address = new SignalServiceAddress(credentialsProvider.getUuid(), credentialsProvider.getE164());
cipher = new SignalServiceCipher(address, dataStore, sessionLock, certificateValidator);
});
}
private <T> T getOrCreate(Supplier<T> supplier, Callable creator) {
var value = supplier.get();
if (value != null) {
return value;
}
synchronized (LOCK) {
value = supplier.get();
if (value != null) {
return value;
}
creator.call();
return supplier.get();
}
}
private interface Callable {
void call();
} }
} }

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
public interface MessageReceiverProvider {
SignalServiceMessageReceiver getMessageReceiver();
}

View file

@ -45,8 +45,6 @@ public final class ProfileHelper {
private final AvatarStore avatarStore; private final AvatarStore avatarStore;
private final ProfileKeyProvider profileKeyProvider; private final ProfileKeyProvider profileKeyProvider;
private final UnidentifiedAccessProvider unidentifiedAccessProvider; private final UnidentifiedAccessProvider unidentifiedAccessProvider;
private final ProfileServiceProvider profileServiceProvider;
private final MessageReceiverProvider messageReceiverProvider;
private final SignalServiceAddressResolver addressResolver; private final SignalServiceAddressResolver addressResolver;
public ProfileHelper( public ProfileHelper(
@ -55,8 +53,6 @@ public final class ProfileHelper {
final AvatarStore avatarStore, final AvatarStore avatarStore,
final ProfileKeyProvider profileKeyProvider, final ProfileKeyProvider profileKeyProvider,
final UnidentifiedAccessProvider unidentifiedAccessProvider, final UnidentifiedAccessProvider unidentifiedAccessProvider,
final ProfileServiceProvider profileServiceProvider,
final MessageReceiverProvider messageReceiverProvider,
final SignalServiceAddressResolver addressResolver final SignalServiceAddressResolver addressResolver
) { ) {
this.account = account; this.account = account;
@ -64,8 +60,6 @@ public final class ProfileHelper {
this.avatarStore = avatarStore; this.avatarStore = avatarStore;
this.profileKeyProvider = profileKeyProvider; this.profileKeyProvider = profileKeyProvider;
this.unidentifiedAccessProvider = unidentifiedAccessProvider; this.unidentifiedAccessProvider = unidentifiedAccessProvider;
this.profileServiceProvider = profileServiceProvider;
this.messageReceiverProvider = messageReceiverProvider;
this.addressResolver = addressResolver; this.addressResolver = addressResolver;
} }
@ -218,7 +212,7 @@ public final class ProfileHelper {
} }
private SignalServiceProfile retrieveProfileSync(String username) throws IOException { private SignalServiceProfile retrieveProfileSync(String username) throws IOException {
return messageReceiverProvider.getMessageReceiver().retrieveProfileByUsername(username, Optional.absent()); return dependencies.getMessageReceiver().retrieveProfileByUsername(username, Optional.absent());
} }
private ProfileAndCredential retrieveProfileAndCredential( private ProfileAndCredential retrieveProfileAndCredential(
@ -287,7 +281,7 @@ public final class ProfileHelper {
Optional<UnidentifiedAccess> unidentifiedAccess, Optional<UnidentifiedAccess> unidentifiedAccess,
SignalServiceProfile.RequestType requestType SignalServiceProfile.RequestType requestType
) { ) {
var profileService = profileServiceProvider.getProfileService(); var profileService = dependencies.getProfileService();
Single<ServiceResponse<ProfileAndCredential>> responseSingle; Single<ServiceResponse<ProfileAndCredential>> responseSingle;
try { try {

View file

@ -1,8 +0,0 @@
package org.asamk.signal.manager.helper;
import org.whispersystems.signalservice.api.services.ProfileService;
public interface ProfileServiceProvider {
ProfileService getProfileService();
}

View file

@ -1,19 +1,17 @@
package org.asamk.signal.manager.jobs; package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.SignalDependencies;
import org.asamk.signal.manager.StickerPackStore; import org.asamk.signal.manager.StickerPackStore;
import org.asamk.signal.manager.helper.GroupHelper; import org.asamk.signal.manager.helper.GroupHelper;
import org.asamk.signal.manager.helper.ProfileHelper; import org.asamk.signal.manager.helper.ProfileHelper;
import org.asamk.signal.manager.helper.SendHelper; import org.asamk.signal.manager.helper.SendHelper;
import org.asamk.signal.manager.helper.SyncHelper; import org.asamk.signal.manager.helper.SyncHelper;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
public class Context { public class Context {
private final SignalAccount account; private final SignalAccount account;
private final SignalServiceAccountManager accountManager; private final SignalDependencies dependencies;
private final SignalServiceMessageReceiver messageReceiver;
private final StickerPackStore stickerPackStore; private final StickerPackStore stickerPackStore;
private final SendHelper sendHelper; private final SendHelper sendHelper;
private final GroupHelper groupHelper; private final GroupHelper groupHelper;
@ -22,8 +20,7 @@ public class Context {
public Context( public Context(
final SignalAccount account, final SignalAccount account,
final SignalServiceAccountManager accountManager, final SignalDependencies dependencies,
final SignalServiceMessageReceiver messageReceiver,
final StickerPackStore stickerPackStore, final StickerPackStore stickerPackStore,
final SendHelper sendHelper, final SendHelper sendHelper,
final GroupHelper groupHelper, final GroupHelper groupHelper,
@ -31,8 +28,7 @@ public class Context {
final ProfileHelper profileHelper final ProfileHelper profileHelper
) { ) {
this.account = account; this.account = account;
this.accountManager = accountManager; this.dependencies = dependencies;
this.messageReceiver = messageReceiver;
this.stickerPackStore = stickerPackStore; this.stickerPackStore = stickerPackStore;
this.sendHelper = sendHelper; this.sendHelper = sendHelper;
this.groupHelper = groupHelper; this.groupHelper = groupHelper;
@ -44,12 +40,8 @@ public class Context {
return account; return account;
} }
public SignalServiceAccountManager getAccountManager() { public SignalDependencies getDependencies() {
return accountManager; return dependencies;
}
public SignalServiceMessageReceiver getMessageReceiver() {
return messageReceiver;
} }
public StickerPackStore getStickerPackStore() { public StickerPackStore getStickerPackStore() {

View file

@ -32,7 +32,9 @@ public class RetrieveStickerPackJob implements Job {
} }
logger.debug("Retrieving sticker pack {}.", Hex.toStringCondensed(packId.serialize())); logger.debug("Retrieving sticker pack {}.", Hex.toStringCondensed(packId.serialize()));
try { try {
final var manifest = context.getMessageReceiver().retrieveStickerManifest(packId.serialize(), packKey); final var manifest = context.getDependencies()
.getMessageReceiver()
.retrieveStickerManifest(packId.serialize(), packKey);
final var stickerIds = new HashSet<Integer>(); final var stickerIds = new HashSet<Integer>();
if (manifest.getCover().isPresent()) { if (manifest.getCover().isPresent()) {
@ -43,7 +45,9 @@ public class RetrieveStickerPackJob implements Job {
} }
for (var id : stickerIds) { for (var id : stickerIds) {
final var inputStream = context.getMessageReceiver().retrieveSticker(packId.serialize(), packKey, id); final var inputStream = context.getDependencies()
.getMessageReceiver()
.retrieveSticker(packId.serialize(), packKey, id);
context.getStickerPackStore().storeSticker(packId, id, o -> IOUtils.copyStream(inputStream, o)); context.getStickerPackStore().storeSticker(packId, id, o -> IOUtils.copyStream(inputStream, o));
} }