Update stores to use a constant accountId for PNIs.

This commit is contained in:
Greyson Parrelli
2024-02-08 12:53:22 -05:00
committed by GitHub
parent 65b26adb3d
commit 12385b9c5a
8 changed files with 101 additions and 23 deletions

View File

@@ -233,6 +233,7 @@ class ChangeNumberRepository(
SignalStore.account().setE164(e164)
SignalStore.account().setPni(pni)
ApplicationDependencies.resetProtocolStores()
ApplicationDependencies.getGroupsV2Authorization().clear()

View File

@@ -49,13 +49,15 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
val CREATE_INDEXES = arrayOf(
"CREATE INDEX IF NOT EXISTS $INDEX_ACCOUNT_KEY ON $TABLE_NAME ($ACCOUNT_ID, $KEY_ID, $LAST_RESORT, $SERIALIZED)"
)
const val PNI_ACCOUNT_ID = "PNI"
}
fun get(serviceId: ServiceId, keyId: Int): KyberPreKey? {
return readableDatabase
.select(LAST_RESORT, SERIALIZED)
.from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId)
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId)
.run()
.readToSingleObject { cursor ->
KyberPreKey(
@@ -69,7 +71,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
return readableDatabase
.select(LAST_RESORT, SERIALIZED)
.from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ?", serviceId)
.where("$ACCOUNT_ID = ?", serviceId.toAccountId())
.run()
.readToList { cursor ->
KyberPreKey(
@@ -83,7 +85,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
return readableDatabase
.select(LAST_RESORT, SERIALIZED)
.from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ? AND $LAST_RESORT = ?", serviceId, 1)
.where("$ACCOUNT_ID = ? AND $LAST_RESORT = ?", serviceId.toAccountId(), 1)
.run()
.readToList { cursor ->
KyberPreKey(
@@ -96,7 +98,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
fun contains(serviceId: ServiceId, keyId: Int): Boolean {
return readableDatabase
.exists("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId)
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId)
.run()
}
@@ -104,7 +106,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
writableDatabase
.insertInto(TABLE_NAME)
.values(
ACCOUNT_ID to serviceId.toString(),
ACCOUNT_ID to serviceId.toAccountId(),
KEY_ID to keyId,
TIMESTAMP to record.timestamp,
SERIALIZED to record.serialize(),
@@ -116,14 +118,14 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
fun deleteIfNotLastResort(serviceId: ServiceId, keyId: Int) {
writableDatabase
.delete("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ? AND $KEY_ID = ? AND $LAST_RESORT = ?", serviceId, keyId, 0)
.where("$ACCOUNT_ID = ? AND $KEY_ID = ? AND $LAST_RESORT = ?", serviceId.toAccountId(), keyId, 0)
.run()
}
fun delete(serviceId: ServiceId, keyId: Int) {
writableDatabase
.delete("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId)
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId.toAccountId(), keyId)
.run()
}
@@ -131,7 +133,7 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
writableDatabase
.update(TABLE_NAME)
.values(STALE_TIMESTAMP to staleTime)
.where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0 AND $LAST_RESORT = 0", serviceId)
.where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0 AND $LAST_RESORT = 0", serviceId.toAccountId())
.run()
}
@@ -161,8 +163,8 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
LIMIT $minCount
)
""",
serviceId,
serviceId
serviceId.toAccountId(),
serviceId.toAccountId()
)
.run()
@@ -173,4 +175,11 @@ class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Datab
val record: KyberPreKeyRecord,
val lastResort: Boolean
)
private fun ServiceId.toAccountId(): String {
return when (this) {
is ServiceId.ACI -> this.toString()
is ServiceId.PNI -> PNI_ACCOUNT_ID
}
}
}

View File

@@ -38,10 +38,12 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat
UNIQUE($ACCOUNT_ID, $KEY_ID)
)
"""
const val PNI_ACCOUNT_ID = "PNI"
}
fun get(serviceId: ServiceId, keyId: Int): PreKeyRecord? {
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor ->
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor ->
if (cursor.moveToFirst()) {
try {
val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
@@ -60,7 +62,7 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat
fun insert(serviceId: ServiceId, keyId: Int, record: PreKeyRecord) {
val contentValues = contentValuesOf(
ACCOUNT_ID to serviceId.toString(),
ACCOUNT_ID to serviceId.toAccountId(),
KEY_ID to keyId,
PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()),
PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize())
@@ -71,14 +73,14 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat
fun delete(serviceId: ServiceId, keyId: Int) {
val database = databaseHelper.signalWritableDatabase
database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId))
database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId))
}
fun markAllStaleIfNecessary(serviceId: ServiceId, staleTime: Long) {
writableDatabase
.update(TABLE_NAME)
.values(STALE_TIMESTAMP to staleTime)
.where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0", serviceId)
.where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0", serviceId.toAccountId())
.run()
}
@@ -105,11 +107,18 @@ class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : Dat
LIMIT $minCount
)
""",
serviceId,
serviceId
serviceId.toAccountId(),
serviceId.toAccountId()
)
.run()
Log.i(TAG, "Deleted $count stale one-time EC prekeys.")
}
private fun ServiceId.toAccountId(): String {
return when (this) {
is ServiceId.ACI -> this.toString()
is ServiceId.PNI -> PNI_ACCOUNT_ID
}
}
}

View File

@@ -28,6 +28,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data
const val PRIVATE_KEY = "private_key"
const val SIGNATURE = "signature"
const val TIMESTAMP = "timestamp"
const val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY,
@@ -40,10 +41,12 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data
UNIQUE($ACCOUNT_ID, $KEY_ID)
)
"""
const val PNI_ACCOUNT_ID = "PNI"
}
fun get(serviceId: ServiceId, keyId: Int): SignedPreKeyRecord? {
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor ->
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor ->
if (cursor.moveToFirst()) {
try {
val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
@@ -64,7 +67,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data
fun getAll(serviceId: ServiceId): List<SignedPreKeyRecord> {
val results: MutableList<SignedPreKeyRecord> = LinkedList()
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId), null, null, null).use { cursor ->
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId()), null, null, null).use { cursor ->
while (cursor.moveToNext()) {
try {
val keyId = cursor.requireInt(KEY_ID)
@@ -86,7 +89,7 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data
fun insert(serviceId: ServiceId, keyId: Int, record: SignedPreKeyRecord) {
val contentValues = contentValuesOf(
ACCOUNT_ID to serviceId.toString(),
ACCOUNT_ID to serviceId.toAccountId(),
KEY_ID to keyId,
PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()),
PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize()),
@@ -97,6 +100,13 @@ class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : Data
}
fun delete(serviceId: ServiceId, keyId: Int) {
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId))
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId))
}
private fun ServiceId.toAccountId(): String {
return when (this) {
is ServiceId.ACI -> this.toString()
is ServiceId.PNI -> PNI_ACCOUNT_ID
}
}
}

