diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/PipeConnectivityListener.java b/app/src/main/java/org/thoughtcrime/securesms/net/PipeConnectivityListener.java index dc837f300..13dacf2c2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/net/PipeConnectivityListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/net/PipeConnectivityListener.java @@ -70,6 +70,10 @@ public class PipeConnectivityListener implements ConnectivityListener { Log.w(TAG, "Encountered an error while we had a proxy set! Terminating the connection to prevent retry spam."); ApplicationDependencies.closeConnections(); return false; + } else if (TextSecurePreferences.isUnauthorizedRecieved(ApplicationDependencies.getApplication())) { + Log.w(TAG, "Encountered an error while unregistered! Terminating the connection to prevent retry spam."); + ApplicationDependencies.closeConnections(); + return false; } else { return true; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/UnregisteredBlockingInterceptor.java b/app/src/main/java/org/thoughtcrime/securesms/net/UnregisteredBlockingInterceptor.java new file mode 100644 index 000000000..586558eb1 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/net/UnregisteredBlockingInterceptor.java @@ -0,0 +1,41 @@ +package org.thoughtcrime.securesms.net; + +import androidx.annotation.NonNull; + +import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; +import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.signalservice.internal.push.PushServiceSocket; + +import java.io.IOException; + +import okhttp3.Interceptor; +import okhttp3.Protocol; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** + * Blocks network access when device is unregistered. + */ +public final class UnregisteredBlockingInterceptor implements Interceptor { + + private static final String TAG = Log.tag(UnregisteredBlockingInterceptor.class); + + @Override + public @NonNull Response intercept(@NonNull Chain chain) throws IOException { + if (TextSecurePreferences.isUnauthorizedRecieved(ApplicationDependencies.getApplication()) && + PushServiceSocket.isNotRegistrationPath(chain.request().url().encodedPath())) + { + Log.w(TAG, "Preventing request because device is unregistered."); + return new Response.Builder().request(chain.request()) + .protocol(Protocol.HTTP_1_1) + .receivedResponseAtMillis(System.currentTimeMillis()) + .message("") + .body(ResponseBody.create(null, "")) + .code(508) + .build(); + } + + return chain.proceed(chain.request()); + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java index 19c73940b..c205ef24e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java +++ b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java @@ -3,10 +3,10 @@ package org.thoughtcrime.securesms.push; import android.content.Context; -import com.annimon.stream.Stream; - import androidx.annotation.Nullable; +import com.annimon.stream.Stream; + import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.keyvalue.SignalStore; @@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor; import org.thoughtcrime.securesms.net.RemoteDeprecationDetectorInterceptor; import org.thoughtcrime.securesms.net.SequentialDns; import org.thoughtcrime.securesms.net.StandardUserAgentInterceptor; +import org.thoughtcrime.securesms.net.UnregisteredBlockingInterceptor; import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; @@ -34,8 +35,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.net.ssl.SSLContext; - import okhttp3.CipherSuite; import okhttp3.ConnectionSpec; import okhttp3.Dns; @@ -185,6 +184,7 @@ public class SignalServiceNetworkAccess { final List interceptors = Arrays.asList(new StandardUserAgentInterceptor(), new RemoteDeprecationDetectorInterceptor(), new DeprecatedClientPreventionInterceptor(), + new UnregisteredBlockingInterceptor(), DeviceTransferBlockingInterceptor.getInstance()); final Optional dns = Optional.of(DNS); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 168c718ea..4fcec7233 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -466,6 +466,12 @@ public class TextSecurePreferences { } public static void setUnauthorizedReceived(Context context, boolean value) { + if (value) { + ApplicationDependencies.closeConnections(); + } else { + ApplicationDependencies.getIncomingMessageObserver(); + } + setBooleanPreference(context, UNAUTHORIZED_RECEIVED, value); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java index 42984fef2..03d1ed970 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java @@ -121,6 +121,7 @@ import java.io.UnsupportedEncodingException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -223,8 +224,13 @@ public class PushServiceSocket { private static final String SERVER_DELIVERED_TIMESTAMP_HEADER = "X-Signal-Timestamp"; - private static final Map NO_HEADERS = Collections.emptyMap(); - private static final ResponseCodeHandler NO_HANDLER = new EmptyResponseCodeHandler(); + private static final Map NO_HEADERS = Collections.emptyMap(); + private static final ResponseCodeHandler NO_HANDLER = new EmptyResponseCodeHandler(); + private static final List REQUIRED_REGISTRATION_PATHS = Arrays.asList(CREATE_ACCOUNT_SMS_PATH, + REQUEST_PUSH_CHALLENGE, + VERIFY_ACCOUNT_CODE_PATH, + PREKEY_METADATA_PATH, + REGISTER_GCM_PATH); private static final long CDN2_RESUMABLE_LINK_LIFETIME_MILLIS = TimeUnit.DAYS.toMillis(7); @@ -2163,6 +2169,25 @@ public class PushServiceSocket { } } + public static boolean isNotRegistrationPath(String path) { + if (path == null || path.isEmpty()) { + return true; + } + + for (String registrationPath : REQUIRED_REGISTRATION_PATHS) { + String trimmedRegistrationPath = registrationPath; + int replacementIndex = registrationPath.indexOf("%s"); + if (replacementIndex >= 0) { + trimmedRegistrationPath = trimmedRegistrationPath.substring(0, replacementIndex); + } + + if (path.startsWith(trimmedRegistrationPath)) { + return false; + } + } + return true; + } + public static final class GroupHistory { private final GroupChanges groupChanges; private final Optional contentRange;