mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-26 14:09:58 +00:00
Update stores to use a constant accountId for PNIs.
This commit is contained in:
@@ -233,6 +233,7 @@ class ChangeNumberRepository(
|
||||
|
||||
SignalStore.account().setE164(e164)
|
||||
SignalStore.account().setPni(pni)
|
||||
ApplicationDependencies.resetProtocolStores()
|
||||
|
||||
ApplicationDependencies.getGroupsV2Authorization().clear()
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:%"
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user