]> nmode's Git Repositories - signal-cli/commitdiff
Refactor ServiceConfig and add sandbox config
authorAsamK <asamk@gmx.de>
Sat, 23 Jan 2021 22:06:58 +0000 (23:06 +0100)
committerAsamK <asamk@gmx.de>
Sat, 23 Jan 2021 22:29:18 +0000 (23:29 +0100)
15 files changed:
lib/src/main/java/org/asamk/signal/manager/Manager.java
lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java
lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java
lib/src/main/java/org/asamk/signal/manager/ServiceConfig.java [deleted file]
lib/src/main/java/org/asamk/signal/manager/config/IasTrustStore.java [moved from lib/src/main/java/org/asamk/signal/manager/IasTrustStore.java with 89% similarity]
lib/src/main/java/org/asamk/signal/manager/config/KeyBackupConfig.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/LiveConfig.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/SandboxConfig.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironment.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironmentConfig.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/config/WhisperTrustStore.java [moved from lib/src/main/java/org/asamk/signal/manager/WhisperTrustStore.java with 90% similarity]
lib/src/main/resources/org/asamk/signal/manager/config/ias.store [moved from lib/src/main/resources/org/asamk/signal/manager/ias.store with 100% similarity]
lib/src/main/resources/org/asamk/signal/manager/config/whisper.store [moved from lib/src/main/resources/org/asamk/signal/manager/whisper.store with 100% similarity]
src/main/java/org/asamk/signal/App.java

index c4f32460d97692d75262be1d3cd08ba6450a5510..11ee137d9fa0be905e761d907233e46beef52a50 100644 (file)
@@ -16,6 +16,9 @@
  */
 package org.asamk.signal.manager;
 
+import org.asamk.signal.manager.config.ServiceConfig;
+import org.asamk.signal.manager.config.ServiceEnvironment;
+import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupIdV1;
 import org.asamk.signal.manager.groups.GroupIdV2;
@@ -131,7 +134,6 @@ import org.whispersystems.signalservice.api.util.SleepTimer;
 import org.whispersystems.signalservice.api.util.StreamDetails;
 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
 import org.whispersystems.signalservice.api.util.UuidUtil;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
 import org.whispersystems.signalservice.internal.contacts.crypto.Quote;
 import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException;
 import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
