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 060dc086c5..00bf93a7fb 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 @@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V205_DropPushTable import org.thoughtcrime.securesms.database.helpers.migration.V206_AddConversationCountIndex import org.thoughtcrime.securesms.database.helpers.migration.V207_AddChunkSizeColumn import org.thoughtcrime.securesms.database.helpers.migration.V209_ClearRecipientPniFromAciColumn +import org.thoughtcrime.securesms.database.helpers.migration.V210_FixPniPossibleColumns /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -72,7 +73,7 @@ object SignalDatabaseMigrations { val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass) - const val DATABASE_VERSION = 209 + const val DATABASE_VERSION = 210 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -319,6 +320,10 @@ object SignalDatabaseMigrations { if (oldVersion < 209) { V209_ClearRecipientPniFromAciColumn.migrate(context, db, oldVersion, newVersion) } + + if (oldVersion < 210) { + V210_FixPniPossibleColumns.migrate(context, db, oldVersion, newVersion) + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V210_FixPniPossibleColumns.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V210_FixPniPossibleColumns.kt new file mode 100644 index 0000000000..fc58dbb6f8 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V210_FixPniPossibleColumns.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2023 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.SqlUtil +import org.signal.core.util.logging.Log +import org.signal.core.util.requireString +import org.thoughtcrime.securesms.database.KeyValueDatabase +import org.whispersystems.signalservice.api.push.ServiceId + +/** + * We moved to a strongly typed PNI but did not update all places where a PNI may pre-exist in + * our database. This updates the other tables where our PNI may already be in use without the 'PNI:' + * prefix. + * + * This is an issue for installs that setup PNI related data prior to the strongly typed PNI system and + * then become PNP enabled. + */ +@Suppress("ClassName") +object V210_FixPniPossibleColumns : SignalDatabaseMigration { + + private val TAG = Log.tag(V210_FixPniPossibleColumns::class.java) + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val pni = getLocalPni(context) + + if (pni == null) { + Log.i(TAG, "No local PNI, nothing to migrate") + return + } + + db.execSQL("UPDATE identities SET address = 'PNI:' || address WHERE address = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE one_time_prekeys SET account_id = 'PNI:' || account_id WHERE account_id = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE kyber_prekey SET account_id = 'PNI:' || account_id WHERE account_id = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE sender_key_shared SET address = 'PNI:' || address WHERE address = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE sender_keys SET address = 'PNI:' || address WHERE address = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE sessions SET address = 'PNI:' || address WHERE address = '${pni.toStringWithoutPrefix()}'") + db.execSQL("UPDATE signed_prekeys SET account_id = 'PNI:' || account_id WHERE account_id = '${pni.toStringWithoutPrefix()}'") + } + + private fun getLocalPni(context: Application): ServiceId.PNI? { + if (KeyValueDatabase.exists(context)) { + val keyValueDatabase = KeyValueDatabase.getInstance(context).readableDatabase + keyValueDatabase.query("key_value", arrayOf("value"), "key = ?", SqlUtil.buildArgs("account.pni"), null, null, null).use { cursor -> + return if (cursor.moveToFirst()) { + ServiceId.PNI.parseOrNull(cursor.requireString("value")) + } else { + null + } + } + } else { + return null + } + } +}