Support for expanded domain fronting strategies

// FREEBIE
This commit is contained in:
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

@@ -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;
}
}