From 680d436038dbae6bcf30fd1358261ad92814daa3 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 4 Nov 2025 13:59:19 -0500 Subject: [PATCH] Fix handling non-existent SVR enclaves. --- app/build.gradle.kts | 2 -- .../securesms/pin/PinRestoreViewModel.kt | 4 ++++ .../securesms/pin/SvrRepository.kt | 15 ++++++++++----- .../api/svr/SecureValueRecovery.kt | 3 +++ .../api/svr/SecureValueRecoveryV2.kt | 18 +++++++++++++++--- .../signalservice/api/svr/Svr2Socket.kt | 8 +++++++- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e967f35e44..b46bb12f39 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -215,7 +215,6 @@ android { buildConfigField("String[]", "SIGNAL_CDSI_IPS", rootProject.extra["cdsi_ips"] as String) buildConfigField("String[]", "SIGNAL_SVR2_IPS", rootProject.extra["svr2_ips"] as String) buildConfigField("String", "SIGNAL_AGENT", "\"OWA\"") - buildConfigField("String", "SVR2_MRENCLAVE_LEGACY_LEGACY", "\"9314436a9a144992bb3680770ea5fd7934a7ffd29257844a33763a238903d570\"") buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"093be9ea32405e85ae28dbb48eb668aebeb7dbe29517b9b86ad4bec4dfe0e6a6\"") buildConfigField("String", "SVR2_MRENCLAVE", "\"29cd63c87bea751e3bfd0fbd401279192e2e5c99948b4ee9437eafc4968355fb\"") buildConfigField("String[]", "UNIDENTIFIED_SENDER_TRUST_ROOTS", "new String[]{ \"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\", \"BUkY0I+9+oPgDCn4+Ac6Iu813yvqkDr/ga8DzLxFxuk6\"}") @@ -402,7 +401,6 @@ android { buildConfigField("String", "SIGNAL_CDN3_URL", "\"https://cdn3-staging.signal.org\"") buildConfigField("String", "SIGNAL_CDSI_URL", "\"https://cdsi.staging.signal.org\"") buildConfigField("String", "SIGNAL_SVR2_URL", "\"https://svr2.staging.signal.org\"") - buildConfigField("String", "SVR2_MRENCLAVE_LEGACY_LEGACY", "\"38e01eff4fe357dc0b0e8ef7a44b4abc5489fbccba3a78780f3872c277f62bf3\"") buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"2e8cefe6e3f389d8426adb24e9b7fb7adf10902c96f06f7bbcee36277711ed91\"") buildConfigField("String", "SVR2_MRENCLAVE", "\"a75542d82da9f6914a1e31f8a7407053b99cc99a0e7291d8fbd394253e19b036\"") buildConfigField("String[]", "UNIDENTIFIED_SENDER_TRUST_ROOTS", "new String[]{\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\", \"BYhU6tPjqP46KGZEzRs1OL4U39V5dlPJ/X09ha4rErkm\"}") diff --git a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt index 61cc492de7..3c771f3e62 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/PinRestoreViewModel.kt @@ -68,6 +68,10 @@ class PinRestoreViewModel : ViewModel() { is SecureValueRecovery.RestoreResponse.ApplicationError -> { event.postValue(Event.NETWORK_ERROR) } + + SecureValueRecovery.RestoreResponse.EnclaveNotFound -> { + event.postValue(Event.PIN_LOCKED) + } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/pin/SvrRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/pin/SvrRepository.kt index fbed448b5b..b38c10f4e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/SvrRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/SvrRepository.kt @@ -44,7 +44,6 @@ object SvrRepository { val TAG = Log.tag(SvrRepository::class.java) - private val svr2LegacyLegacy: SecureValueRecovery = AppDependencies.signalServiceAccountManager.getSecureValueRecoveryV2(BuildConfig.SVR2_MRENCLAVE_LEGACY_LEGACY) private val svr2Legacy: SecureValueRecovery = AppDependencies.signalServiceAccountManager.getSecureValueRecoveryV2(BuildConfig.SVR2_MRENCLAVE_LEGACY) private val svr2: SecureValueRecovery = AppDependencies.signalServiceAccountManager.getSecureValueRecoveryV2(BuildConfig.SVR2_MRENCLAVE) private val svr3: SecureValueRecovery = AppDependencies.signalServiceAccountManager.getSecureValueRecoveryV3(AppDependencies.libsignalNetwork) @@ -53,7 +52,7 @@ object SvrRepository { private val readImplementations: List = if (Svr3Migration.shouldReadFromSvr3) { listOf(svr3, svr2) } else { - listOf(svr2, svr2Legacy, svr2LegacyLegacy) + listOf(svr2, svr2Legacy) } /** An ordered list of SVR implementations to write to. They should be in priority order, with the most important one listed first. */ @@ -66,7 +65,6 @@ object SvrRepository { if (Svr3Migration.shouldWriteToSvr2) { implementations += svr2 implementations += svr2Legacy - implementations += svr2LegacyLegacy } return implementations } @@ -104,8 +102,7 @@ object SvrRepository { } else { listOf( svr2 to { restoreMasterKeyPreRegistrationFromV2(svr2, credentials.svr2, userPin) }, - svr2Legacy to { restoreMasterKeyPreRegistrationFromV2(svr2Legacy, credentials.svr2, userPin) }, - svr2LegacyLegacy to { restoreMasterKeyPreRegistrationFromV2(svr2LegacyLegacy, credentials.svr2, userPin) } + svr2Legacy to { restoreMasterKeyPreRegistrationFromV2(svr2Legacy, credentials.svr2, userPin) } ) } @@ -140,6 +137,10 @@ object SvrRepository { RestoreResponse.Missing -> { Log.w(TAG, "[restoreMasterKeyPreRegistration] No data found for $implementation | Continuing to next implementation.", true) } + + RestoreResponse.EnclaveNotFound -> { + Log.w(TAG, "[restoreMasterKeyPreRegistration] Enclave no longer exists: $implementation | Continuing to next implementation.", true) + } } } @@ -218,6 +219,10 @@ object SvrRepository { RestoreResponse.Missing -> { Log.w(TAG, "[restoreMasterKeyPostRegistration] No data found for: $implementation | Continuing to next implementation.", true) } + + RestoreResponse.EnclaveNotFound -> { + Log.w(TAG, "[restoreMasterKeyPostRegistration] Enclave no longer exists: $implementation | Continuing to next implementation.", true) + } } } diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecovery.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecovery.kt index 2386cc2191..ee08ae77ff 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecovery.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecovery.kt @@ -103,6 +103,9 @@ interface SecureValueRecovery { /** The PIN was incorrect. Includes the number of attempts the user has remaining. */ data class PinMismatch(val triesRemaining: Int) : RestoreResponse() + /** The enclave no longer exists */ + data object EnclaveNotFound : RestoreResponse() + /** There as a network error. Not a bad response, but rather interference or some other inability to make a network request. */ data class NetworkError(val exception: IOException) : RestoreResponse() diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecoveryV2.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecoveryV2.kt index c8c85400d3..428710e074 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecoveryV2.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/SecureValueRecoveryV2.kt @@ -83,7 +83,11 @@ class SecureValueRecoveryV2( DeleteResponse.Success } catch (e: NonSuccessfulResponseCodeException) { Log.w(TAG, "[Delete] Failed with a non-successful response code exception!", e) - DeleteResponse.ApplicationError(e) + if (e.code == 404) { + DeleteResponse.EnclaveNotFound + } else { + DeleteResponse.ApplicationError(e) + } } catch (e: IOException) { Log.w(TAG, "[Delete] Failed with a network exception!", e) DeleteResponse.NetworkError(e) @@ -149,7 +153,11 @@ class SecureValueRecoveryV2( } } catch (e: NonSuccessfulResponseCodeException) { Log.w(TAG, "[Restore] Failed with a non-successful response code exception!", e) - RestoreResponse.ApplicationError(e) + if (e.code == 404) { + RestoreResponse.EnclaveNotFound + } else { + RestoreResponse.ApplicationError(e) + } } catch (e: IOException) { Log.w(TAG, "[Restore] Failed with a network exception!", e) RestoreResponse.NetworkError(e) @@ -212,7 +220,11 @@ class SecureValueRecoveryV2( } } catch (e: NonSuccessfulResponseCodeException) { Log.w(TAG, "[Set] Failed with a non-successful response code exception!", e) - BackupResponse.ApplicationError(e) + if (e.code == 404) { + BackupResponse.EnclaveNotFound + } else { + BackupResponse.ApplicationError(e) + } } catch (e: IOException) { Log.w(TAG, "[Set] Failed with a network exception!", e) BackupResponse.NetworkError(e) diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/Svr2Socket.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/Svr2Socket.kt index ce36148d2e..cae94e7747 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/Svr2Socket.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/svr/Svr2Socket.kt @@ -149,7 +149,13 @@ internal class Svr2Socket( } override fun onFailure(webSocket: WebSocket, t: Throwable, response: OkHttpResponse?) { - if (emitError(IOException(t))) { + val exception = if (t.message?.contains("404") == true) { + NonSuccessfulResponseCodeException(404) + } else { + IOException(t) + } + + if (emitError(exception)) { Log.w(TAG, "[onFailure] response? " + (response != null), t) stage.set(Stage.FAILED) webSocket.close(1000, "OK")