From 4cb5bd9edd2369c5e1b843e863cfbdf7d02beb26 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 15 Apr 2025 16:59:44 -0400 Subject: [PATCH] Fix potential bad state with change numbers. --- .../thoughtcrime/securesms/MainActivity.kt | 1 - .../securesms/jobs/JobManagerFactories.java | 2 + .../migrations/ApplicationMigrations.java | 10 ++- .../FixChangeNumberErrorMigrationJob.kt | 73 +++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/migrations/FixChangeNumberErrorMigrationJob.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index d3f762af1b..0fc193c568 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -113,7 +113,6 @@ import org.thoughtcrime.securesms.util.CachedInflater import org.thoughtcrime.securesms.util.CommunicationActions import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme import org.thoughtcrime.securesms.util.DynamicTheme -import org.thoughtcrime.securesms.util.RemoteConfig import org.thoughtcrime.securesms.util.SplashScreenUtil import org.thoughtcrime.securesms.util.viewModel import org.thoughtcrime.securesms.window.AppScaffold diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 77782eba20..da580d76ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.migrations.DuplicateE164MigrationJob; import org.thoughtcrime.securesms.migrations.E164FormattingMigrationJob; import org.thoughtcrime.securesms.migrations.EmojiDownloadMigrationJob; import org.thoughtcrime.securesms.migrations.EmojiSearchIndexCheckMigrationJob; +import org.thoughtcrime.securesms.migrations.FixChangeNumberErrorMigrationJob; import org.thoughtcrime.securesms.migrations.GooglePlayBillingPurchaseTokenMigrationJob; import org.thoughtcrime.securesms.migrations.IdentityTableCleanupMigrationJob; import org.thoughtcrime.securesms.migrations.LegacyMigrationJob; @@ -299,6 +300,7 @@ public final class JobManagerFactories { put(E164FormattingMigrationJob.KEY, new E164FormattingMigrationJob.Factory()); put(EmojiDownloadMigrationJob.KEY, new EmojiDownloadMigrationJob.Factory()); put(EmojiSearchIndexCheckMigrationJob.KEY, new EmojiSearchIndexCheckMigrationJob.Factory()); + put(FixChangeNumberErrorMigrationJob.KEY, new FixChangeNumberErrorMigrationJob.Factory()); put(GooglePlayBillingPurchaseTokenMigrationJob.KEY, new GooglePlayBillingPurchaseTokenMigrationJob.Factory()); put(IdentityTableCleanupMigrationJob.KEY, new IdentityTableCleanupMigrationJob.Factory()); put(LegacyMigrationJob.KEY, new LegacyMigrationJob.Factory()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index a199ff25d5..9e06788b71 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -176,10 +176,12 @@ public class ApplicationMigrations { static final int AVATAR_COLOR_MIGRATION_JOB = 132; static final int DUPLICATE_E164_FIX_2 = 133; static final int E164_FORMATTING = 134; - static final int CHAT_FOLDER_STORAGE_SYNC = 135; + // Need to skip 135 because of hotfix ordering issues + static final int FIX_CHANGE_NUMBER_ERROR = 136; + static final int CHAT_FOLDER_STORAGE_SYNC = 137; } - public static final int CURRENT_VERSION = 135; + public static final int CURRENT_VERSION = 137; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -814,6 +816,10 @@ public class ApplicationMigrations { jobs.put(Version.E164_FORMATTING, new E164FormattingMigrationJob()); } + if (lastSeenVersion < Version.FIX_CHANGE_NUMBER_ERROR) { + jobs.put(Version.FIX_CHANGE_NUMBER_ERROR, new FixChangeNumberErrorMigrationJob()); + } + if (lastSeenVersion < Version.CHAT_FOLDER_STORAGE_SYNC) { jobs.put(Version.CHAT_FOLDER_STORAGE_SYNC, new SyncChatFoldersMigrationJob()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/FixChangeNumberErrorMigrationJob.kt b/app/src/main/java/org/thoughtcrime/securesms/migrations/FixChangeNumberErrorMigrationJob.kt new file mode 100644 index 0000000000..15036eeaee --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/FixChangeNumberErrorMigrationJob.kt @@ -0,0 +1,73 @@ +package org.thoughtcrime.securesms.migrations + +import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberRepository +import org.thoughtcrime.securesms.jobmanager.Job +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.net.SignalNetwork +import org.whispersystems.signalservice.api.NetworkResult +import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.internal.push.WhoAmIResponse +import java.io.IOException + +/** + * There was a server error during change number where a number was changed but gave back a 409 response. + * We need devices to re-fetch their E164+PNI's, save them, and then get prekeys. + */ +internal class FixChangeNumberErrorMigrationJob( + parameters: Parameters = Parameters.Builder().build() +) : MigrationJob(parameters) { + companion object { + const val KEY = "FixChangeNumberErrorMigrationJob" + private val TAG = Log.tag(FixChangeNumberErrorMigrationJob::class) + } + + override fun getFactoryKey(): String = KEY + + override fun isUiBlocking(): Boolean = false + + override fun performMigration() { + if (!SignalStore.account.isRegistered) { + Log.i(TAG, "Not registered, skipping.") + return + } + + val pendingChangeNumberMetadata = SignalStore.misc.pendingChangeNumberMetadata + + if (pendingChangeNumberMetadata == null) { + Log.i(TAG, "No pending change number metadata, skipping.") + return + } + + if (pendingChangeNumberMetadata.previousPni != SignalStore.account.pni?.toByteString()) { + Log.i(TAG, "Pending change number operation isn't for our current PNI, skipping.") + return + } + + when (val result = SignalNetwork.account.whoAmI()) { + is NetworkResult.Success -> { + val pni = result.result.pni?.let { ServiceId.PNI.parseOrNull(it) } ?: return + + if (result.result.number != SignalStore.account.e164 || pni != SignalStore.account.pni) { + Log.w(TAG, "Detected a number or PNI mismatch! Fixing...") + ChangeNumberRepository().changeLocalNumber(result.result.number, pni) + Log.w(TAG, "Done!") + } else { + Log.i(TAG, "No number or PNI mismatch detected.") + return + } + } + is NetworkResult.ApplicationError -> throw result.throwable + is NetworkResult.NetworkError -> throw result.exception + is NetworkResult.StatusCodeError -> throw result.exception + } + } + + override fun shouldRetry(e: Exception): Boolean = e is IOException + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): FixChangeNumberErrorMigrationJob { + return FixChangeNumberErrorMigrationJob(parameters) + } + } +}