mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
clean up: signal service protocols
This commit is contained in:
parent
88bbc0b677
commit
1db9ccdf27
@ -81,7 +81,6 @@ import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
|||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
|
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
|
||||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
|
||||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.service.LocalBackupListener;
|
import org.thoughtcrime.securesms.service.LocalBackupListener;
|
||||||
|
@ -2,11 +2,8 @@ package org.thoughtcrime.securesms.dependencies;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.util.guava.Optional;
|
|
||||||
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
|
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
|
||||||
import org.session.libsignal.service.api.SignalServiceMessageSender;
|
import org.session.libsignal.service.api.SignalServiceMessageSender;
|
||||||
import org.session.libsignal.service.api.util.CredentialsProvider;
|
|
||||||
import org.session.libsignal.service.api.websocket.ConnectivityListener;
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
@ -24,15 +21,12 @@ import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
|
||||||
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
|
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
|
||||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.util.RealtimeSleepTimer;
|
|
||||||
import org.session.libsession.utilities.TextSecurePreferences;
|
import org.session.libsession.utilities.TextSecurePreferences;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import network.loki.messenger.BuildConfig;
|
|
||||||
|
|
||||||
@Module(complete = false, injects = {PushGroupSendJob.class,
|
@Module(complete = false, injects = {PushGroupSendJob.class,
|
||||||
PushTextSendJob.class,
|
PushTextSendJob.class,
|
||||||
@ -52,8 +46,6 @@ import network.loki.messenger.BuildConfig;
|
|||||||
|
|
||||||
public class SignalCommunicationModule {
|
public class SignalCommunicationModule {
|
||||||
|
|
||||||
private static final String TAG = SignalCommunicationModule.class.getSimpleName();
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
private SignalServiceMessageSender messageSender;
|
private SignalServiceMessageSender messageSender;
|
||||||
@ -66,8 +58,7 @@ public class SignalCommunicationModule {
|
|||||||
@Provides
|
@Provides
|
||||||
public synchronized SignalServiceMessageSender provideSignalMessageSender() {
|
public synchronized SignalServiceMessageSender provideSignalMessageSender() {
|
||||||
if (this.messageSender == null) {
|
if (this.messageSender == null) {
|
||||||
this.messageSender = new SignalServiceMessageSender(new DynamicCredentialsProvider(context),
|
this.messageSender = new SignalServiceMessageSender(new SignalProtocolStoreImpl(context),
|
||||||
new SignalProtocolStoreImpl(context),
|
|
||||||
TextSecurePreferences.getLocalNumber(context),
|
TextSecurePreferences.getLocalNumber(context),
|
||||||
DatabaseFactory.getLokiAPIDatabase(context),
|
DatabaseFactory.getLokiAPIDatabase(context),
|
||||||
DatabaseFactory.getLokiThreadDatabase(context),
|
DatabaseFactory.getLokiThreadDatabase(context),
|
||||||
@ -89,54 +80,4 @@ public class SignalCommunicationModule {
|
|||||||
|
|
||||||
return this.messageReceiver;
|
return this.messageReceiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DynamicCredentialsProvider implements CredentialsProvider {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
private DynamicCredentialsProvider(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUser() {
|
|
||||||
return TextSecurePreferences.getLocalNumber(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return TextSecurePreferences.getPushServerPassword(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSignalingKey() {
|
|
||||||
return TextSecurePreferences.getSignalingKey(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PipeConnectivityListener implements ConnectivityListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnected() {
|
|
||||||
Log.i(TAG, "onConnected()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnecting() {
|
|
||||||
Log.i(TAG, "onConnecting()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisconnected() {
|
|
||||||
Log.w(TAG, "onDisconnected()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationFailure() {
|
|
||||||
Log.w(TAG, "onAuthenticationFailure()");
|
|
||||||
TextSecurePreferences.setUnauthorizedReceived(context, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
|||||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.session.libsignal.service.api.util.InvalidNumberException;
|
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -137,7 +136,6 @@ public class GroupManager {
|
|||||||
@Nullable Bitmap avatar,
|
@Nullable Bitmap avatar,
|
||||||
@Nullable String name,
|
@Nullable String name,
|
||||||
@NonNull Set<Recipient> admins)
|
@NonNull Set<Recipient> admins)
|
||||||
throws InvalidNumberException
|
|
||||||
{
|
{
|
||||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
final Set<Address> memberAddresses = getMemberAddresses(members);
|
final Set<Address> memberAddresses = getMemberAddresses(members);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class DomainFrontingTrustStore implements TrustStore {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public DomainFrontingTrustStore(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getKeyStoreInputStream() {
|
|
||||||
return context.getResources().openRawResource(R.raw.censorship_fronting);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getKeyStorePassword() {
|
|
||||||
return "whisper";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class IasTrustStore implements TrustStore {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public IasTrustStore(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getKeyStoreInputStream() {
|
|
||||||
return context.getResources().openRawResource(R.raw.ias);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getKeyStorePassword() {
|
|
||||||
return "whisper";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
|
||||||
import org.session.libsignal.service.api.SignalServiceMessageSender;
|
|
||||||
import org.session.libsignal.service.api.push.SignalServiceAddress;
|
|
||||||
|
|
||||||
public class MessageSenderEventListener implements SignalServiceMessageSender.EventListener {
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public MessageSenderEventListener(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSecurityEvent(SignalServiceAddress textSecureAddress) {
|
|
||||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,171 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.session.libsession.utilities.TextSecurePreferences;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
import org.session.libsignal.service.internal.configuration.SignalCdnUrl;
|
|
||||||
import org.session.libsignal.service.internal.configuration.SignalContactDiscoveryUrl;
|
|
||||||
import org.session.libsignal.service.internal.configuration.SignalServiceConfiguration;
|
|
||||||
import org.session.libsignal.service.internal.configuration.SignalServiceUrl;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import network.loki.messenger.BuildConfig;
|
|
||||||
import okhttp3.CipherSuite;
|
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
import okhttp3.TlsVersion;
|
|
||||||
|
|
||||||
public class SignalServiceNetworkAccess {
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String TAG = SignalServiceNetworkAccess.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final String COUNTRY_CODE_EGYPT = "+20";
|
|
||||||
private static final String COUNTRY_CODE_UAE = "+971";
|
|
||||||
private static final String COUNTRY_CODE_OMAN = "+968";
|
|
||||||
private static final String COUNTRY_CODE_QATAR = "+974";
|
|
||||||
|
|
||||||
private static final String SERVICE_REFLECTOR_HOST = "europe-west1-signal-cdn-reflector.cloudfunctions.net";
|
|
||||||
|
|
||||||
private static final ConnectionSpec GMAPS_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.tlsVersions(TlsVersion.TLS_1_2)
|
|
||||||
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
|
|
||||||
.supportsTlsExtensions(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private static final ConnectionSpec GMAIL_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.tlsVersions(TlsVersion.TLS_1_2)
|
|
||||||
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
|
|
||||||
.supportsTlsExtensions(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private static final ConnectionSpec PLAY_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.tlsVersions(TlsVersion.TLS_1_2)
|
|
||||||
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
|
|
||||||
.supportsTlsExtensions(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
private final Map<String, SignalServiceConfiguration> censorshipConfiguration;
|
|
||||||
private final String[] censoredCountries;
|
|
||||||
private final SignalServiceConfiguration uncensoredConfiguration;
|
|
||||||
|
|
||||||
public SignalServiceNetworkAccess(Context context) {
|
|
||||||
|
|
||||||
final TrustStore trustStore = new DomainFrontingTrustStore(context);
|
|
||||||
final SignalServiceUrl baseGoogleService = new SignalServiceUrl("https://www.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl baseAndroidService = new SignalServiceUrl("https://android.clients.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl mapsOneAndroidService = new SignalServiceUrl("https://clients3.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl mapsTwoAndroidService = new SignalServiceUrl("https://clients4.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl mailAndroidService = new SignalServiceUrl("https://inbox.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl egyptGoogleService = new SignalServiceUrl("https://www.google.com.eg/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl uaeGoogleService = new SignalServiceUrl("https://www.google.com.ae/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl omanGoogleService = new SignalServiceUrl("https://www.google.com.om/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalServiceUrl qatarGoogleService = new SignalServiceUrl("https://www.google.com.qa/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
|
|
||||||
final SignalCdnUrl baseGoogleCdn = new SignalCdnUrl("https://www.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl baseAndroidCdn = new SignalCdnUrl("https://android.clients.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl mapsOneAndroidCdn = new SignalCdnUrl("https://clients3.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl mapsTwoAndroidCdn = new SignalCdnUrl("https://clients4.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl mailAndroidCdn = new SignalCdnUrl("https://inbox.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl egyptGoogleCdn = new SignalCdnUrl("https://www.google.com.eg/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl uaeGoogleCdn = new SignalCdnUrl("https://www.google.com.ae/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl omanGoogleCdn = new SignalCdnUrl("https://www.google.com.om/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalCdnUrl qatarGoogleCdn = new SignalCdnUrl("https://www.google.com.qa/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
|
|
||||||
final SignalContactDiscoveryUrl baseGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl baseAndroidDiscovery = new SignalContactDiscoveryUrl("https://android.clients.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl mapsOneAndroidDiscovery = new SignalContactDiscoveryUrl("https://clients3.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl mapsTwoAndroidDiscovery = new SignalContactDiscoveryUrl("https://clients4.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl mailAndroidDiscovery = new SignalContactDiscoveryUrl("https://inbox.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl egyptGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.eg/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl uaeGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.ae/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl omanGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.om/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
final SignalContactDiscoveryUrl qatarGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.qa/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
|
|
||||||
|
|
||||||
|
|
||||||
this.censorshipConfiguration = new HashMap<String, SignalServiceConfiguration>() {{
|
|
||||||
put(COUNTRY_CODE_EGYPT, new SignalServiceConfiguration(new SignalServiceUrl[] {egyptGoogleService, baseGoogleService, baseAndroidService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
|
|
||||||
new SignalCdnUrl[] {egyptGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn, mailAndroidCdn},
|
|
||||||
new SignalContactDiscoveryUrl[] {egyptGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
|
|
||||||
|
|
||||||
put(COUNTRY_CODE_UAE, new SignalServiceConfiguration(new SignalServiceUrl[] {uaeGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
|
|
||||||
new SignalCdnUrl[] {uaeGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
|
|
||||||
new SignalContactDiscoveryUrl[] {uaeGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
|
|
||||||
|
|
||||||
put(COUNTRY_CODE_OMAN, new SignalServiceConfiguration(new SignalServiceUrl[] {omanGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
|
|
||||||
new SignalCdnUrl[] {omanGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
|
|
||||||
new SignalContactDiscoveryUrl[] {omanGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
|
|
||||||
|
|
||||||
|
|
||||||
put(COUNTRY_CODE_QATAR, new SignalServiceConfiguration(new SignalServiceUrl[] {qatarGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
|
|
||||||
new SignalCdnUrl[] {qatarGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
|
|
||||||
new SignalContactDiscoveryUrl[] {qatarGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
|
|
||||||
}};
|
|
||||||
|
|
||||||
this.uncensoredConfiguration = new SignalServiceConfiguration(new SignalServiceUrl[] {new SignalServiceUrl(BuildConfig.SIGNAL_URL, new SignalServiceTrustStore(context))},
|
|
||||||
new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, new SignalServiceTrustStore(context))},
|
|
||||||
new SignalContactDiscoveryUrl[] {new SignalContactDiscoveryUrl(BuildConfig.SIGNAL_CONTACT_DISCOVERY_URL, new SignalServiceTrustStore(context))});
|
|
||||||
|
|
||||||
this.censoredCountries = this.censorshipConfiguration.keySet().toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalServiceConfiguration getConfiguration(Context context) {
|
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
return getConfiguration(localNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalServiceConfiguration getConfiguration(@Nullable String localNumber) {
|
|
||||||
if (localNumber == null) return this.uncensoredConfiguration;
|
|
||||||
|
|
||||||
for (String censoredRegion : this.censoredCountries) {
|
|
||||||
if (localNumber.startsWith(censoredRegion)) {
|
|
||||||
return this.censorshipConfiguration.get(censoredRegion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.uncensoredConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCensored(Context context) {
|
|
||||||
return getConfiguration(context) != this.uncensoredConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCensored(String number) {
|
|
||||||
return getConfiguration(number) != this.uncensoredConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.push;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import network.loki.messenger.R;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class SignalServiceTrustStore implements TrustStore {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public SignalServiceTrustStore(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getKeyStoreInputStream() {
|
|
||||||
return context.getResources().openRawResource(R.raw.whisper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getKeyStorePassword() {
|
|
||||||
return "whisper";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.util;
|
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.util.SleepTimer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sleep timer that is based on elapsed realtime, so
|
|
||||||
* that it works properly, even in low-power sleep modes.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class RealtimeSleepTimer implements SleepTimer {
|
|
||||||
private static final String TAG = RealtimeSleepTimer.class.getSimpleName();
|
|
||||||
|
|
||||||
private final AlarmReceiver alarmReceiver;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public RealtimeSleepTimer(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
alarmReceiver = new RealtimeSleepTimer.AlarmReceiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sleep(long millis) {
|
|
||||||
context.registerReceiver(alarmReceiver,
|
|
||||||
new IntentFilter(AlarmReceiver.WAKE_UP_THREAD_ACTION));
|
|
||||||
|
|
||||||
final long startTime = System.currentTimeMillis();
|
|
||||||
alarmReceiver.setAlarm(millis);
|
|
||||||
|
|
||||||
while (System.currentTimeMillis() - startTime < millis) {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
wait(millis - System.currentTimeMillis() + startTime);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.unregisterReceiver(alarmReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AlarmReceiver extends BroadcastReceiver {
|
|
||||||
private static final String WAKE_UP_THREAD_ACTION = "org.session.libsignal.service.api.util.RealtimeSleepTimer.AlarmReceiver.WAKE_UP_THREAD";
|
|
||||||
|
|
||||||
private void setAlarm(long millis) {
|
|
||||||
final Intent intent = new Intent(WAKE_UP_THREAD_ACTION);
|
|
||||||
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
||||||
final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
|
||||||
|
|
||||||
Log.w(TAG, "Setting alarm to wake up in " + millis + "ms.");
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
} else {
|
|
||||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
Log.w(TAG, "Waking up.");
|
|
||||||
|
|
||||||
synchronized (RealtimeSleepTimer.this) {
|
|
||||||
RealtimeSleepTimer.this.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,6 @@ import org.session.libsignal.service.api.messages.shared.SharedContact;
|
|||||||
import org.session.libsignal.service.api.push.SignalServiceAddress;
|
import org.session.libsignal.service.api.push.SignalServiceAddress;
|
||||||
import org.session.libsignal.service.api.push.exceptions.PushNetworkException;
|
import org.session.libsignal.service.api.push.exceptions.PushNetworkException;
|
||||||
import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException;
|
import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException;
|
||||||
import org.session.libsignal.service.api.util.CredentialsProvider;
|
|
||||||
import org.session.libsignal.service.internal.crypto.PaddingInputStream;
|
import org.session.libsignal.service.internal.crypto.PaddingInputStream;
|
||||||
import org.session.libsignal.service.internal.push.OutgoingPushMessage;
|
import org.session.libsignal.service.internal.push.OutgoingPushMessage;
|
||||||
import org.session.libsignal.service.internal.push.OutgoingPushMessageList;
|
import org.session.libsignal.service.internal.push.OutgoingPushMessageList;
|
||||||
@ -44,7 +43,6 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos.TypingMes
|
|||||||
import org.session.libsignal.service.internal.push.http.AttachmentCipherOutputStreamFactory;
|
import org.session.libsignal.service.internal.push.http.AttachmentCipherOutputStreamFactory;
|
||||||
import org.session.libsignal.service.internal.push.http.OutputStreamFactory;
|
import org.session.libsignal.service.internal.push.http.OutputStreamFactory;
|
||||||
import org.session.libsignal.utilities.Base64;
|
import org.session.libsignal.utilities.Base64;
|
||||||
import org.session.libsignal.service.internal.util.StaticCredentialsProvider;
|
|
||||||
import org.session.libsignal.service.internal.util.Util;
|
import org.session.libsignal.service.internal.util.Util;
|
||||||
import org.session.libsignal.utilities.concurrent.SettableFuture;
|
import org.session.libsignal.utilities.concurrent.SettableFuture;
|
||||||
import org.session.libsignal.service.loki.api.LokiDotNetAPI;
|
import org.session.libsignal.service.loki.api.LokiDotNetAPI;
|
||||||
@ -75,7 +73,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
@ -91,8 +88,6 @@ public class SignalServiceMessageSender {
|
|||||||
private static final String TAG = SignalServiceMessageSender.class.getSimpleName();
|
private static final String TAG = SignalServiceMessageSender.class.getSimpleName();
|
||||||
|
|
||||||
private final IdentityKeyStore store;
|
private final IdentityKeyStore store;
|
||||||
private final SignalServiceAddress localAddress;
|
|
||||||
|
|
||||||
// Loki
|
// Loki
|
||||||
private final String userPublicKey;
|
private final String userPublicKey;
|
||||||
private final LokiAPIDatabaseProtocol apiDatabase;
|
private final LokiAPIDatabaseProtocol apiDatabase;
|
||||||
@ -103,29 +98,7 @@ public class SignalServiceMessageSender {
|
|||||||
private final LokiOpenGroupDatabaseProtocol openGroupDatabase;
|
private final LokiOpenGroupDatabaseProtocol openGroupDatabase;
|
||||||
private final Broadcaster broadcaster;
|
private final Broadcaster broadcaster;
|
||||||
|
|
||||||
/**
|
public SignalServiceMessageSender(IdentityKeyStore store,
|
||||||
* Construct a SignalServiceMessageSender.
|
|
||||||
*
|
|
||||||
* @param user The Signal Service username (eg phone number).
|
|
||||||
* @param password The Signal Service user password.
|
|
||||||
* @param store The SignalProtocolStore.
|
|
||||||
*/
|
|
||||||
public SignalServiceMessageSender(String user, String password,
|
|
||||||
IdentityKeyStore store,
|
|
||||||
String userPublicKey,
|
|
||||||
LokiAPIDatabaseProtocol apiDatabase,
|
|
||||||
LokiThreadDatabaseProtocol threadDatabase,
|
|
||||||
LokiMessageDatabaseProtocol messageDatabase,
|
|
||||||
SessionProtocol sessionProtocolImpl,
|
|
||||||
LokiUserDatabaseProtocol userDatabase,
|
|
||||||
LokiOpenGroupDatabaseProtocol openGroupDatabase,
|
|
||||||
Broadcaster broadcaster)
|
|
||||||
{
|
|
||||||
this(new StaticCredentialsProvider(user, password, null), store, userPublicKey, apiDatabase, threadDatabase, messageDatabase, sessionProtocolImpl, userDatabase, openGroupDatabase, broadcaster);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalServiceMessageSender(CredentialsProvider credentialsProvider,
|
|
||||||
IdentityKeyStore store,
|
|
||||||
String userPublicKey,
|
String userPublicKey,
|
||||||
LokiAPIDatabaseProtocol apiDatabase,
|
LokiAPIDatabaseProtocol apiDatabase,
|
||||||
LokiThreadDatabaseProtocol threadDatabase,
|
LokiThreadDatabaseProtocol threadDatabase,
|
||||||
@ -136,7 +109,6 @@ public class SignalServiceMessageSender {
|
|||||||
Broadcaster broadcaster)
|
Broadcaster broadcaster)
|
||||||
{
|
{
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.localAddress = new SignalServiceAddress(credentialsProvider.getUser());
|
|
||||||
this.userPublicKey = userPublicKey;
|
this.userPublicKey = userPublicKey;
|
||||||
this.apiDatabase = apiDatabase;
|
this.apiDatabase = apiDatabase;
|
||||||
this.threadDatabase = threadDatabase;
|
this.threadDatabase = threadDatabase;
|
||||||
@ -517,7 +489,6 @@ public class SignalServiceMessageSender {
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
List<SendMessageResult> results = new LinkedList<>();
|
List<SendMessageResult> results = new LinkedList<>();
|
||||||
SignalServiceAddress ownAddress = localAddress;
|
|
||||||
Iterator<SignalServiceAddress> recipientIterator = recipients.iterator();
|
Iterator<SignalServiceAddress> recipientIterator = recipients.iterator();
|
||||||
Iterator<Optional<UnidentifiedAccess>> unidentifiedAccessIterator = unidentifiedAccess.iterator();
|
Iterator<Optional<UnidentifiedAccess>> unidentifiedAccessIterator = unidentifiedAccess.iterator();
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.profiles;
|
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
public class SignalServiceProfile {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String identityKey;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String avatar;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String unidentifiedAccess;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private boolean unrestrictedUnidentifiedAccess;
|
|
||||||
|
|
||||||
public SignalServiceProfile() {}
|
|
||||||
|
|
||||||
public String getIdentityKey() {
|
|
||||||
return identityKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAvatar() {
|
|
||||||
return avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUnidentifiedAccess() {
|
|
||||||
return unidentifiedAccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUnrestrictedUnidentifiedAccess() {
|
|
||||||
return unrestrictedUnidentifiedAccess;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.api.push;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents a Java {@link java.security.KeyStore} and
|
|
||||||
* its associated password.
|
|
||||||
*/
|
|
||||||
public interface TrustStore {
|
|
||||||
public InputStream getKeyStoreInputStream();
|
|
||||||
public String getKeyStorePassword();
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
public interface CredentialsProvider {
|
|
||||||
public String getUser();
|
|
||||||
public String getPassword();
|
|
||||||
public String getSignalingKey();
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
public class InvalidNumberException extends Throwable {
|
|
||||||
public InvalidNumberException(String s) {
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
|
||||||
|
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Phone number formats are a pain.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PhoneNumberFormatter {
|
|
||||||
|
|
||||||
private static final String TAG = PhoneNumberFormatter.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final String COUNTRY_CODE_BR = "55";
|
|
||||||
private static final String COUNTRY_CODE_US = "1";
|
|
||||||
|
|
||||||
public static boolean isValidNumber(String e164Number, String countryCode) {
|
|
||||||
if (!PhoneNumberUtil.getInstance().isPossibleNumber(e164Number, countryCode)) {
|
|
||||||
Log.w(TAG, "Failed isPossibleNumber()");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (COUNTRY_CODE_US.equals(countryCode) && !Pattern.matches("^\\+1\\d{10}$", e164Number)) {
|
|
||||||
Log.w(TAG, "Failed US number format check");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (COUNTRY_CODE_BR.equals(countryCode) && !Pattern.matches("^\\+55\\d{2}9?\\d{8}$", e164Number)) {
|
|
||||||
Log.w(TAG, "Failed Brazil number format check");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return e164Number.matches("^\\+[0-9]{10,}") ||
|
|
||||||
e164Number.matches("^\\+685[0-9]{5}") ||
|
|
||||||
e164Number.matches("^\\+376[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+299[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+597[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+298[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+240[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+687[0-9]{6}") ||
|
|
||||||
e164Number.matches("^\\+689[0-9]{6}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String impreciseFormatNumber(String number, String localNumber)
|
|
||||||
throws InvalidNumberException
|
|
||||||
{
|
|
||||||
number = number.replaceAll("[^0-9+]", "");
|
|
||||||
|
|
||||||
if (number.charAt(0) == '+')
|
|
||||||
return number;
|
|
||||||
|
|
||||||
if (localNumber.charAt(0) == '+')
|
|
||||||
localNumber = localNumber.substring(1);
|
|
||||||
|
|
||||||
if (localNumber.length() == number.length() || number.length() > localNumber.length())
|
|
||||||
return "+" + number;
|
|
||||||
|
|
||||||
int difference = localNumber.length() - number.length();
|
|
||||||
|
|
||||||
return "+" + localNumber.substring(0, difference) + number;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String formatNumberInternational(String number) {
|
|
||||||
try {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
PhoneNumber parsedNumber = util.parse(number, null);
|
|
||||||
return util.format(parsedNumber, PhoneNumberFormat.INTERNATIONAL);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String formatNumber(String number, String localNumber)
|
|
||||||
throws InvalidNumberException
|
|
||||||
{
|
|
||||||
if (number == null) {
|
|
||||||
throw new InvalidNumberException("Null String passed as number.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (number.contains("@")) {
|
|
||||||
throw new InvalidNumberException("Possible attempt to use email address.");
|
|
||||||
}
|
|
||||||
|
|
||||||
number = number.replaceAll("[^0-9+]", "");
|
|
||||||
|
|
||||||
if (number.length() == 0) {
|
|
||||||
throw new InvalidNumberException("No valid characters found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (number.charAt(0) == '+')
|
|
||||||
// return number;
|
|
||||||
|
|
||||||
try {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
PhoneNumber localNumberObject = util.parse(localNumber, null);
|
|
||||||
|
|
||||||
String localCountryCode = util.getRegionCodeForNumber(localNumberObject);
|
|
||||||
Log.w(TAG, "Got local CC: " + localCountryCode);
|
|
||||||
|
|
||||||
PhoneNumber numberObject = util.parse(number, localCountryCode);
|
|
||||||
return util.format(numberObject, PhoneNumberFormat.E164);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return impreciseFormatNumber(number, localNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getRegionDisplayName(String regionCode) {
|
|
||||||
return (regionCode == null || regionCode.equals("ZZ") || regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY))
|
|
||||||
? "Unknown country" : new Locale("", regionCode).getDisplayCountry(Locale.getDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String formatE164(String countryCode, String number) {
|
|
||||||
try {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
int parsedCountryCode = Integer.parseInt(countryCode);
|
|
||||||
PhoneNumber parsedNumber = util.parse(number,
|
|
||||||
util.getRegionCodeForCountryCode(parsedCountryCode));
|
|
||||||
|
|
||||||
return util.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "+" +
|
|
||||||
countryCode.replaceAll("[^0-9]", "").replaceAll("^0*", "") +
|
|
||||||
number.replaceAll("[^0-9]", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getInternationalFormatFromE164(String e164number) {
|
|
||||||
try {
|
|
||||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
|
||||||
PhoneNumber parsedNumber = util.parse(e164number, null);
|
|
||||||
return util.format(parsedNumber, PhoneNumberFormat.INTERNATIONAL);
|
|
||||||
} catch (NumberParseException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return e164number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sleep timer that is based on elapsed realtime, so
|
|
||||||
* that it works properly, even in low-power sleep modes.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class RealtimeSleepTimer implements SleepTimer {
|
|
||||||
private static final String TAG = RealtimeSleepTimer.class.getSimpleName();
|
|
||||||
|
|
||||||
private final AlarmReceiver alarmReceiver;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public RealtimeSleepTimer(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
alarmReceiver = new AlarmReceiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sleep(long millis) {
|
|
||||||
context.registerReceiver(alarmReceiver,
|
|
||||||
new IntentFilter(AlarmReceiver.WAKE_UP_THREAD_ACTION));
|
|
||||||
|
|
||||||
final long startTime = System.currentTimeMillis();
|
|
||||||
alarmReceiver.setAlarm(millis);
|
|
||||||
|
|
||||||
while (System.currentTimeMillis() - startTime < millis) {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
wait(millis - System.currentTimeMillis() + startTime);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.unregisterReceiver(alarmReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AlarmReceiver extends BroadcastReceiver {
|
|
||||||
private static final String WAKE_UP_THREAD_ACTION = "org.session.libsignal.service.api.util.RealtimeSleepTimer.AlarmReceiver.WAKE_UP_THREAD";
|
|
||||||
|
|
||||||
private void setAlarm(long millis) {
|
|
||||||
final Intent intent = new Intent(WAKE_UP_THREAD_ACTION);
|
|
||||||
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
||||||
final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
|
||||||
|
|
||||||
Log.w(TAG, "Setting alarm to wake up in " + millis + "ms.");
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
} else {
|
|
||||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
||||||
SystemClock.elapsedRealtime() + millis,
|
|
||||||
pendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
Log.w(TAG, "Waking up.");
|
|
||||||
|
|
||||||
synchronized (RealtimeSleepTimer.this) {
|
|
||||||
RealtimeSleepTimer.this.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
public interface SleepTimer {
|
|
||||||
public void sleep(long millis) throws InterruptedException;
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables TLS v1.2 when creating SSLSockets.
|
|
||||||
* <p/>
|
|
||||||
* For some reason, android supports TLS v1.2 from API 16, but enables it by
|
|
||||||
* default only from API 20.
|
|
||||||
* @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
|
||||||
* @see SSLSocketFactory
|
|
||||||
*/
|
|
||||||
public class Tls12SocketFactory extends SSLSocketFactory {
|
|
||||||
private static final String[] TLS_V12_V13_ONLY = {"TLSv1.3", "TLSv1.2"};
|
|
||||||
|
|
||||||
final SSLSocketFactory delegate;
|
|
||||||
|
|
||||||
public Tls12SocketFactory(SSLSocketFactory base) {
|
|
||||||
this.delegate = base;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getDefaultCipherSuites() {
|
|
||||||
return delegate.getDefaultCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedCipherSuites() {
|
|
||||||
return delegate.getSupportedCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
|
||||||
return patch(delegate.createSocket(s, host, port, autoClose));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
|
|
||||||
return patch(delegate.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
|
|
||||||
return patch(delegate.createSocket(host, port, localHost, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
||||||
return patch(delegate.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
|
||||||
return patch(delegate.createSocket(address, port, localAddress, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Socket patch(Socket s) {
|
|
||||||
if (s instanceof SSLSocket) {
|
|
||||||
((SSLSocket) s).setEnabledProtocols(TLS_V12_V13_ONLY);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.util;
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.util.SleepTimer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simle sleep timer. Since Thread.sleep is based on uptime
|
|
||||||
* this will not work properly in low-power sleep modes, when
|
|
||||||
* the CPU is suspended and uptime does not elapse.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class UptimeSleepTimer implements SleepTimer {
|
|
||||||
@Override
|
|
||||||
public void sleep(long millis) throws InterruptedException {
|
|
||||||
Thread.sleep(millis);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package org.session.libsignal.service.api.websocket;
|
|
||||||
|
|
||||||
|
|
||||||
public interface ConnectivityListener {
|
|
||||||
void onConnected();
|
|
||||||
void onConnecting();
|
|
||||||
void onDisconnected();
|
|
||||||
void onAuthenticationFailure();
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.configuration;
|
|
||||||
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
|
|
||||||
public class SignalCdnUrl extends SignalUrl {
|
|
||||||
public SignalCdnUrl(String url, TrustStore trustStore) {
|
|
||||||
super(url, trustStore);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalCdnUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) {
|
|
||||||
super(url, hostHeader, trustStore, connectionSpec);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.configuration;
|
|
||||||
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
|
|
||||||
public class SignalContactDiscoveryUrl extends SignalUrl {
|
|
||||||
|
|
||||||
public SignalContactDiscoveryUrl(String url, TrustStore trustStore) {
|
|
||||||
super(url, trustStore);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalContactDiscoveryUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) {
|
|
||||||
super(url, hostHeader, trustStore, connectionSpec);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.configuration;
|
|
||||||
|
|
||||||
|
|
||||||
public class SignalServiceConfiguration {
|
|
||||||
|
|
||||||
private final SignalServiceUrl[] signalServiceUrls;
|
|
||||||
private final SignalCdnUrl[] signalCdnUrls;
|
|
||||||
private final SignalContactDiscoveryUrl[] signalContactDiscoveryUrls;
|
|
||||||
|
|
||||||
public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls, SignalCdnUrl[] signalCdnUrls, SignalContactDiscoveryUrl[] signalContactDiscoveryUrls) {
|
|
||||||
this.signalServiceUrls = signalServiceUrls;
|
|
||||||
this.signalCdnUrls = signalCdnUrls;
|
|
||||||
this.signalContactDiscoveryUrls = signalContactDiscoveryUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalServiceUrl[] getSignalServiceUrls() {
|
|
||||||
return signalServiceUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalCdnUrl[] getSignalCdnUrls() {
|
|
||||||
return signalCdnUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalContactDiscoveryUrl[] getSignalContactDiscoveryUrls() {
|
|
||||||
return signalContactDiscoveryUrls;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.configuration;
|
|
||||||
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
|
|
||||||
public class SignalServiceUrl extends SignalUrl {
|
|
||||||
|
|
||||||
public SignalServiceUrl(String url, TrustStore trustStore) {
|
|
||||||
super(url, trustStore);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalServiceUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) {
|
|
||||||
super(url, hostHeader, trustStore, connectionSpec);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.configuration;
|
|
||||||
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.util.guava.Optional;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
import org.session.libsignal.service.internal.util.BlacklistingTrustManager;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
|
|
||||||
import okhttp3.ConnectionSpec;
|
|
||||||
|
|
||||||
public class SignalUrl {
|
|
||||||
|
|
||||||
private final String url;
|
|
||||||
private final Optional<String> hostHeader;
|
|
||||||
private final Optional<ConnectionSpec> connectionSpec;
|
|
||||||
private TrustStore trustStore;
|
|
||||||
|
|
||||||
public SignalUrl(String url, TrustStore trustStore) {
|
|
||||||
this(url, null, trustStore, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalUrl(String url, String hostHeader,
|
|
||||||
TrustStore trustStore,
|
|
||||||
ConnectionSpec connectionSpec)
|
|
||||||
{
|
|
||||||
this.url = url;
|
|
||||||
this.hostHeader = Optional.fromNullable(hostHeader);
|
|
||||||
this.trustStore = trustStore;
|
|
||||||
this.connectionSpec = Optional.fromNullable(connectionSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Optional<String> getHostHeader() {
|
|
||||||
return hostHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrustStore getTrustStore() {
|
|
||||||
return trustStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<List<ConnectionSpec>> getConnectionSpecs() {
|
|
||||||
return connectionSpec.isPresent() ? Optional.of(Collections.singletonList(connectionSpec.get())) : Optional.<List<ConnectionSpec>>absent();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
|
|
||||||
import org.threeten.bp.Instant;
|
|
||||||
import org.threeten.bp.LocalDateTime;
|
|
||||||
import org.threeten.bp.Period;
|
|
||||||
import org.threeten.bp.ZoneId;
|
|
||||||
import org.threeten.bp.ZonedDateTime;
|
|
||||||
import org.threeten.bp.format.DateTimeFormatter;
|
|
||||||
import org.session.libsignal.libsignal.util.ByteUtil;
|
|
||||||
import org.session.libsignal.service.api.crypto.InvalidCiphertextException;
|
|
||||||
import org.session.libsignal.service.internal.contacts.entities.DiscoveryRequest;
|
|
||||||
import org.session.libsignal.service.internal.contacts.entities.DiscoveryResponse;
|
|
||||||
import org.session.libsignal.service.internal.contacts.entities.RemoteAttestationResponse;
|
|
||||||
import org.session.libsignal.utilities.Hex;
|
|
||||||
import org.session.libsignal.utilities.JsonUtil;
|
|
||||||
import org.session.libsignal.service.internal.util.Util;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import java.security.cert.CertPathValidatorException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
import javax.crypto.NoSuchPaddingException;
|
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
public class ContactDiscoveryCipher {
|
|
||||||
|
|
||||||
private static final int TAG_LENGTH_BYTES = 16;
|
|
||||||
private static final int TAG_LENGTH_BITS = TAG_LENGTH_BYTES * 8;
|
|
||||||
private static final long SIGNATURE_BODY_VERSION = 3L;
|
|
||||||
|
|
||||||
public DiscoveryRequest createDiscoveryRequest(List<String> addressBook, RemoteAttestation remoteAttestation) {
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream requestDataStream = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
for (String address : addressBook) {
|
|
||||||
requestDataStream.write(ByteUtil.longToByteArray(Long.parseLong(address)));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] requestData = requestDataStream.toByteArray();
|
|
||||||
byte[] nonce = Util.getSecretBytes(12);
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
||||||
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(remoteAttestation.getKeys().getClientKey(), "AES"), new GCMParameterSpec(TAG_LENGTH_BITS, nonce));
|
|
||||||
cipher.updateAAD(remoteAttestation.getRequestId());
|
|
||||||
|
|
||||||
byte[] cipherText = cipher.doFinal(requestData);
|
|
||||||
byte[][] parts = ByteUtil.split(cipherText, cipherText.length - TAG_LENGTH_BYTES, TAG_LENGTH_BYTES);
|
|
||||||
|
|
||||||
return new DiscoveryRequest(addressBook.size(), remoteAttestation.getRequestId(), nonce, parts[0], parts[1]);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchPaddingException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (IllegalBlockSizeException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (BadPaddingException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getDiscoveryResponseData(DiscoveryResponse response, RemoteAttestation remoteAttestation) throws InvalidCiphertextException {
|
|
||||||
return decrypt(remoteAttestation.getKeys().getServerKey(), response.getIv(), response.getData(), response.getMac());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getRequestId(RemoteAttestationKeys keys, RemoteAttestationResponse response) throws InvalidCiphertextException {
|
|
||||||
return decrypt(keys.getServerKey(), response.getIv(), response.getCiphertext(), response.getTag());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyServerQuote(Quote quote, byte[] serverPublicStatic, String mrenclave)
|
|
||||||
throws UnauthenticatedQuoteException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
byte[] theirServerPublicStatic = new byte[serverPublicStatic.length];
|
|
||||||
System.arraycopy(quote.getReportData(), 0, theirServerPublicStatic, 0, theirServerPublicStatic.length);
|
|
||||||
|
|
||||||
if (!MessageDigest.isEqual(theirServerPublicStatic, serverPublicStatic)) {
|
|
||||||
throw new UnauthenticatedQuoteException("Response quote has unauthenticated report data!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!MessageDigest.isEqual(Hex.fromStringCondensed(mrenclave), quote.getMrenclave())) {
|
|
||||||
throw new UnauthenticatedQuoteException("The response quote has the wrong mrenclave value in it: " + Hex.toStringCondensed(quote.getMrenclave()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quote.isDebugQuote()) {
|
|
||||||
throw new UnauthenticatedQuoteException("Received quote for debuggable enclave");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UnauthenticatedQuoteException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyIasSignature(KeyStore trustStore, String certificates, String signatureBody, String signature, Quote quote)
|
|
||||||
throws SignatureException
|
|
||||||
{
|
|
||||||
if (certificates == null || certificates.isEmpty()) {
|
|
||||||
throw new SignatureException("No certificates.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
SigningCertificate signingCertificate = new SigningCertificate(certificates, trustStore);
|
|
||||||
signingCertificate.verifySignature(signatureBody, signature);
|
|
||||||
|
|
||||||
SignatureBodyEntity signatureBodyEntity = JsonUtil.fromJson(signatureBody, SignatureBodyEntity.class);
|
|
||||||
|
|
||||||
if (signatureBodyEntity.getVersion() != SIGNATURE_BODY_VERSION) {
|
|
||||||
throw new SignatureException("Unexpected signed quote version " + signatureBodyEntity.getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!MessageDigest.isEqual(ByteUtil.trim(signatureBodyEntity.getIsvEnclaveQuoteBody(), 432), ByteUtil.trim(quote.getQuoteBytes(), 432))) {
|
|
||||||
throw new SignatureException("Signed quote is not the same as RA quote: " + Hex.toStringCondensed(signatureBodyEntity.getIsvEnclaveQuoteBody()) + " vs " + Hex.toStringCondensed(quote.getQuoteBytes()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"OK".equals(signatureBodyEntity.getIsvEnclaveQuoteStatus())) {
|
|
||||||
throw new SignatureException("Quote status is: " + signatureBodyEntity.getIsvEnclaveQuoteStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Instant.from(ZonedDateTime.of(LocalDateTime.from(DateTimeFormatter.ofPattern("yyy-MM-dd'T'HH:mm:ss.SSSSSS").parse(signatureBodyEntity.getTimestamp())), ZoneId.of("UTC")))
|
|
||||||
.plus(Period.ofDays(1))
|
|
||||||
.isBefore(Instant.now()))
|
|
||||||
{
|
|
||||||
throw new SignatureException("Signature is expired");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
throw new SignatureException(e);
|
|
||||||
} catch (CertPathValidatorException e) {
|
|
||||||
throw new SignatureException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new SignatureException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] decrypt(byte[] key, byte[] iv, byte[] ciphertext, byte[] tag) throws InvalidCiphertextException {
|
|
||||||
try {
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
|
|
||||||
|
|
||||||
return cipher.doFinal(ByteUtil.combine(ciphertext, tag));
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchPaddingException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch(InvalidAlgorithmParameterException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (IllegalBlockSizeException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new InvalidCiphertextException(e);
|
|
||||||
} catch (BadPaddingException e) {
|
|
||||||
throw new InvalidCiphertextException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
|
|
||||||
public class Quote {
|
|
||||||
|
|
||||||
private static final long SGX_FLAGS_INITTED = 0x0000000000000001L;
|
|
||||||
private static final long SGX_FLAGS_DEBUG = 0x0000000000000002L;
|
|
||||||
private static final long SGX_FLAGS_MODE64BIT = 0x0000000000000004L;
|
|
||||||
private static final long SGX_FLAGS_PROVISION_KEY = 0x0000000000000004L;
|
|
||||||
private static final long SGX_FLAGS_EINITTOKEN_KEY = 0x0000000000000004L;
|
|
||||||
private static final long SGX_FLAGS_RESERVED = 0xFFFFFFFFFFFFFFC8L;
|
|
||||||
private static final long SGX_XFRM_LEGACY = 0x0000000000000003L;
|
|
||||||
private static final long SGX_XFRM_AVX = 0x0000000000000006L;
|
|
||||||
private static final long SGX_XFRM_RESERVED = 0xFFFFFFFFFFFFFFF8L;
|
|
||||||
|
|
||||||
private final int version;
|
|
||||||
private final boolean isSigLinkable;
|
|
||||||
private final long gid;
|
|
||||||
private final int qeSvn;
|
|
||||||
private final int pceSvn;
|
|
||||||
private final byte[] basename = new byte[32];
|
|
||||||
private final byte[] cpuSvn = new byte[16];
|
|
||||||
private final long flags;
|
|
||||||
private final long xfrm;
|
|
||||||
private final byte[] mrenclave = new byte[32];
|
|
||||||
private final byte[] mrsigner = new byte[32];
|
|
||||||
private final int isvProdId;
|
|
||||||
private final int isvSvn;
|
|
||||||
private final byte[] reportData = new byte[64];
|
|
||||||
private final byte[] signature;
|
|
||||||
private final byte[] quoteBytes;
|
|
||||||
|
|
||||||
public Quote(byte[] quoteBytes) throws InvalidQuoteFormatException {
|
|
||||||
this.quoteBytes = quoteBytes;
|
|
||||||
|
|
||||||
ByteBuffer quoteBuf = ByteBuffer.wrap(quoteBytes);
|
|
||||||
quoteBuf.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
this.version = quoteBuf.getShort(0) & 0xFFFF;
|
|
||||||
if (!(version >= 1 && version <= 2)) {
|
|
||||||
throw new InvalidQuoteFormatException("unknown_quote_version "+version);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sign_type = quoteBuf.getShort(2) & 0xFFFF;
|
|
||||||
if ((sign_type & ~1) != 0) {
|
|
||||||
throw new InvalidQuoteFormatException("unknown_quote_sign_type "+sign_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isSigLinkable = sign_type == 1;
|
|
||||||
this.gid = quoteBuf.getInt(4) & 0xFFFFFFFF;
|
|
||||||
this.qeSvn = quoteBuf.getShort(8) & 0xFFFF;
|
|
||||||
|
|
||||||
if (version > 1) {
|
|
||||||
this.pceSvn = quoteBuf.getShort(10) & 0xFFFF;
|
|
||||||
} else {
|
|
||||||
readZero(quoteBuf, 10, 2);
|
|
||||||
this.pceSvn = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
readZero(quoteBuf, 12, 4); // xeid (reserved)
|
|
||||||
read(quoteBuf, 16, basename);
|
|
||||||
|
|
||||||
//
|
|
||||||
// report_body
|
|
||||||
//
|
|
||||||
|
|
||||||
read(quoteBuf, 48, cpuSvn);
|
|
||||||
readZero(quoteBuf, 64, 4); // misc_select (reserved)
|
|
||||||
readZero(quoteBuf, 68, 28); // reserved1
|
|
||||||
this.flags = quoteBuf.getLong(96);
|
|
||||||
if ((flags & SGX_FLAGS_RESERVED ) != 0 ||
|
|
||||||
(flags & SGX_FLAGS_INITTED ) == 0 ||
|
|
||||||
(flags & SGX_FLAGS_MODE64BIT) == 0) {
|
|
||||||
throw new InvalidQuoteFormatException("bad_quote_flags "+flags);
|
|
||||||
}
|
|
||||||
this.xfrm = quoteBuf.getLong(104);
|
|
||||||
if ((xfrm & SGX_XFRM_RESERVED) != 0) {
|
|
||||||
throw new InvalidQuoteFormatException("bad_quote_xfrm "+xfrm);
|
|
||||||
}
|
|
||||||
read(quoteBuf, 112, mrenclave);
|
|
||||||
readZero(quoteBuf, 144, 32); // reserved2
|
|
||||||
read(quoteBuf, 176, mrsigner);
|
|
||||||
readZero(quoteBuf, 208, 96); // reserved3
|
|
||||||
this.isvProdId = quoteBuf.getShort(304) & 0xFFFF;
|
|
||||||
this.isvSvn = quoteBuf.getShort(306) & 0xFFFF;
|
|
||||||
readZero(quoteBuf, 308, 60); // reserved4
|
|
||||||
read(quoteBuf, 368, reportData);
|
|
||||||
|
|
||||||
// quote signature
|
|
||||||
int sig_len = quoteBuf.getInt(432) & 0xFFFFFFFF;
|
|
||||||
if (sig_len != quoteBytes.length - 436) {
|
|
||||||
throw new InvalidQuoteFormatException("bad_quote_sig_len "+sig_len);
|
|
||||||
}
|
|
||||||
this.signature = new byte[sig_len];
|
|
||||||
read(quoteBuf, 436, signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getReportData() {
|
|
||||||
return reportData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void read(ByteBuffer quoteBuf, int pos, byte[] buf) {
|
|
||||||
quoteBuf.position(pos);
|
|
||||||
quoteBuf.get(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readZero(ByteBuffer quoteBuf, int pos, int count) {
|
|
||||||
byte[] zeroBuf = new byte[count];
|
|
||||||
read(quoteBuf, pos, zeroBuf);
|
|
||||||
for (int zeroBufIdx = 0; zeroBufIdx < count; zeroBufIdx++) {
|
|
||||||
if (zeroBuf[zeroBufIdx] != 0) {
|
|
||||||
throw new IllegalArgumentException("quote_reserved_mismatch "+pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getQuoteBytes() {
|
|
||||||
return quoteBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getMrenclave() {
|
|
||||||
return mrenclave;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDebugQuote() {
|
|
||||||
return (flags & SGX_FLAGS_DEBUG) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InvalidQuoteFormatException extends Exception {
|
|
||||||
public InvalidQuoteFormatException(String value) {
|
|
||||||
super(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
import org.session.libsignal.service.internal.contacts.crypto.RemoteAttestationKeys;
|
|
||||||
|
|
||||||
public class RemoteAttestation {
|
|
||||||
|
|
||||||
private final byte[] requestId;
|
|
||||||
private final RemoteAttestationKeys keys;
|
|
||||||
|
|
||||||
public RemoteAttestation(byte[] requestId, RemoteAttestationKeys keys) {
|
|
||||||
this.requestId = requestId;
|
|
||||||
this.keys = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getRequestId() {
|
|
||||||
return requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteAttestationKeys getKeys() {
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
|
|
||||||
import org.whispersystems.curve25519.Curve25519;
|
|
||||||
import org.whispersystems.curve25519.Curve25519KeyPair;
|
|
||||||
import org.session.libsignal.libsignal.kdf.HKDFv3;
|
|
||||||
import org.session.libsignal.libsignal.util.ByteUtil;
|
|
||||||
|
|
||||||
public class RemoteAttestationKeys {
|
|
||||||
|
|
||||||
private final byte[] clientKey = new byte[32];
|
|
||||||
private final byte[] serverKey = new byte[32];
|
|
||||||
|
|
||||||
public RemoteAttestationKeys(Curve25519KeyPair keyPair, byte[] serverPublicEphemeral, byte[] serverPublicStatic) {
|
|
||||||
byte[] ephemeralToEphemeral = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicEphemeral, keyPair.getPrivateKey());
|
|
||||||
byte[] ephemeralToStatic = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicStatic, keyPair.getPrivateKey());
|
|
||||||
|
|
||||||
byte[] masterSecret = ByteUtil.combine(ephemeralToEphemeral, ephemeralToStatic );
|
|
||||||
byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey(), serverPublicEphemeral, serverPublicStatic);
|
|
||||||
|
|
||||||
HKDFv3 generator = new HKDFv3();
|
|
||||||
byte[] keys = generator.deriveSecrets(masterSecret, publicKeys, null, clientKey.length + serverKey.length);
|
|
||||||
|
|
||||||
System.arraycopy(keys, 0, clientKey, 0, clientKey.length);
|
|
||||||
System.arraycopy(keys, clientKey.length, serverKey, 0, serverKey.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getClientKey() {
|
|
||||||
return clientKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getServerKey() {
|
|
||||||
return serverKey;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
public class SignatureBodyEntity {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] isvEnclaveQuoteBody;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String isvEnclaveQuoteStatus;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private Long version;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String timestamp;
|
|
||||||
|
|
||||||
public byte[] getIsvEnclaveQuoteBody() {
|
|
||||||
return isvEnclaveQuoteBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIsvEnclaveQuoteStatus() {
|
|
||||||
return isvEnclaveQuoteStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
import org.session.libsignal.utilities.Base64;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import java.security.cert.CertPath;
|
|
||||||
import java.security.cert.CertPathValidator;
|
|
||||||
import java.security.cert.CertPathValidatorException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.security.cert.PKIXParameters;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SigningCertificate {
|
|
||||||
|
|
||||||
private final CertPath path;
|
|
||||||
|
|
||||||
public SigningCertificate(String certificateChain, KeyStore trustStore)
|
|
||||||
throws CertificateException, CertPathValidatorException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
|
||||||
Collection<X509Certificate> certificatesCollection = (Collection<X509Certificate>) certificateFactory.generateCertificates(new ByteArrayInputStream(URLDecoder.decode(certificateChain).getBytes()));
|
|
||||||
List<X509Certificate> certificates = new LinkedList<X509Certificate>(certificatesCollection);
|
|
||||||
PKIXParameters pkixParameters = new PKIXParameters(trustStore);
|
|
||||||
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
|
||||||
|
|
||||||
this.path = certificateFactory.generateCertPath(certificates);
|
|
||||||
|
|
||||||
pkixParameters.setRevocationEnabled(false);
|
|
||||||
validator.validate(path, pkixParameters);
|
|
||||||
verifyDistinguishedName(path);
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifySignature(String body, String encodedSignature)
|
|
||||||
throws SignatureException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Signature signature = Signature.getInstance("SHA256withRSA");
|
|
||||||
signature.initVerify(path.getCertificates().get(0));
|
|
||||||
signature.update(body.getBytes());
|
|
||||||
if (!signature.verify(Base64.decode(encodedSignature.getBytes()))) {
|
|
||||||
throw new SignatureException("Signature verification failed.");
|
|
||||||
}
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyDistinguishedName(CertPath path) throws CertificateException {
|
|
||||||
X509Certificate leaf = (X509Certificate) path.getCertificates().get(0);
|
|
||||||
String distinguishedName = leaf.getSubjectX500Principal().getName();
|
|
||||||
|
|
||||||
if (!"CN=Intel SGX Attestation Report Signing,O=Intel Corporation,L=Santa Clara,ST=CA,C=US".equals(distinguishedName)) {
|
|
||||||
throw new CertificateException("Bad DN: " + distinguishedName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
|
|
||||||
public class UnauthenticatedQuoteException extends Exception {
|
|
||||||
public UnauthenticatedQuoteException(String s) {
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnauthenticatedQuoteException(Exception nested) {
|
|
||||||
super(nested);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package org.session.libsignal.service.internal.contacts.crypto;
|
|
||||||
|
|
||||||
|
|
||||||
public class UnauthenticatedResponseException extends Exception {
|
|
||||||
public UnauthenticatedResponseException(Exception e) {
|
|
||||||
super(e);
|
|
||||||
}
|
|
||||||
public UnauthenticatedResponseException(String s) {
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.service.internal.contacts.entities;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import org.session.libsignal.utilities.Hex;
|
|
||||||
|
|
||||||
|
|
||||||
public class DiscoveryRequest {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private int addressCount;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] requestId;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] iv;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] data;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] mac;
|
|
||||||
|
|
||||||
public DiscoveryRequest() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public DiscoveryRequest(int addressCount, byte[] requestId, byte[] iv, byte[] data, byte[] mac) {
|
|
||||||
this.addressCount = addressCount;
|
|
||||||
this.requestId = requestId;
|
|
||||||
this.iv = iv;
|
|
||||||
this.data = data;
|
|
||||||
this. mac = mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getRequestId() {
|
|
||||||
return requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getIv() {
|
|
||||||
return iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getMac() {
|
|
||||||
return mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAddressCount() {
|
|
||||||
return addressCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "{ addressCount: " + addressCount + ", ticket: " + Hex.toString(requestId) + ", iv: " + Hex.toString(iv) + ", data: " + Hex.toString(data) + ", mac: " + Hex.toString(mac) + "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.service.internal.contacts.entities;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import org.session.libsignal.utilities.Hex;
|
|
||||||
|
|
||||||
public class DiscoveryResponse {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] iv;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] data;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] mac;
|
|
||||||
|
|
||||||
public DiscoveryResponse() {}
|
|
||||||
|
|
||||||
public DiscoveryResponse(byte[] iv, byte[] data, byte[] mac) {
|
|
||||||
this.iv = iv;
|
|
||||||
this.data = data;
|
|
||||||
this.mac = mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getIv() {
|
|
||||||
return iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getMac() {
|
|
||||||
return mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "{iv: " + (iv == null ? null : Hex.toString(iv)) + ", data: " + (data == null ? null: Hex.toString(data)) + ", mac: " + (mac == null ? null : Hex.toString(mac)) + "}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.service.internal.contacts.entities;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
public class RemoteAttestationRequest {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] clientPublic;
|
|
||||||
|
|
||||||
public RemoteAttestationRequest() {}
|
|
||||||
|
|
||||||
public RemoteAttestationRequest(byte[] clientPublic) {
|
|
||||||
this.clientPublic = clientPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getClientPublic() {
|
|
||||||
return clientPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.session.libsignal.service.internal.contacts.entities;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
public class RemoteAttestationResponse {
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] serverEphemeralPublic;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] serverStaticPublic;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] quote;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] iv;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] ciphertext;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private byte[] tag;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String signature;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String certificates;
|
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String signatureBody;
|
|
||||||
|
|
||||||
public RemoteAttestationResponse(byte[] serverEphemeralPublic, byte[] serverStaticPublic,
|
|
||||||
byte[] iv, byte[] ciphertext, byte[] tag,
|
|
||||||
byte[] quote, String signature, String certificates, String signatureBody)
|
|
||||||
{
|
|
||||||
this.serverEphemeralPublic = serverEphemeralPublic;
|
|
||||||
this.serverStaticPublic = serverStaticPublic;
|
|
||||||
this.iv = iv;
|
|
||||||
this.ciphertext = ciphertext;
|
|
||||||
this.tag = tag;
|
|
||||||
this.quote = quote;
|
|
||||||
this.signature = signature;
|
|
||||||
this.certificates = certificates;
|
|
||||||
this.signatureBody = signatureBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteAttestationResponse() {}
|
|
||||||
|
|
||||||
public byte[] getServerEphemeralPublic() {
|
|
||||||
return serverEphemeralPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getServerStaticPublic() {
|
|
||||||
return serverStaticPublic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getQuote() {
|
|
||||||
return quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getIv() {
|
|
||||||
return iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getCiphertext() {
|
|
||||||
return ciphertext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getTag() {
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSignature() {
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCertificates() {
|
|
||||||
return certificates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSignatureBody() {
|
|
||||||
return signatureBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.internal.util;
|
|
||||||
|
|
||||||
import org.session.libsignal.libsignal.util.Pair;
|
|
||||||
import org.session.libsignal.service.api.push.TrustStore;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trust manager that defers to a system X509 trust manager, and
|
|
||||||
* additionally rejects certificates if they have a blacklisted
|
|
||||||
* serial.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
public class BlacklistingTrustManager implements X509TrustManager {
|
|
||||||
|
|
||||||
private static final List<Pair<String, BigInteger>> BLACKLIST = new LinkedList<Pair<String, BigInteger>>() {{
|
|
||||||
add(new Pair<String, BigInteger>("Open Whisper Systems", new BigInteger("4098")));
|
|
||||||
}};
|
|
||||||
|
|
||||||
public static TrustManager[] createFor(TrustManager[] trustManagers) {
|
|
||||||
for (TrustManager trustManager : trustManagers) {
|
|
||||||
if (trustManager instanceof X509TrustManager) {
|
|
||||||
TrustManager[] results = new BlacklistingTrustManager[1];
|
|
||||||
results[0] = new BlacklistingTrustManager((X509TrustManager)trustManager);
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new AssertionError("No X509 Trust Managers!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TrustManager[] createFor(TrustStore trustStore) {
|
|
||||||
try {
|
|
||||||
InputStream keyStoreInputStream = trustStore.getKeyStoreInputStream();
|
|
||||||
KeyStore keyStore = KeyStore.getInstance("BKS");
|
|
||||||
|
|
||||||
keyStore.load(keyStoreInputStream, trustStore.getKeyStorePassword().toCharArray());
|
|
||||||
|
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
|
|
||||||
trustManagerFactory.init(keyStore);
|
|
||||||
|
|
||||||
return BlacklistingTrustManager.createFor(trustManagerFactory.getTrustManagers());
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final X509TrustManager trustManager;
|
|
||||||
|
|
||||||
public BlacklistingTrustManager(X509TrustManager trustManager) {
|
|
||||||
this.trustManager = trustManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
|
||||||
throws CertificateException
|
|
||||||
{
|
|
||||||
trustManager.checkClientTrusted(chain, authType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
|
||||||
throws CertificateException
|
|
||||||
{
|
|
||||||
trustManager.checkServerTrusted(chain, authType);
|
|
||||||
|
|
||||||
for (X509Certificate certificate : chain) {
|
|
||||||
for (Pair<String, BigInteger> blacklistedSerial : BLACKLIST) {
|
|
||||||
if (certificate.getIssuerDN().getName().equals(blacklistedSerial.first()) &&
|
|
||||||
certificate.getSerialNumber().equals(blacklistedSerial.second()))
|
|
||||||
{
|
|
||||||
throw new CertificateException("Blacklisted Serial: " + certificate.getSerialNumber());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getAcceptedIssuers() {
|
|
||||||
return trustManager.getAcceptedIssuers();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014-2016 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* Licensed according to the LICENSE file in this repository.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.session.libsignal.service.internal.util;
|
|
||||||
|
|
||||||
import org.session.libsignal.service.api.util.CredentialsProvider;
|
|
||||||
|
|
||||||
public class StaticCredentialsProvider implements CredentialsProvider {
|
|
||||||
|
|
||||||
private final String user;
|
|
||||||
private final String password;
|
|
||||||
private final String signalingKey;
|
|
||||||
|
|
||||||
public StaticCredentialsProvider(String user, String password, String signalingKey) {
|
|
||||||
this.user = user;
|
|
||||||
this.password = password;
|
|
||||||
this.signalingKey = signalingKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSignalingKey() {
|
|
||||||
return signalingKey;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user