View File

@@ -76,6 +76,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V215_RemoveAttachme
import org.thoughtcrime.securesms.database.helpers.migration.V216_PhoneNumberDiscoverable
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
/**
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
@@ -154,10 +155,11 @@ object SignalDatabaseMigrations {
215 to V215_RemoveAttachmentUniqueId,
216 to V216_PhoneNumberDiscoverable,
217 to V217_MessageTableExtrasColumn,
218 to V218_RecipientPniSignatureVerified
218 to V218_RecipientPniSignatureVerified,
219 to V219_PniPreKeyStores
)
const val DATABASE_VERSION = 218
const val DATABASE_VERSION = 219
@JvmStatic
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {

View File

@@ -0,0 +1,41 @@
/*
* 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
/**
* Changes our PNI prekey stores to use a constant indicating it's for a PNI rather than the specific PNI.
*/
@Suppress("ClassName")
object V219_PniPreKeyStores : SignalDatabaseMigration {
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL(
"""
UPDATE one_time_prekeys
SET account_id = "PNI"
WHERE account_id LIKE "PNI:%"
"""
)
db.execSQL(
"""
UPDATE signed_prekeys
SET account_id = "PNI"
WHERE account_id LIKE "PNI:%"
"""
)
db.execSQL(
"""
UPDATE kyber_prekey
SET account_id = "PNI"
WHERE account_id LIKE "PNI:%"
"""
)
}
}

View File

@@ -589,6 +589,12 @@ public class ApplicationDependencies {
return protocolStore;
}
public static void resetProtocolStores() {
synchronized (LOCK) {
protocolStore = null;
}
}
public static @NonNull GiphyMp4Cache getGiphyMp4Cache() {
if (giphyMp4Cache == null) {
synchronized (LOCK) {

View File

@@ -24,7 +24,7 @@ class BufferedSignedPreKeyStore(private val selfServiceId: ServiceId) : SignedPr
@kotlin.jvm.Throws(InvalidKeyIdException::class)
override fun loadSignedPreKey(id: Int): SignedPreKeyRecord {
return store.computeIfAbsent(id) {
SignalDatabase.signedPreKeys.get(selfServiceId, id) ?: throw InvalidKeyIdException("Missing one-time prekey with ID: $id")
SignalDatabase.signedPreKeys.get(selfServiceId, id) ?: throw InvalidKeyIdException("Missing signed prekey with ID: $id")
}
}