mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 16:49:40 +01:00
Add initial storage interfaces for kyber prekeys.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.delete
|
||||
import org.signal.core.util.exists
|
||||
import org.signal.core.util.insertInto
|
||||
import org.signal.core.util.readToList
|
||||
import org.signal.core.util.readToSingleObject
|
||||
import org.signal.core.util.requireBoolean
|
||||
import org.signal.core.util.requireNonNullBlob
|
||||
import org.signal.core.util.select
|
||||
import org.signal.libsignal.protocol.state.KyberPreKeyRecord
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
|
||||
/**
|
||||
* A table for storing data related to [org.thoughtcrime.securesms.crypto.storage.SignalKyberPreKeyStore].
|
||||
*/
|
||||
class KyberPreKeyTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper) {
|
||||
companion object {
|
||||
const val TABLE_NAME = "kyber_prekey"
|
||||
const val ID = "_id"
|
||||
const val ACCOUNT_ID = "account_id"
|
||||
const val KEY_ID = "key_id"
|
||||
const val TIMESTAMP = "timestamp"
|
||||
const val LAST_RESORT = "last_resort"
|
||||
const val SERIALIZED = "serialized"
|
||||
const val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY,
|
||||
$ACCOUNT_ID TEXT NOT NULL,
|
||||
$KEY_ID INTEGER UNIQUE NOT NULL,
|
||||
$TIMESTAMP INTEGER NOT NULL,
|
||||
$LAST_RESORT INTEGER NOT NULL,
|
||||
$SERIALIZED BLOB NOT NULL,
|
||||
UNIQUE($ACCOUNT_ID, $KEY_ID)
|
||||
)
|
||||
"""
|
||||
|
||||
private const val INDEX_ACCOUNT_KEY = "kyber_account_id_key_id"
|
||||
|
||||
val CREATE_INDEXES = arrayOf(
|
||||
"CREATE INDEX IF NOT EXISTS $INDEX_ACCOUNT_KEY ON $TABLE_NAME ($ACCOUNT_ID, $KEY_ID, $LAST_RESORT, $SERIALIZED)"
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
KyberPreKey(
|
||||
record = KyberPreKeyRecord(cursor.requireNonNullBlob(SERIALIZED)),
|
||||
lastResort = cursor.requireBoolean(LAST_RESORT)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAll(serviceId: ServiceId): List<KyberPreKey> {
|
||||
return readableDatabase
|
||||
.select(LAST_RESORT, SERIALIZED)
|
||||
.from("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
|
||||
.where("$ACCOUNT_ID = ?", serviceId)
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
KyberPreKey(
|
||||
record = KyberPreKeyRecord(cursor.requireNonNullBlob(SERIALIZED)),
|
||||
lastResort = cursor.requireBoolean(LAST_RESORT)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
.run()
|
||||
}
|
||||
|
||||
fun insert(serviceId: ServiceId, keyId: Int, record: KyberPreKeyRecord) {
|
||||
writableDatabase
|
||||
.insertInto(TABLE_NAME)
|
||||
.values(
|
||||
ACCOUNT_ID to serviceId.toString(),
|
||||
KEY_ID to keyId,
|
||||
TIMESTAMP to record.timestamp,
|
||||
SERIALIZED to record.serialize()
|
||||
)
|
||||
.run(SQLiteDatabase.CONFLICT_REPLACE)
|
||||
}
|
||||
|
||||
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)
|
||||
.run()
|
||||
}
|
||||
|
||||
fun delete(serviceId: ServiceId, keyId: Int) {
|
||||
writableDatabase
|
||||
.delete("$TABLE_NAME INDEXED BY $INDEX_ACCOUNT_KEY")
|
||||
.where("$ACCOUNT_ID = ? AND $KEY_ID = ?", serviceId, keyId)
|
||||
.run()
|
||||
}
|
||||
|
||||
data class KyberPreKey(
|
||||
val record: KyberPreKeyRecord,
|
||||
val lastResort: Boolean
|
||||
)
|
||||
}
|
||||
@@ -74,6 +74,7 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
val remoteMegaphoneTable: RemoteMegaphoneTable = RemoteMegaphoneTable(context, this)
|
||||
val pendingPniSignatureMessageTable: PendingPniSignatureMessageTable = PendingPniSignatureMessageTable(context, this)
|
||||
val callTable: CallTable = CallTable(context, this)
|
||||
val kyberPreKeyTable: KyberPreKeyTable = KyberPreKeyTable(context, this)
|
||||
|
||||
override fun onOpen(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
|
||||
db.setForeignKeyConstraintsEnabled(true)
|
||||
@@ -110,6 +111,7 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
db.execSQL(PendingPniSignatureMessageTable.CREATE_TABLE)
|
||||
db.execSQL(CallLinkTable.CREATE_TABLE)
|
||||
db.execSQL(CallTable.CREATE_TABLE)
|
||||
db.execSQL(KyberPreKeyTable.CREATE_TABLE)
|
||||
executeStatements(db, SearchTable.CREATE_TABLE)
|
||||
executeStatements(db, RemappedRecordTables.CREATE_TABLE)
|
||||
executeStatements(db, MessageSendLogTables.CREATE_TABLE)
|
||||
@@ -135,6 +137,7 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
executeStatements(db, PendingPniSignatureMessageTable.CREATE_INDEXES)
|
||||
executeStatements(db, CallTable.CREATE_INDEXES)
|
||||
executeStatements(db, ReactionTable.CREATE_INDEXES)
|
||||
executeStatements(db, KyberPreKeyTable.CREATE_INDEXES)
|
||||
|
||||
executeStatements(db, SearchTable.CREATE_TRIGGERS)
|
||||
executeStatements(db, MessageSendLogTables.CREATE_TRIGGERS)
|
||||
@@ -403,6 +406,11 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
val identities: IdentityTable
|
||||
get() = instance!!.identityTable
|
||||
|
||||
@get:JvmStatic
|
||||
@get:JvmName("kyberPreKeys")
|
||||
val kyberPreKeys: KyberPreKeyTable
|
||||
get() = instance!!.kyberPreKeyTable
|
||||
|
||||
@get:JvmStatic
|
||||
@get:JvmName("media")
|
||||
val media: MediaTable
|
||||
|
||||
@@ -49,6 +49,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V190_UniqueMessageM
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V191_UniqueMessageMigrationV2
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V192_CallLinkTableNullableRootKeys
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V193_BackCallLinksWithRecipient
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V194_KyberPreKeyMigration
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -57,7 +58,7 @@ object SignalDatabaseMigrations {
|
||||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 193
|
||||
const val DATABASE_VERSION = 194
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -240,6 +241,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 193) {
|
||||
V193_BackCallLinksWithRecipient.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 194) {
|
||||
V194_KyberPreKeyMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Introduces [org.thoughtcrime.securesms.database.KyberPreKeyTable].
|
||||
*/
|
||||
object V194_KyberPreKeyMigration : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE kyber_prekey (
|
||||
_id INTEGER PRIMARY KEY,
|
||||
account_id TEXT NOT NULL,
|
||||
key_id INTEGER UNIQUE NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
last_resort INTEGER NOT NULL,
|
||||
serialized BLOB NOT NULL,
|
||||
UNIQUE(account_id, key_id)
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS kyber_account_id_key_id ON kyber_prekey (account_id, key_id, last_resort, serialized)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user