From 88fd8fb36b73af57fe1cbd46cc51b9f53fe7c9a4 Mon Sep 17 00:00:00 2001 From: andrew-signal Date: Fri, 28 Mar 2025 11:30:52 -0400 Subject: [PATCH] Add handling for AppExpiredConnection in LibSignalChatConnection:connect. Co-authored-by: Cody Henthorne --- .../main/MainActivityListHostFragment.kt | 4 +++- .../net/SignalWebSocketHealthMonitor.kt | 8 +++++++- .../preferences/EditProxyFragment.java | 1 + .../websocket/WebSocketConnectionState.java | 3 ++- .../websocket/LibSignalChatConnection.kt | 19 ++++++++++++++----- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt index c7ac7cc662..d12490af8b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt @@ -310,7 +310,9 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f when (state) { WebSocketConnectionState.CONNECTING, WebSocketConnectionState.DISCONNECTING, WebSocketConnectionState.DISCONNECTED -> proxyStatus.setImageResource(R.drawable.ic_proxy_connecting_24) WebSocketConnectionState.CONNECTED -> proxyStatus.setImageResource(R.drawable.ic_proxy_connected_24) - WebSocketConnectionState.AUTHENTICATION_FAILED, WebSocketConnectionState.FAILED -> proxyStatus.setImageResource(R.drawable.ic_proxy_failed_24) + WebSocketConnectionState.AUTHENTICATION_FAILED, + WebSocketConnectionState.REMOTE_DEPRECATED, + WebSocketConnectionState.FAILED -> proxyStatus.setImageResource(R.drawable.ic_proxy_failed_24) else -> proxyStatus.visibility = View.GONE } } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/SignalWebSocketHealthMonitor.kt b/app/src/main/java/org/thoughtcrime/securesms/net/SignalWebSocketHealthMonitor.kt index df401c798f..bb6718ad8a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/net/SignalWebSocketHealthMonitor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/net/SignalWebSocketHealthMonitor.kt @@ -9,6 +9,7 @@ import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.util.SleepTimer import org.whispersystems.signalservice.api.websocket.HealthMonitor @@ -17,7 +18,6 @@ import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState import org.whispersystems.signalservice.internal.websocket.OkHttpWebSocketConnection import java.util.concurrent.Executor import java.util.concurrent.Executors -import kotlin.concurrent.Volatile import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -80,6 +80,12 @@ class SignalWebSocketHealthMonitor( TextSecurePreferences.setUnauthorizedReceived(AppDependencies.application, true) } } + WebSocketConnectionState.REMOTE_DEPRECATED -> { + if (!SignalStore.misc.isClientDeprecated) { + Log.w(TAG, "Received remote deprecation. Client version is deprecated.", true) + SignalStore.misc.isClientDeprecated = true + } + } else -> Unit } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/EditProxyFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/EditProxyFragment.java index 67202fa138..2ba8164c87 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/EditProxyFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/EditProxyFragment.java @@ -142,6 +142,7 @@ public class EditProxyFragment extends Fragment { proxyStatus.setTextColor(getResources().getColor(R.color.signal_accent_green)); break; case AUTHENTICATION_FAILED: + case REMOTE_DEPRECATED: case FAILED: proxyStatus.setText(R.string.preferences_connection_failed); proxyStatus.setTextColor(getResources().getColor(R.color.signal_alert_primary)); diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketConnectionState.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketConnectionState.java index ea2addddf2..ce09f0f784 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketConnectionState.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketConnectionState.java @@ -10,9 +10,10 @@ public enum WebSocketConnectionState { RECONNECTING, DISCONNECTING, AUTHENTICATION_FAILED, + REMOTE_DEPRECATED, FAILED; public boolean isFailure() { - return this == AUTHENTICATION_FAILED || this == FAILED; + return this == AUTHENTICATION_FAILED || this == REMOTE_DEPRECATED || this == FAILED; } } diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/LibSignalChatConnection.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/LibSignalChatConnection.kt index 420419d85a..0f6dfa89e7 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/LibSignalChatConnection.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/LibSignalChatConnection.kt @@ -14,6 +14,7 @@ import okio.ByteString import okio.ByteString.Companion.toByteString import org.signal.core.util.logging.Log import org.signal.libsignal.internal.CompletableFuture +import org.signal.libsignal.net.AppExpiredException import org.signal.libsignal.net.AuthenticatedChatConnection import org.signal.libsignal.net.ChatConnection import org.signal.libsignal.net.ChatConnectionListener @@ -192,10 +193,17 @@ class LibSignalChatConnection( // request returns HTTP 403. // The chat service currently does not return HTTP 401 on /v1/websocket. // Thus, this currently matches the implementation in OkHttpWebSocketConnection. - if (throwable is DeviceDeregisteredException) { - state.onNext(WebSocketConnectionState.AUTHENTICATION_FAILED) - } else { - state.onNext(WebSocketConnectionState.FAILED) + when (throwable) { + is DeviceDeregisteredException -> { + state.onNext(WebSocketConnectionState.AUTHENTICATION_FAILED) + } + is AppExpiredException -> { + state.onNext(WebSocketConnectionState.REMOTE_DEPRECATED) + } + else -> { + Log.w(TAG, "Unknown connection failure reason", throwable) + state.onNext(WebSocketConnectionState.FAILED) + } } } } @@ -210,7 +218,8 @@ class LibSignalChatConnection( WebSocketConnectionState.DISCONNECTED, WebSocketConnectionState.DISCONNECTING, WebSocketConnectionState.FAILED, - WebSocketConnectionState.AUTHENTICATION_FAILED -> true + WebSocketConnectionState.AUTHENTICATION_FAILED, + WebSocketConnectionState.REMOTE_DEPRECATED -> true WebSocketConnectionState.CONNECTING, WebSocketConnectionState.CONNECTED,