Support for expanded domain fronting strategies

// FREEBIE
master
Moxie Marlinspike 2016-12-29 20:54:05 -08:00
parent 7488525641
commit ae40715526
8 changed files with 106 additions and 91 deletions

View File

@ -76,7 +76,7 @@ dependencies {
compile 'org.whispersystems:jobmanager:1.0.2'
compile 'org.whispersystems:libpastelog:1.0.7'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'org.whispersystems:signal-service-android:2.4.3'
compile 'org.whispersystems:signal-service-android:2.4.4'
compile 'com.h6ah4i.android.compat:mulsellistprefcompat:1.0.0'
compile 'com.google.zxing:core:3.2.1'
@ -134,7 +134,7 @@ dependencyVerification {
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
'org.whispersystems:libpastelog:bb331d9a98240fc139101128ba836c1edec3c40e000597cdbb29ebf4cbf34d88',
'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
'org.whispersystems:signal-service-android:59e4cec73b9160b7d7c073841318098d46f25c618561d457baf4e10775a6e7b1',
'org.whispersystems:signal-service-android:27f3f686d9d9f855360307b4b641e666246e7b617020e271df66cb4bdcc26f2a',
'com.h6ah4i.android.compat:mulsellistprefcompat:47167c5cb796de1a854788e9ff318358e36c8fb88123baaa6e38fb78511dfabe',
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
@ -144,7 +144,7 @@ dependencyVerification {
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
'org.whispersystems:signal-protocol-android:1b4b9d557c8eaf861797ff683990d482d4aa8e9f23d9b17ff0cc67a02f38cb19',
'org.whispersystems:signal-service-java:9e983922084ca2c8089de0a58d7f2032e50026c2456c2bf9dfb0a56ac46a5864',
'org.whispersystems:signal-service-java:df0e83633ff4078cd276838c8942b953f670c61a5f2615ae2a89c75c19fc1bec',
'com.google.android.gms:play-services-basement:e1d29b21e02fd2a63e5a31807415cbb17a59568e27e3254181c01ffae10659bf',
'org.whispersystems:curve25519-android:bf6c34223d45d2f2813a8efcab9923caf99115115c760c9acea680bcb42d23c0',
'org.whispersystems:signal-protocol-java:a835cd0609cf116a74651bd0aa748db9392bba48c2d2af787757b8a1b50d131c',
@ -176,10 +176,7 @@ android {
vectorDrawables.useSupportLibrary = true
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
buildConfigField "String", "TEXTSECURE_URL", "\"https://textsecure-service.whispersystems.org\""
buildConfigField "String[]", "CENSORED_COUNTRIES", "{\"+20\", \"+971\", \"+53\", \"+968\"}"
buildConfigField "String", "UNCENSORED_FRONTING_HOST", "\"https://www.google.com\""
buildConfigField "String", "CENSORED_REFLECTOR", "\"signal-reflector-meek.appspot.com\""
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
buildConfigField "String", "GIPHY_PROXY_HOST", "\"giphy-proxy-production.whispersystems.org\""
buildConfigField "int", "GIPHY_PROXY_PORT", "80"
buildConfigField "String", "USER_AGENT", "\"OWA\""

View File

@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.jobs.persistence.EncryptingJobSerializer;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobManager;
@ -126,7 +127,7 @@ public class ApplicationContext extends Application implements DependencyInjecto
}
private void initializeDependencyInjection() {
this.objectGraph = ObjectGraph.create(new SignalCommunicationModule(this),
this.objectGraph = ObjectGraph.create(new SignalCommunicationModule(this, new SignalServiceNetworkAccess(this)),
new RedPhoneCommunicationModule(this),
new AxolotlStorageModule(this));
}

View File

@ -14,7 +14,7 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.push.Censorship;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -33,12 +33,14 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
private static final int STATE_PROMPT_PUSH_REGISTRATION = 4;
private static final int STATE_EXPERIENCE_UPGRADE = 5;
private BroadcastReceiver clearKeyReceiver;
private boolean isVisible;
private SignalServiceNetworkAccess networkAccess;
private BroadcastReceiver clearKeyReceiver;
private boolean isVisible;
@Override
protected final void onCreate(Bundle savedInstanceState) {
Log.w(TAG, "onCreate(" + savedInstanceState + ")");
this.networkAccess = new SignalServiceNetworkAccess(this);
onPreCreate();
final MasterSecret masterSecret = KeyCachingService.getMasterSecret(this);
routeApplicationState(masterSecret);
@ -58,8 +60,9 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
super.onResume();
KeyCachingService.registerPassphraseActivityStarted(this);
if (!Censorship.isCensored(this)) MessageRetrievalService.registerActivityStarted(this);
else ApplicationContext.getInstance(this).getJobManager().add(new PushNotificationReceiveJob(this));
if (!networkAccess.isCensored(this)) MessageRetrievalService.registerActivityStarted(this);
else ApplicationContext.getInstance(this).getJobManager().add(new PushNotificationReceiveJob(this));
isVisible = true;
}
@ -69,7 +72,8 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
super.onPause();
KeyCachingService.registerPassphraseActivityStopped(this);
if (!Censorship.isCensored(this)) MessageRetrievalService.registerActivityStopped(this);
if (!networkAccess.isCensored(this)) MessageRetrievalService.registerActivityStopped(this);
isVisible = false;
}

View File

@ -23,17 +23,14 @@ import org.thoughtcrime.securesms.jobs.PushTextSendJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.push.Censorship;
import org.thoughtcrime.securesms.push.SignalServiceTrustStore;
import org.thoughtcrime.securesms.push.CensorshipFrontingTrustStore;
import org.thoughtcrime.securesms.push.SecurityEventListener;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.internal.push.SignalServiceUrl;
@ -62,24 +59,16 @@ import dagger.Provides;
AvatarDownloadJob.class})
public class SignalCommunicationModule {
private final Context context;
private final SignalServiceUrl url;
private final TrustStore trustStore;
private final Context context;
private final SignalServiceUrl[] urls;
public SignalCommunicationModule(Context context) {
this.context = context;
if (Censorship.isCensored(context)) {
this.url = new SignalServiceUrl(BuildConfig.UNCENSORED_FRONTING_HOST, BuildConfig.CENSORED_REFLECTOR);
this.trustStore = new CensorshipFrontingTrustStore(context);
} else {
this.url = new SignalServiceUrl(BuildConfig.TEXTSECURE_URL, null);
this.trustStore = new SignalServiceTrustStore(context);
}
public SignalCommunicationModule(Context context, SignalServiceNetworkAccess networkAccess) {
this.context = context;
this.urls = networkAccess.getConfiguration(context);
}
@Provides SignalServiceAccountManager provideSignalAccountManager() {
return new SignalServiceAccountManager(this.url, this.trustStore,
return new SignalServiceAccountManager(urls,
TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getPushServerPassword(context),
BuildConfig.USER_AGENT);
@ -90,8 +79,7 @@ public class SignalCommunicationModule {
return new SignalMessageSenderFactory() {
@Override
public SignalServiceMessageSender create() {
return new SignalServiceMessageSender(SignalCommunicationModule.this.url,
SignalCommunicationModule.this.trustStore,
return new SignalServiceMessageSender(urls,
TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getPushServerPassword(context),
new SignalProtocolStoreImpl(context),
@ -102,7 +90,7 @@ public class SignalCommunicationModule {
}
@Provides SignalServiceMessageReceiver provideSignalMessageReceiver() {
return new SignalServiceMessageReceiver(this.url, this.trustStore,
return new SignalServiceMessageReceiver(urls,
new DynamicCredentialsProvider(context),
BuildConfig.USER_AGENT);
}

View File

@ -1,50 +1,24 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.internal.push.SignalServiceUrl;
public class AccountManagerFactory {
public static SignalServiceAccountManager createManager(Context context) {
return new SignalServiceAccountManager(getUrl(context), getTrustStore(context),
return new SignalServiceAccountManager(new SignalServiceNetworkAccess(context).getConfiguration(context),
TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getPushServerPassword(context),
BuildConfig.USER_AGENT);
}
public static SignalServiceAccountManager createManager(Context context, String number, String password) {
return new SignalServiceAccountManager(getUrl(number), getTrustStore(context, number),
return new SignalServiceAccountManager(new SignalServiceNetworkAccess(context).getConfiguration(number),
number, password, BuildConfig.USER_AGENT);
}
private static SignalServiceUrl getUrl(@NonNull Context context) {
return getUrl(TextSecurePreferences.getLocalNumber(context));
}
private static TrustStore getTrustStore(@NonNull Context context) {
return getTrustStore(context, TextSecurePreferences.getLocalNumber(context));
}
private static SignalServiceUrl getUrl(@NonNull String number) {
if (Censorship.isCensored(number)) {
return new SignalServiceUrl(BuildConfig.UNCENSORED_FRONTING_HOST, BuildConfig.CENSORED_REFLECTOR);
} else {
return new SignalServiceUrl(BuildConfig.TEXTSECURE_URL, null);
}
}
private static TrustStore getTrustStore(@NonNull Context context, @NonNull String number) {
if (Censorship.isCensored(number)) {
return new CensorshipFrontingTrustStore(context);
} else {
return new SignalServiceTrustStore(context);
}
}
}

View File

@ -1,26 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
public class Censorship {
public static boolean isCensored(Context context) {
String localNumber = TextSecurePreferences.getLocalNumber(context);
return isCensored(localNumber);
}
public static boolean isCensored(String localNumber) {
for (String censoredRegion : BuildConfig.CENSORED_COUNTRIES) {
if (localNumber.startsWith(censoredRegion)) {
return true;
}
}
return false;
}
}

View File

@ -8,11 +8,11 @@ import org.whispersystems.signalservice.api.push.TrustStore;
import java.io.InputStream;
public class CensorshipFrontingTrustStore implements TrustStore {
public class GoogleFrontingTrustStore implements TrustStore {
private final Context context;
public CensorshipFrontingTrustStore(Context context) {
public GoogleFrontingTrustStore(Context context) {
this.context = context.getApplicationContext();
}

View File

@ -0,0 +1,77 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.internal.push.SignalServiceUrl;
import java.util.HashMap;
import java.util.Map;
public class SignalServiceNetworkAccess {
private static final String TAG = SignalServiceNetworkAccess.class.getName();
private static final String APPSPOT_REFLECTOR_HOST = "signal-reflector-meek.appspot.com";
private final Map<String, SignalServiceUrl[]> censorshipConfiguration;
private final String[] censoredCountries;
private final SignalServiceUrl[] uncensoredConfiguration;
public SignalServiceNetworkAccess(Context context) {
final TrustStore googleTrustStore = new GoogleFrontingTrustStore(context);
final SignalServiceUrl baseGoogle = new SignalServiceUrl("https://www.google.com", APPSPOT_REFLECTOR_HOST, googleTrustStore);
final SignalServiceUrl baseAndroid = new SignalServiceUrl("https://android.clients.google.com", APPSPOT_REFLECTOR_HOST, googleTrustStore);
this.censorshipConfiguration = new HashMap<String, SignalServiceUrl[]>() {{
put("+20", new SignalServiceUrl[] {new SignalServiceUrl("https://www.google.com.eg",
APPSPOT_REFLECTOR_HOST,
googleTrustStore),
baseAndroid});
put("+971", new SignalServiceUrl[] {new SignalServiceUrl("https://www.google.ae",
APPSPOT_REFLECTOR_HOST,
googleTrustStore),
baseAndroid, baseGoogle});
put("+53", new SignalServiceUrl[] {new SignalServiceUrl("https://www.google.com.om",
APPSPOT_REFLECTOR_HOST,
googleTrustStore),
baseAndroid, baseGoogle});
put("+968", new SignalServiceUrl[] {new SignalServiceUrl("https://www.google.com.cu",
APPSPOT_REFLECTOR_HOST,
googleTrustStore),
baseAndroid, baseGoogle});
}};
this.uncensoredConfiguration = new SignalServiceUrl[] {
new SignalServiceUrl(BuildConfig.SIGNAL_URL, new SignalServiceTrustStore(context))
};
this.censoredCountries = this.censorshipConfiguration.keySet().toArray(new String[0]);
}
public SignalServiceUrl[] getConfiguration(Context context) {
String localNumber = TextSecurePreferences.getLocalNumber(context);
return getConfiguration(localNumber);
}
public SignalServiceUrl[] getConfiguration(String localNumber) {
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;
}
}