From 56725f0f5c64576dd25da3291ee357fd9fd2ba6e Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 15 Oct 2025 14:21:41 -0400 Subject: [PATCH] Fix crash with missing last_resort_key_tuple table. --- .../securesms/backup/FullBackupExporter.java | 2 ++ .../securesms/backup/FullBackupImporter.java | 3 +- .../database/LastResortKeyTupleTable.kt | 2 +- .../helpers/SignalDatabaseMigrations.kt | 6 ++-- ...stRestoreKeyTypeTableIfMissingMigration.kt | 29 +++++++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V295_AddLastRestoreKeyTypeTableIfMissingMigration.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java index 91496a3595..088148caf9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java @@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.database.EmojiSearchTable; import org.thoughtcrime.securesms.database.GroupReceiptTable; import org.thoughtcrime.securesms.database.KeyValueDatabase; import org.thoughtcrime.securesms.database.KyberPreKeyTable; +import org.thoughtcrime.securesms.database.LastResortKeyTupleTable; import org.thoughtcrime.securesms.database.MentionTable; import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.OneTimePreKeyTable; @@ -90,6 +91,7 @@ public class FullBackupExporter extends FullBackupBase { SignedPreKeyTable.TABLE_NAME, OneTimePreKeyTable.TABLE_NAME, KyberPreKeyTable.TABLE_NAME, + LastResortKeyTupleTable.TABLE_NAME, SessionTable.TABLE_NAME, SearchTable.FTS_TABLE_NAME, EmojiSearchTable.TABLE_NAME, diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java index 96b643d075..375668e4aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java @@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.database.AttachmentTable; import org.thoughtcrime.securesms.database.EmojiSearchTable; import org.thoughtcrime.securesms.database.KeyValueDatabase; import org.thoughtcrime.securesms.database.KyberPreKeyTable; +import org.thoughtcrime.securesms.database.LastResortKeyTupleTable; import org.thoughtcrime.securesms.database.OneTimePreKeyTable; import org.thoughtcrime.securesms.database.SearchTable; import org.thoughtcrime.securesms.database.SignedPreKeyTable; @@ -70,7 +71,7 @@ public class FullBackupImporter extends FullBackupBase { @SuppressWarnings("unused") private static final String TAG = Log.tag(FullBackupImporter.class); - private static final Set KEY_TABLES = SetsKt.setOf(KyberPreKeyTable.TABLE_NAME, OneTimePreKeyTable.TABLE_NAME, SignedPreKeyTable.TABLE_NAME); + private static final Set KEY_TABLES = SetsKt.setOf(KyberPreKeyTable.TABLE_NAME, LastResortKeyTupleTable.TABLE_NAME, OneTimePreKeyTable.TABLE_NAME, SignedPreKeyTable.TABLE_NAME); public static boolean validatePassphrase(@NonNull Context context, @NonNull Uri uri, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LastResortKeyTupleTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LastResortKeyTupleTable.kt index b1fae9c1c3..ca908f8396 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/LastResortKeyTupleTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/LastResortKeyTupleTable.kt @@ -23,7 +23,7 @@ class LastResortKeyTupleTable(context: Context, databaseHelper: SignalDatabase) companion object { private val TAG = Log.tag(LastResortKeyTupleTable::class) - private const val TABLE_NAME = "last_resort_key_tuple" + const val TABLE_NAME = "last_resort_key_tuple" private const val ID = "_id" private const val KYBER_PREKEY = "kyber_prekey_id" diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index cf05ead45c..5b4ce4333a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -149,6 +149,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V291_NullOutRemoteK import org.thoughtcrime.securesms.database.helpers.migration.V292_AddPollTables import org.thoughtcrime.securesms.database.helpers.migration.V293_LastResortKeyTupleTableMigration import org.thoughtcrime.securesms.database.helpers.migration.V294_RemoveLastResortKeyTupleColumnConstraintMigration +import org.thoughtcrime.securesms.database.helpers.migration.V295_AddLastRestoreKeyTypeTableIfMissingMigration import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase /** @@ -303,10 +304,11 @@ object SignalDatabaseMigrations { 291 to V291_NullOutRemoteKeyIfEmpty, 292 to V292_AddPollTables, 293 to V293_LastResortKeyTupleTableMigration, - 294 to V294_RemoveLastResortKeyTupleColumnConstraintMigration + 294 to V294_RemoveLastResortKeyTupleColumnConstraintMigration, + 295 to V295_AddLastRestoreKeyTypeTableIfMissingMigration ) - const val DATABASE_VERSION = 294 + const val DATABASE_VERSION = 295 @JvmStatic fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V295_AddLastRestoreKeyTypeTableIfMissingMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V295_AddLastRestoreKeyTypeTableIfMissingMigration.kt new file mode 100644 index 0000000000..726bb9beff --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V295_AddLastRestoreKeyTypeTableIfMissingMigration.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import org.thoughtcrime.securesms.database.SQLiteDatabase + +/** + * Creates the LastResortKeyTuple table if missed getting created on backup or device transfer import. + */ +@Suppress("ClassName") +object V295_AddLastRestoreKeyTypeTableIfMissingMigration : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL( + """ + CREATE TABLE IF NOT EXISTS last_resort_key_tuple ( + _id INTEGER PRIMARY KEY, + kyber_prekey_id INTEGER NOT NULL REFERENCES kyber_prekey (_id) ON DELETE CASCADE, + signed_key_id INTEGER NOT NULL, + public_key BLOB NOT NULL, + UNIQUE(kyber_prekey_id, signed_key_id, public_key) + ) + """.trimIndent() + ) + } +}