*/
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;
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;
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;
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(),
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(),
}
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);
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) {
private SignalServiceMessageSender createMessageSender() {
final ExecutorService executor = null;
- return new SignalServiceMessageSender(serviceConfiguration,
+ return new SignalServiceMessageSender(serviceEnvironmentConfig.getSignalServiceConfiguration(),
account.getUuid(),
account.getUsername(),
account.getPassword(),
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);
}
*/
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;
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;
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;
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();
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,
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();
profileKey)) {
account.save();
- try (Manager m = new Manager(account, pathConfig, serviceConfiguration, userAgent)) {
+ try (Manager m = new Manager(account, pathConfig, serviceEnvironmentConfig, userAgent)) {
try {
m.refreshPreKeys();
*/
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;
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;
private SignalAccount account;
private final PathConfig pathConfig;
- private final SignalServiceConfiguration serviceConfiguration;
+ private final ServiceEnvironmentConfig serviceEnvironmentConfig;
private final String userAgent;
private final SignalServiceAccountManager accountManager;
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);
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();
+++ /dev/null
-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() {
- }
-}
-package org.asamk.signal.manager;
+package org.asamk.signal.manager.config;
import org.whispersystems.signalservice.api.push.TrustStore;
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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() {
+ }
+}
--- /dev/null
+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() {
+ }
+}
--- /dev/null
+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");
+ }
+ }
+}
--- /dev/null
+package org.asamk.signal.manager.config;
+
+public enum ServiceEnvironment {
+ LIVE,
+ SANDBOX,
+}
--- /dev/null
+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;
+ }
+}
-package org.asamk.signal.manager;
+package org.asamk.signal.manager.config;
import org.whispersystems.signalservice.api.push.TrustStore;
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;
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,"
return 1;
}
- return handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceConfiguration);
+ return handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceEnvironment);
}
if (username == null) {
}
if (command instanceof MultiLocalCommand) {
- return handleMultiLocalCommand((MultiLocalCommand) command, dataPath, serviceConfiguration, usernames);
+ return handleMultiLocalCommand((MultiLocalCommand) command, dataPath, serviceEnvironment, usernames);
}
if (usernames.size() > 1) {
}
if (command instanceof RegistrationCommand) {
- return handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceConfiguration);
+ return handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceEnvironment);
}
if (!(command instanceof LocalCommand)) {
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);
}
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;
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;
}
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());
}
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;