From 41b57b9207e419c48138953e75b27cb73503f290 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 1 Mar 2024 15:08:49 -0500 Subject: [PATCH] Remove unnecessary uniqueness constraint on prekey tables. --- .../securesms/database/KyberPreKeyTable.kt | 2 +- .../securesms/database/OneTimePreKeyTable.kt | 2 +- .../securesms/database/SignedPreKeyTable.kt | 2 +- .../helpers/SignalDatabaseMigrations.kt | 6 +- .../migration/V220_PreKeyConstraints.kt | 105 ++++++++++++++++++ 5 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V220_PreKeyConstraints.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/KyberPreKeyTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/KyberPreKeyTable.kt index bec3b247dc..74141ae3ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/KyberPreKeyTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/KyberPreKeyTable.kt @@ -36,7 +36,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE NOT NULL, + $KEY_ID INTEGER NOT NULL, $TIMESTAMP INTEGER NOT NULL, $LAST_RESORT INTEGER NOT NULL, $SERIALIZED BLOB NOT NULL, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/OneTimePreKeyTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/OneTimePreKeyTable.kt index 1cf59d43ec..ec3c629ed0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/OneTimePreKeyTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/OneTimePreKeyTable.kt @@ -32,7 +32,7 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE, + $KEY_ID INTEGER NOT NULL, $PUBLIC_KEY TEXT NOT NULL, $PRIVATE_KEY TEXT NOT NULL, $STALE_TIMESTAMP INTEGER NOT NULL DEFAULT 0, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SignedPreKeyTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SignedPreKeyTable.kt index 7679d26737..5fb5f7ba60 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SignedPreKeyTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SignedPreKeyTable.kt @@ -34,7 +34,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY, $ACCOUNT_ID TEXT NOT NULL, - $KEY_ID INTEGER UNIQUE, + $KEY_ID INTEGER NOT NULL, $PUBLIC_KEY TEXT NOT NULL, $PRIVATE_KEY TEXT NOT NULL, $SIGNATURE TEXT NOT NULL, 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 528ce3129a..8ecc56a239 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 @@ -77,6 +77,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V216_PhoneNumberDis import org.thoughtcrime.securesms.database.helpers.migration.V217_MessageTableExtrasColumn import org.thoughtcrime.securesms.database.helpers.migration.V218_RecipientPniSignatureVerified import org.thoughtcrime.securesms.database.helpers.migration.V219_PniPreKeyStores +import org.thoughtcrime.securesms.database.helpers.migration.V220_PreKeyConstraints /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -156,10 +157,11 @@ object SignalDatabaseMigrations { 216 to V216_PhoneNumberDiscoverable, 217 to V217_MessageTableExtrasColumn, 218 to V218_RecipientPniSignatureVerified, - 219 to V219_PniPreKeyStores + 219 to V219_PniPreKeyStores, + 220 to V220_PreKeyConstraints ) - const val DATABASE_VERSION = 219 + const val DATABASE_VERSION = 220 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V220_PreKeyConstraints.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V220_PreKeyConstraints.kt new file mode 100644 index 0000000000..04c8a764d0 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V220_PreKeyConstraints.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase +import org.signal.core.util.Stopwatch +import org.signal.core.util.logging.Log + +/** + * A while back we added an accountId to the prekey tables to support a mix of ACI and PNI identities. + * Unfortunately, we didn't remove the unique constraint on the keyId, which isn't correct: the uniqueness + * is now based on the combination of (accountId, keyId). This migration fixes that by removing the unique + * address from the keyId column itself. + */ +object V220_PreKeyConstraints : SignalDatabaseMigration { + + private val TAG = Log.tag(V220_PreKeyConstraints::class.java) + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val stopwatch = Stopwatch("migration", decimalPlaces = 2) + migrateSignedEcKeyTable(db) + stopwatch.split("signed-ec") + + migrateOneTimeEcPreKeysTable(db) + stopwatch.split("one-time-ec") + + migrateKyberTable(db) + stopwatch.split("kyber") + + stopwatch.stop(TAG) + } + + private fun migrateKyberTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE kyber_prekey_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + timestamp INTEGER NOT NULL, + last_resort INTEGER NOT NULL, + serialized BLOB NOT NULL, + stale_timestamp INTEGER NOT NULL DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO kyber_prekey_temp SELECT * FROM kyber_prekey") + + db.execSQL("DROP TABLE kyber_prekey") + db.execSQL("DROP INDEX IF EXISTS kyber_account_id_key_id") + + db.execSQL("ALTER TABLE kyber_prekey_temp RENAME TO kyber_prekey") + db.execSQL("CREATE INDEX IF NOT EXISTS kyber_account_id_key_id ON kyber_prekey (account_id, key_id, last_resort, serialized)") + } + + private fun migrateSignedEcKeyTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE signed_prekeys_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + public_key TEXT NOT NULL, + private_key TEXT NOT NULL, + signature TEXT NOT NULL, + timestamp INTEGER DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO signed_prekeys_temp SELECT * FROM signed_prekeys") + + db.execSQL("DROP TABLE signed_prekeys") + + db.execSQL("ALTER TABLE signed_prekeys_temp RENAME TO signed_prekeys") + } + + private fun migrateOneTimeEcPreKeysTable(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE one_time_prekeys_temp ( + _id INTEGER PRIMARY KEY, + account_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + public_key TEXT NOT NULL, + private_key TEXT NOT NULL, + stale_timestamp INTEGER NOT NULL DEFAULT 0, + UNIQUE(account_id, key_id) + ) + """ + ) + + db.execSQL("INSERT INTO one_time_prekeys_temp SELECT * FROM one_time_prekeys") + + db.execSQL("DROP TABLE one_time_prekeys") + + db.execSQL("ALTER TABLE one_time_prekeys_temp RENAME TO one_time_prekeys") } +}