@@ -169,17 +171,15 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
-import static org.asamk.signal.manager.ServiceConfig.CDS_MRENCLAVE;
-import static org.asamk.signal.manager.ServiceConfig.capabilities;
-import static org.asamk.signal.manager.ServiceConfig.getIasKeyStore;
+import static org.asamk.signal.manager.config.ServiceConfig.capabilities;
 
 public class Manager implements Closeable {
 
     private final static Logger logger = LoggerFactory.getLogger(Manager.class);
 
-    private final CertificateValidator certificateValidator = new CertificateValidator(ServiceConfig.getUnidentifiedSenderTrustRoot());
+    private final CertificateValidator certificateValidator;
 
-    private final SignalServiceConfiguration serviceConfiguration;
+    private final ServiceEnvironmentConfig serviceEnvironmentConfig;
     private final String userAgent;
 
     private SignalAccount account;
@@ -202,16 +202,17 @@ public class Manager implements Closeable {
     Manager(
             SignalAccount account,
             PathConfig pathConfig,
-            SignalServiceConfiguration serviceConfiguration,
+            ServiceEnvironmentConfig serviceEnvironmentConfig,
             String userAgent
     ) {
         this.account = account;
-        this.serviceConfiguration = serviceConfiguration;
+        this.serviceEnvironmentConfig = serviceEnvironmentConfig;
+        this.certificateValidator = new CertificateValidator(serviceEnvironmentConfig.getUnidentifiedSenderTrustRoot());
         this.userAgent = userAgent;
         this.groupsV2Operations = capabilities.isGv2() ? new GroupsV2Operations(ClientZkOperations.create(
-                serviceConfiguration)) : null;
+                serviceEnvironmentConfig.getSignalServiceConfiguration())) : null;
         final SleepTimer timer = new UptimeSleepTimer();
-        this.accountManager = new SignalServiceAccountManager(serviceConfiguration,
+        this.accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
                 new DynamicCredentialsProvider(account.getUuid(),
                         account.getUsername(),
                         account.getPassword(),
@@ -222,11 +223,18 @@ public class Manager implements Closeable {
                 ServiceConfig.AUTOMATIC_NETWORK_RETRY,
                 timer);
         this.groupsV2Api = accountManager.getGroupsV2Api();
-        final KeyBackupService keyBackupService = ServiceConfig.createKeyBackupService(accountManager);
+        final KeyBackupService keyBackupService = accountManager.getKeyBackupService(ServiceConfig.getIasKeyStore(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
+                10);
+
         this.pinHelper = new PinHelper(keyBackupService);
-        this.clientZkProfileOperations = capabilities.isGv2() ? ClientZkOperations.create(serviceConfiguration)
-                .getProfileOperations() : null;
-        this.messageReceiver = new SignalServiceMessageReceiver(serviceConfiguration,
+        this.clientZkProfileOperations = capabilities.isGv2()
+                ? ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration())
+                .getProfileOperations()
+                : null;
+        this.messageReceiver = new SignalServiceMessageReceiver(serviceEnvironmentConfig.getSignalServiceConfiguration(),
                 account.getUuid(),
                 account.getUsername(),
                 account.getPassword(),
@@ -275,7 +283,7 @@ public class Manager implements Closeable {
     }
 
     public static Manager init(
-            String username, File settingsPath, SignalServiceConfiguration serviceConfiguration, String userAgent
+            String username, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
     ) throws IOException, NotRegisteredException {
         PathConfig pathConfig = PathConfig.createDefault(settingsPath);
 
@@ -289,7 +297,11 @@ public class Manager implements Closeable {
             throw new NotRegisteredException();
         }
 
-        return new Manager(account, pathConfig, serviceConfiguration, userAgent);
+        final ServiceEnvironmentConfig serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(
+                serviceEnvironment,
+                userAgent);
+
+        return new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent);
     }
 
     public static List<String> getAllLocalUsernames(File settingsPath) {
@@ -498,7 +510,7 @@ public class Manager implements Closeable {
 
     private SignalServiceMessageSender createMessageSender() {
         final ExecutorService executor = null;
-        return new SignalServiceMessageSender(serviceConfiguration,
+        return new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
                 account.getUuid(),
                 account.getUsername(),
                 account.getPassword(),
@@ -1262,7 +1274,9 @@ public class Manager implements Closeable {
 
     private Map<String, UUID> getRegisteredUsers(final Set<String> numbersMissingUuid) throws IOException {
         try {
-            return accountManager.getRegisteredUsers(getIasKeyStore(), numbersMissingUuid, CDS_MRENCLAVE);
+            return accountManager.getRegisteredUsers(ServiceConfig.getIasKeyStore(),
+                    numbersMissingUuid,
+                    serviceEnvironmentConfig.getCdsMrenclave());
         } catch (Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | SignatureException | UnauthenticatedResponseException | InvalidKeyException e) {
             throw new IOException(e);
         }
index 0c26cf77964ffe4ebed3a1994ed402d62ff846a8..c01ceabf2ece755e4becdd431dcacf826792d3fc 100644 (file)
@@ -16,6 +16,9 @@
  */
 package org.asamk.signal.manager;
 
+import org.asamk.signal.manager.config.ServiceConfig;
+import org.asamk.signal.manager.config.ServiceEnvironment;
+import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.signal.zkgroup.InvalidInputException;
@@ -31,7 +34,6 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.SleepTimer;
 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
 import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
 
 import java.io.File;
@@ -43,7 +45,7 @@ public class ProvisioningManager {
     private final static Logger logger = LoggerFactory.getLogger(ProvisioningManager.class);
 
     private final PathConfig pathConfig;
-    private final SignalServiceConfiguration serviceConfiguration;
+    private final ServiceEnvironmentConfig serviceEnvironmentConfig;
     private final String userAgent;
 
     private final SignalServiceAccountManager accountManager;
@@ -51,9 +53,9 @@ public class ProvisioningManager {
     private final int registrationId;
     private final String password;
 
-    public ProvisioningManager(File settingsPath, SignalServiceConfiguration serviceConfiguration, String userAgent) {
-        this.pathConfig = PathConfig.createDefault(settingsPath);
-        this.serviceConfiguration = serviceConfiguration;
+    ProvisioningManager(PathConfig pathConfig, ServiceEnvironmentConfig serviceEnvironmentConfig, String userAgent) {
+        this.pathConfig = pathConfig;
+        this.serviceEnvironmentConfig = serviceEnvironmentConfig;
         this.userAgent = userAgent;
 
         identityKey = KeyUtils.generateIdentityKeyPair();
@@ -62,11 +64,11 @@ public class ProvisioningManager {
         final SleepTimer timer = new UptimeSleepTimer();
         GroupsV2Operations groupsV2Operations;
         try {
-            groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceConfiguration));
+            groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration()));
         } catch (Throwable ignored) {
             groupsV2Operations = null;
         }
-        accountManager = new SignalServiceAccountManager(serviceConfiguration,
+        accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
                 new DynamicCredentialsProvider(null, null, password, null, SignalServiceAddress.DEFAULT_DEVICE_ID),
                 userAgent,
                 groupsV2Operations,
@@ -74,6 +76,18 @@ public class ProvisioningManager {
                 timer);
     }
 
+    public static ProvisioningManager init(
+            File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
+    ) {
+        PathConfig pathConfig = PathConfig.createDefault(settingsPath);
+
+        final ServiceEnvironmentConfig serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(
+                serviceEnvironment,
+                userAgent);
+
+        return new ProvisioningManager(pathConfig, serviceConfiguration, userAgent);
+    }
+
     public String getDeviceLinkUri() throws TimeoutException, IOException {
         String deviceUuid = accountManager.getNewDeviceUuid();
 
@@ -120,7 +134,7 @@ public class ProvisioningManager {
                 profileKey)) {
             account.save();
 
-            try (Manager m = new Manager(account, pathConfig, serviceConfiguration, userAgent)) {
+            try (Manager m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent)) {
 
                 try {
                     m.refreshPreKeys();
index 506948badde039f026bf58f94deb1445faaa2fa8..914a5fcfeb7869df5b59ec57dec145bf8743e18e 100644 (file)
@@ -16,6 +16,9 @@
  */
 package org.asamk.signal.manager;
 
+import org.asamk.signal.manager.config.ServiceConfig;
+import org.asamk.signal.manager.config.ServiceEnvironment;
+import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.helper.PinHelper;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.util.KeyUtils;
@@ -28,11 +31,12 @@ import org.whispersystems.signalservice.api.KeyBackupService;
 import org.whispersystems.signalservice.api.KeyBackupServicePinException;
 import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
 import org.whispersystems.signalservice.api.SignalServiceAccountManager;
+import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
+import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.SleepTimer;
 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
 import org.whispersystems.signalservice.api.util.UuidUtil;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
 import org.whispersystems.signalservice.internal.push.LockedException;
 import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
 import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
@@ -46,7 +50,7 @@ public class RegistrationManager implements Closeable {
 
     private SignalAccount account;
     private final PathConfig pathConfig;
-    private final SignalServiceConfiguration serviceConfiguration;
+    private final ServiceEnvironmentConfig serviceEnvironmentConfig;
     private final String userAgent;
 
     private final SignalServiceAccountManager accountManager;
@@ -55,31 +59,49 @@ public class RegistrationManager implements Closeable {
     public RegistrationManager(
             SignalAccount account,
             PathConfig pathConfig,
-            SignalServiceConfiguration serviceConfiguration,
+            ServiceEnvironmentConfig serviceEnvironmentConfig,
             String userAgent
     ) {
         this.account = account;
         this.pathConfig = pathConfig;
-        this.serviceConfiguration = serviceConfiguration;
+        this.serviceEnvironmentConfig = serviceEnvironmentConfig;
         this.userAgent = userAgent;
 
         final SleepTimer timer = new UptimeSleepTimer();
-        this.accountManager = new SignalServiceAccountManager(serviceConfiguration, new DynamicCredentialsProvider(
-                // Using empty UUID, because registering doesn't work otherwise
-                null,
-                account.getUsername(),
-                account.getPassword(),
-                account.getSignalingKey(),
-                SignalServiceAddress.DEFAULT_DEVICE_ID), userAgent, null, ServiceConfig.AUTOMATIC_NETWORK_RETRY, timer);
-        final KeyBackupService keyBackupService = ServiceConfig.createKeyBackupService(accountManager);
+        GroupsV2Operations groupsV2Operations;
+        try {
+            groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration()));
+        } catch (Throwable ignored) {
+            groupsV2Operations = null;
+        }
+        this.accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(),
+                new DynamicCredentialsProvider(
+                        // Using empty UUID, because registering doesn't work otherwise
+                        null,
+                        account.getUsername(),
+                        account.getPassword(),
+                        account.getSignalingKey(),
+                        SignalServiceAddress.DEFAULT_DEVICE_ID),
+                userAgent,
+                groupsV2Operations,
+                ServiceConfig.AUTOMATIC_NETWORK_RETRY,
+                timer);
+        final KeyBackupService keyBackupService = accountManager.getKeyBackupService(ServiceConfig.getIasKeyStore(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getEnclaveName(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getServiceId(),
+                serviceEnvironmentConfig.getKeyBackupConfig().getMrenclave(),
+                10);
         this.pinHelper = new PinHelper(keyBackupService);
     }
 
     public static RegistrationManager init(
-            String username, File settingsPath, SignalServiceConfiguration serviceConfiguration, String userAgent
+            String username, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
     ) throws IOException {
         PathConfig pathConfig = PathConfig.createDefault(settingsPath);
 
+        final ServiceEnvironmentConfig serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(
+                serviceEnvironment,
+                userAgent);
         if (!SignalAccount.userExists(pathConfig.getDataPath(), username)) {
             IdentityKeyPair identityKey = KeyUtils.generateIdentityKeyPair();
             int registrationId = KeyHelper.generateRegistrationId(false);
@@ -159,7 +181,7 @@ public class RegistrationManager implements Closeable {
                         account.getSignalProtocolStore().getIdentityKeyPair().getPublicKey(),
                         TrustLevel.TRUSTED_VERIFIED);
 
-        try (Manager m = new Manager(account, pathConfig, serviceConfiguration, userAgent)) {
+        try (Manager m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent)) {
 
             m.refreshPreKeys();
 
diff --git a/lib/src/main/java/org/asamk/signal/manager/ServiceConfig.java b/lib/src/main/java/org/asamk/signal/manager/ServiceConfig.java
deleted file mode 100644 (file)
index c68e577..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.asamk.signal.manager;
-
-import org.bouncycastle.util.encoders.Hex;
-import org.signal.zkgroup.ServerPublicParams;
-import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.libsignal.ecc.Curve;
-import org.whispersystems.libsignal.ecc.ECPublicKey;
-import org.whispersystems.libsignal.util.guava.Optional;
-import org.whispersystems.signalservice.api.KeyBackupService;
-import org.whispersystems.signalservice.api.SignalServiceAccountManager;
-import org.whispersystems.signalservice.api.account.AccountAttributes;
-import org.whispersystems.signalservice.api.push.TrustStore;
-import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl;
-import org.whispersystems.signalservice.internal.configuration.SignalContactDiscoveryUrl;
-import org.whispersystems.signalservice.internal.configuration.SignalKeyBackupServiceUrl;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceUrl;
-import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl;
-
-import java.io.IOException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.util.Base64;
-import java.util.List;
-import java.util.Map;
-
-import okhttp3.Dns;
-import okhttp3.Interceptor;
-
-public class ServiceConfig {
-
-    final static byte[] UNIDENTIFIED_SENDER_TRUST_ROOT = Base64.getDecoder()
-            .decode("BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF");
-    final static int PREKEY_MINIMUM_COUNT = 20;
-    final static int PREKEY_BATCH_SIZE = 100;
-    final static int MAX_ATTACHMENT_SIZE = 150 * 1024 * 1024;
-    final static long MAX_ENVELOPE_SIZE = 0;
-    final static long AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE = 10 * 1024 * 1024;
-    final static boolean AUTOMATIC_NETWORK_RETRY = true;
-
-    final static String CDS_MRENCLAVE = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15";
-
-    final static String KEY_BACKUP_ENCLAVE_NAME = "fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe";
-    final static byte[] KEY_BACKUP_SERVICE_ID = Hex.decode(
-            "fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe");
-    final static String KEY_BACKUP_MRENCLAVE = "a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87";
-
-    private final static String URL = "https://textsecure-service.whispersystems.org";
-    private final static String CDN_URL = "https://cdn.signal.org";
-    private final static String CDN2_URL = "https://cdn2.signal.org";
-    private final static String SIGNAL_CONTACT_DISCOVERY_URL = "https://api.directory.signal.org";
-    private final static String SIGNAL_KEY_BACKUP_URL = "https://api.backup.signal.org";
-    private final static String STORAGE_URL = "https://storage.signal.org";
-    private final static TrustStore TRUST_STORE = new WhisperTrustStore();
-    private final static TrustStore IAS_TRUST_STORE = new IasTrustStore();
-
-    private final static Optional<Dns> dns = Optional.absent();
-
-    private final static byte[] zkGroupServerPublicParams = Base64.getDecoder()
-            .decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=");
-
-    static final AccountAttributes.Capabilities capabilities;
-
-    static {
-        boolean zkGroupAvailable;
-        try {
-            new ServerPublicParams(zkGroupServerPublicParams);
-            zkGroupAvailable = true;
-        } catch (Throwable ignored) {
-            zkGroupAvailable = false;
-        }
-        capabilities = new AccountAttributes.Capabilities(false, zkGroupAvailable, false, zkGroupAvailable);
-    }
-
-    public static SignalServiceConfiguration createDefaultServiceConfiguration(String userAgent) {
-        final Interceptor userAgentInterceptor = chain -> chain.proceed(chain.request()
-                .newBuilder()
-                .header("User-Agent", userAgent)
-                .build());
-
-        final List<Interceptor> interceptors = List.of(userAgentInterceptor);
-
-        return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)},
-                makeSignalCdnUrlMapFor(new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)},
-                        new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}),
-                new SignalContactDiscoveryUrl[]{new SignalContactDiscoveryUrl(SIGNAL_CONTACT_DISCOVERY_URL,
-                        TRUST_STORE)},
-                new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)},
-                new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)},
-                interceptors,
-                dns,
-                zkGroupServerPublicParams);
-    }
-
-    public static AccountAttributes.Capabilities getCapabilities() {
-        return capabilities;
-    }
-
-    static KeyStore getIasKeyStore() {
-        try {
-            TrustStore contactTrustStore = IAS_TRUST_STORE;
-
-            KeyStore keyStore = KeyStore.getInstance("BKS");
-            keyStore.load(contactTrustStore.getKeyStoreInputStream(),
-                    contactTrustStore.getKeyStorePassword().toCharArray());
-
-            return keyStore;
-        } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    static KeyBackupService createKeyBackupService(SignalServiceAccountManager accountManager) {
-        KeyStore keyStore = ServiceConfig.getIasKeyStore();
-
-        return accountManager.getKeyBackupService(keyStore,
-                ServiceConfig.KEY_BACKUP_ENCLAVE_NAME,
-                ServiceConfig.KEY_BACKUP_SERVICE_ID,
-                ServiceConfig.KEY_BACKUP_MRENCLAVE,
-                10);
-    }
-
-    static ECPublicKey getUnidentifiedSenderTrustRoot() {
-        try {
-            return Curve.decodePoint(UNIDENTIFIED_SENDER_TRUST_ROOT, 0);
-        } catch (InvalidKeyException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    private static Map<Integer, SignalCdnUrl[]> makeSignalCdnUrlMapFor(
-            SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls
-    ) {
-        return Map.of(0, cdn0Urls, 2, cdn2Urls);
-    }
-
-    private ServiceConfig() {
-    }
-}
similarity index 89%
rename from lib/src/main/java/org/asamk/signal/manager/IasTrustStore.java
rename to lib/src/main/java/org/asamk/signal/manager/config/IasTrustStore.java
index f9bbb0b38f44e46e1366ae5943eedf04d9e96c0b..4d70809b088756cad0880799e9d9924bc562d9e5 100644 (file)
@@ -1,4 +1,4 @@
-package org.asamk.signal.manager;
+package org.asamk.signal.manager.config;
 
 import org.whispersystems.signalservice.api.push.TrustStore;
 
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/KeyBackupConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/KeyBackupConfig.java
new file mode 100644 (file)
index 0000000..60173c1
--- /dev/null
@@ -0,0 +1,26 @@
+package org.asamk.signal.manager.config;
+
+public class KeyBackupConfig {
+
+    private final String enclaveName;
+    private final byte[] serviceId;
+    private final String mrenclave;
+
+    public KeyBackupConfig(final String enclaveName, final byte[] serviceId, final String mrenclave) {
+        this.enclaveName = enclaveName;
+        this.serviceId = serviceId;
+        this.mrenclave = mrenclave;
+    }
+
+    public String getEnclaveName() {
+        return enclaveName;
+    }
+
+    public byte[] getServiceId() {
+        return serviceId;
+    }
+
+    public String getMrenclave() {
+        return mrenclave;
+    }
+}
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/LiveConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/LiveConfig.java
new file mode 100644 (file)
index 0000000..80df8bb
--- /dev/null
@@ -0,0 +1,82 @@
+package org.asamk.signal.manager.config;
+
+import org.bouncycastle.util.encoders.Hex;
+import org.whispersystems.libsignal.InvalidKeyException;
+import org.whispersystems.libsignal.ecc.Curve;
+import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.libsignal.util.guava.Optional;
+import org.whispersystems.signalservice.api.push.TrustStore;
+import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalContactDiscoveryUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalKeyBackupServiceUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
+import org.whispersystems.signalservice.internal.configuration.SignalServiceUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl;
+
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+import okhttp3.Dns;
+import okhttp3.Interceptor;
+
+class LiveConfig {
+
+    private final static byte[] UNIDENTIFIED_SENDER_TRUST_ROOT = Base64.getDecoder()
+            .decode("BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF");
+    private final static String CDS_MRENCLAVE = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15";
+
+    private final static String KEY_BACKUP_ENCLAVE_NAME = "fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe";
+    private final static byte[] KEY_BACKUP_SERVICE_ID = Hex.decode(
+            "fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe");
+    private final static String KEY_BACKUP_MRENCLAVE = "a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87";
+
+    private final static String URL = "https://textsecure-service.whispersystems.org";
+    private final static String CDN_URL = "https://cdn.signal.org";
+    private final static String CDN2_URL = "https://cdn2.signal.org";
+    private final static String SIGNAL_CONTACT_DISCOVERY_URL = "https://api.directory.signal.org";
+    private final static String SIGNAL_KEY_BACKUP_URL = "https://api.backup.signal.org";
+    private final static String STORAGE_URL = "https://storage.signal.org";
+    private final static TrustStore TRUST_STORE = new WhisperTrustStore();
+
+    private final static Optional<Dns> dns = Optional.absent();
+
+    private final static byte[] zkGroupServerPublicParams = Base64.getDecoder()
+            .decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=");
+
+    static SignalServiceConfiguration createDefaultServiceConfiguration(
+            final List<Interceptor> interceptors
+    ) {
+        return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)},
+                Map.of(0,
+                        new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)},
+                        2,
+                        new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}),
+                new SignalContactDiscoveryUrl[]{new SignalContactDiscoveryUrl(SIGNAL_CONTACT_DISCOVERY_URL,
+                        TRUST_STORE)},
+                new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)},
+                new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)},
+                interceptors,
+                dns,
+                zkGroupServerPublicParams);
+    }
+
+    static ECPublicKey getUnidentifiedSenderTrustRoot() {
+        try {
+            return Curve.decodePoint(UNIDENTIFIED_SENDER_TRUST_ROOT, 0);
+        } catch (InvalidKeyException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    static KeyBackupConfig createKeyBackupConfig() {
+        return new KeyBackupConfig(KEY_BACKUP_ENCLAVE_NAME, KEY_BACKUP_SERVICE_ID, KEY_BACKUP_MRENCLAVE);
+    }
+
+    static String getCdsMrenclave() {
+        return CDS_MRENCLAVE;
+    }
+
+    private LiveConfig() {
+    }
+}
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/SandboxConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/SandboxConfig.java
new file mode 100644 (file)
index 0000000..edb180a
--- /dev/null
@@ -0,0 +1,82 @@
+package org.asamk.signal.manager.config;
+
+import org.bouncycastle.util.encoders.Hex;
+import org.whispersystems.libsignal.InvalidKeyException;
+import org.whispersystems.libsignal.ecc.Curve;
+import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.libsignal.util.guava.Optional;
+import org.whispersystems.signalservice.api.push.TrustStore;
+import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalContactDiscoveryUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalKeyBackupServiceUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
+import org.whispersystems.signalservice.internal.configuration.SignalServiceUrl;
+import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl;
+
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+import okhttp3.Dns;
+import okhttp3.Interceptor;
+
+class SandboxConfig {
+
+    private final static byte[] UNIDENTIFIED_SENDER_TRUST_ROOT = Base64.getDecoder()
+            .decode("BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx");
+    private final static String CDS_MRENCLAVE = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15";
+
+    private final static String KEY_BACKUP_ENCLAVE_NAME = "823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9";
+    private final static byte[] KEY_BACKUP_SERVICE_ID = Hex.decode(
+            "038c40bbbacdc873caa81ac793bb75afde6dfe436a99ab1f15e3f0cbb7434ced");
+    private final static String KEY_BACKUP_MRENCLAVE = "a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87";
+
+    private final static String URL = "https://textsecure-service-staging.whispersystems.org";
+    private final static String CDN_URL = "https://cdn-staging.signal.org";
+    private final static String CDN2_URL = "https://cdn2-staging.signal.org";
+    private final static String SIGNAL_CONTACT_DISCOVERY_URL = "https://api-staging.directory.signal.org";
+    private final static String SIGNAL_KEY_BACKUP_URL = "https://api-staging.backup.signal.org";
+    private final static String STORAGE_URL = "https://storage-staging.signal.org";
+    private final static TrustStore TRUST_STORE = new WhisperTrustStore();
+
+    private final static Optional<Dns> dns = Optional.absent();
+
+    private final static byte[] zkGroupServerPublicParams = Base64.getDecoder()
+            .decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdls=");
+
+    static SignalServiceConfiguration createDefaultServiceConfiguration(
+            final List<Interceptor> interceptors
+    ) {
+        return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)},
+                Map.of(0,
+                        new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)},
+                        2,
+                        new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}),
+                new SignalContactDiscoveryUrl[]{new SignalContactDiscoveryUrl(SIGNAL_CONTACT_DISCOVERY_URL,
+                        TRUST_STORE)},
+                new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)},
+                new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)},
+                interceptors,
+                dns,
+                zkGroupServerPublicParams);
+    }
+
+    static ECPublicKey getUnidentifiedSenderTrustRoot() {
+        try {
+            return Curve.decodePoint(UNIDENTIFIED_SENDER_TRUST_ROOT, 0);
+        } catch (InvalidKeyException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    static KeyBackupConfig createKeyBackupConfig() {
+        return new KeyBackupConfig(KEY_BACKUP_ENCLAVE_NAME, KEY_BACKUP_SERVICE_ID, KEY_BACKUP_MRENCLAVE);
+    }
+
+    static String getCdsMrenclave() {
+        return CDS_MRENCLAVE;
+    }
+
+    private SandboxConfig() {
+    }
+}
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java
new file mode 100644 (file)
index 0000000..7a54edd
--- /dev/null
@@ -0,0 +1,85 @@
+package org.asamk.signal.manager.config;
+
+import org.signal.zkgroup.internal.Native;
+import org.whispersystems.signalservice.api.account.AccountAttributes;
+import org.whispersystems.signalservice.api.push.TrustStore;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.List;
+
+import okhttp3.Interceptor;
+
+public class ServiceConfig {
+
+    public final static int PREKEY_MINIMUM_COUNT = 20;
+    public final static int PREKEY_BATCH_SIZE = 100;
+    public final static int MAX_ATTACHMENT_SIZE = 150 * 1024 * 1024;
+    public final static long MAX_ENVELOPE_SIZE = 0;
+    public final static long AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE = 10 * 1024 * 1024;
+    public final static boolean AUTOMATIC_NETWORK_RETRY = true;
+
+    private final static KeyStore iasKeyStore;
+
+    public static final AccountAttributes.Capabilities capabilities;
+
+    static {
+        boolean zkGroupAvailable;
+        try {
+            Native.serverPublicParamsCheckValidContentsJNI(new byte[]{});
+            zkGroupAvailable = true;
+        } catch (Throwable ignored) {
+            zkGroupAvailable = false;
+        }
+        capabilities = new AccountAttributes.Capabilities(false, zkGroupAvailable, false, zkGroupAvailable);
+
+        try {
+            TrustStore contactTrustStore = new IasTrustStore();
+
+            KeyStore keyStore = KeyStore.getInstance("BKS");
+            keyStore.load(contactTrustStore.getKeyStoreInputStream(),
+                    contactTrustStore.getKeyStorePassword().toCharArray());
+
+            iasKeyStore = keyStore;
+        } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static AccountAttributes.Capabilities getCapabilities() {
+        return capabilities;
+    }
+
+    public static KeyStore getIasKeyStore() {
+        return iasKeyStore;
+    }
+
+    public static ServiceEnvironmentConfig getServiceEnvironmentConfig(
+            ServiceEnvironment serviceEnvironment, String userAgent
+    ) {
+        final Interceptor userAgentInterceptor = chain -> chain.proceed(chain.request()
+                .newBuilder()
+                .header("User-Agent", userAgent)
+                .build());
+
+        final List<Interceptor> interceptors = List.of(userAgentInterceptor);
+
+        switch (serviceEnvironment) {
+            case LIVE:
+                return new ServiceEnvironmentConfig(LiveConfig.createDefaultServiceConfiguration(interceptors),
+                        LiveConfig.getUnidentifiedSenderTrustRoot(),
+                        LiveConfig.createKeyBackupConfig(),
+                        LiveConfig.getCdsMrenclave());
+            case SANDBOX:
+                return new ServiceEnvironmentConfig(SandboxConfig.createDefaultServiceConfiguration(interceptors),
+                        SandboxConfig.getUnidentifiedSenderTrustRoot(),
+                        SandboxConfig.createKeyBackupConfig(),
+                        SandboxConfig.getCdsMrenclave());
+            default:
+                throw new IllegalArgumentException("Unsupported environment");
+        }
+    }
+}
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironment.java b/lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironment.java
new file mode 100644 (file)
index 0000000..142a2dd
--- /dev/null
@@ -0,0 +1,6 @@
+package org.asamk.signal.manager.config;
+
+public enum ServiceEnvironment {
+    LIVE,
+    SANDBOX,
+}
diff --git a/lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironmentConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/ServiceEnvironmentConfig.java
new file mode 100644 (file)
index 0000000..e64472a
--- /dev/null
@@ -0,0 +1,43 @@
+package org.asamk.signal.manager.config;
+
+import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
+
+public class ServiceEnvironmentConfig {
+
+    private final SignalServiceConfiguration signalServiceConfiguration;
+
+    private final ECPublicKey unidentifiedSenderTrustRoot;
+
+    private final KeyBackupConfig keyBackupConfig;
+
+    private final String cdsMrenclave;
+
+    public ServiceEnvironmentConfig(
+            final SignalServiceConfiguration signalServiceConfiguration,
+            final ECPublicKey unidentifiedSenderTrustRoot,
+            final KeyBackupConfig keyBackupConfig,
+            final String cdsMrenclave
+    ) {
+        this.signalServiceConfiguration = signalServiceConfiguration;
+        this.unidentifiedSenderTrustRoot = unidentifiedSenderTrustRoot;
+        this.keyBackupConfig = keyBackupConfig;
+        this.cdsMrenclave = cdsMrenclave;
+    }
+
+    public SignalServiceConfiguration getSignalServiceConfiguration() {
+        return signalServiceConfiguration;
+    }
+
+    public ECPublicKey getUnidentifiedSenderTrustRoot() {
+        return unidentifiedSenderTrustRoot;
+    }
+
+    public KeyBackupConfig getKeyBackupConfig() {
+        return keyBackupConfig;
+    }
+
+    public String getCdsMrenclave() {
+        return cdsMrenclave;
+    }
+}
similarity index 90%
rename from lib/src/main/java/org/asamk/signal/manager/WhisperTrustStore.java
rename to lib/src/main/java/org/asamk/signal/manager/config/WhisperTrustStore.java
index 185ab599ec3cf1293cda63db1e0e54231a7c7764..7add1d794c20c556fd2c2c4e93635401005d4e03 100644 (file)
@@ -1,4 +1,4 @@
-package org.asamk.signal.manager;
+package org.asamk.signal.manager.config;
 
 import org.whispersystems.signalservice.api.push.TrustStore;
 
index 6dc3d799c2a9c52c9a75ffd998fcfeab5f23745f..e35285c3da624a4a9e4f8169b0ca370540848141 100644 (file)
@@ -21,14 +21,14 @@ import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.NotRegisteredException;
 import org.asamk.signal.manager.ProvisioningManager;
 import org.asamk.signal.manager.RegistrationManager;
-import org.asamk.signal.manager.ServiceConfig;
+import org.asamk.signal.manager.config.ServiceConfig;
+import org.asamk.signal.manager.config.ServiceEnvironment;
 import org.asamk.signal.util.IOUtils;
 import org.freedesktop.dbus.connections.impl.DBusConnection;
 import org.freedesktop.dbus.exceptions.DBusException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
-import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
 
 import java.io.File;
 import java.io.IOException;
@@ -114,8 +114,7 @@ public class App {
             dataPath = getDefaultDataPath();
         }
 
-        final SignalServiceConfiguration serviceConfiguration = ServiceConfig.createDefaultServiceConfiguration(
-                BaseConfig.USER_AGENT);
+        final ServiceEnvironment serviceEnvironment = ServiceEnvironment.LIVE;
 
         if (!ServiceConfig.getCapabilities().isGv2()) {
             logger.warn("WARNING: Support for new group V2 is disabled,"
@@ -128,7 +127,7 @@ public class App {
                 return 1;
             }
 
-            return handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceConfiguration);
+            return handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceEnvironment);
         }
 
         if (username == null) {
@@ -139,7 +138,7 @@ public class App {
             }
 
             if (command instanceof MultiLocalCommand) {
-                return handleMultiLocalCommand((MultiLocalCommand) command, dataPath, serviceConfiguration, usernames);
+                return handleMultiLocalCommand((MultiLocalCommand) command, dataPath, serviceEnvironment, usernames);
             }
 
             if (usernames.size() > 1) {
@@ -154,7 +153,7 @@ public class App {
         }
 
         if (command instanceof RegistrationCommand) {
-            return handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceConfiguration);
+            return handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceEnvironment);
         }
 
         if (!(command instanceof LocalCommand)) {
@@ -162,15 +161,13 @@ public class App {
             return 1;
         }
 
-        return handleLocalCommand((LocalCommand) command, username, dataPath, serviceConfiguration);
+        return handleLocalCommand((LocalCommand) command, username, dataPath, serviceEnvironment);
     }
 
     private int handleProvisioningCommand(
-            final ProvisioningCommand command,
-            final File dataPath,
-            final SignalServiceConfiguration serviceConfiguration
+            final ProvisioningCommand command, final File dataPath, final ServiceEnvironment serviceEnvironment
     ) {
-        ProvisioningManager pm = new ProvisioningManager(dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
+        ProvisioningManager pm = ProvisioningManager.init(dataPath, serviceEnvironment, BaseConfig.USER_AGENT);
         return command.handleCommand(ns, pm);
     }
 
@@ -178,11 +175,11 @@ public class App {
             final RegistrationCommand command,
             final String username,
             final File dataPath,
-            final SignalServiceConfiguration serviceConfiguration
+            final ServiceEnvironment serviceEnvironment
     ) {
         final RegistrationManager manager;
         try {
-            manager = RegistrationManager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
+            manager = RegistrationManager.init(username, dataPath, serviceEnvironment, BaseConfig.USER_AGENT);
         } catch (Throwable e) {
             logger.error("Error loading or creating state file: {}", e.getMessage());
             return 2;
@@ -199,9 +196,9 @@ public class App {
             final LocalCommand command,
             final String username,
             final File dataPath,
-            final SignalServiceConfiguration serviceConfiguration
+            final ServiceEnvironment serviceEnvironment
     ) {
-        try (Manager m = loadManager(username, dataPath, serviceConfiguration)) {
+        try (Manager m = loadManager(username, dataPath, serviceEnvironment)) {
             if (m == null) {
                 return 2;
             }
@@ -216,11 +213,11 @@ public class App {
     private int handleMultiLocalCommand(
             final MultiLocalCommand command,
             final File dataPath,
-            final SignalServiceConfiguration serviceConfiguration,
+            final ServiceEnvironment serviceEnvironment,
             final List<String> usernames
     ) {
         final List<Manager> managers = usernames.stream()
-                .map(u -> loadManager(u, dataPath, serviceConfiguration))
+                .map(u -> loadManager(u, dataPath, serviceEnvironment))
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
 
@@ -237,11 +234,11 @@ public class App {
     }
 
     private Manager loadManager(
-            final String username, final File dataPath, final SignalServiceConfiguration serviceConfiguration
+            final String username, final File dataPath, final ServiceEnvironment serviceEnvironment
     ) {
         Manager manager;
         try {
-            manager = Manager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
+            manager = Manager.init(username, dataPath, serviceEnvironment, BaseConfig.USER_AGENT);
         } catch (NotRegisteredException e) {
             logger.error("User " + username + " is not registered.");
             return null;