kopia lustrzana https://github.com/ryukoposting/Signal-Android
131 wiersze
4.5 KiB
Kotlin
131 wiersze
4.5 KiB
Kotlin
package org.thoughtcrime.securesms.database
|
|
|
|
import android.content.Context
|
|
import android.database.Cursor
|
|
import androidx.core.content.contentValuesOf
|
|
import org.signal.core.util.CursorUtil
|
|
import org.signal.core.util.delete
|
|
import org.signal.core.util.firstOrNull
|
|
import org.signal.core.util.logging.Log
|
|
import org.signal.core.util.requireLong
|
|
import org.signal.core.util.select
|
|
import org.signal.core.util.update
|
|
import org.signal.core.util.withinTransaction
|
|
import org.signal.libsignal.protocol.InvalidMessageException
|
|
import org.signal.libsignal.protocol.SignalProtocolAddress
|
|
import org.signal.libsignal.protocol.groups.state.SenderKeyRecord
|
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|
import org.whispersystems.signalservice.api.push.DistributionId
|
|
|
|
/**
|
|
* Stores all of the sender keys -- both the ones we create, and the ones we're told about.
|
|
*
|
|
* When working with SenderKeys, keep this in mind: they're not *really* keys. They're sessions.
|
|
* The name is largely historical, and there's too much momentum to change it.
|
|
*/
|
|
class SenderKeyTable internal constructor(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper) {
|
|
companion object {
|
|
private val TAG = Log.tag(SenderKeyTable::class.java)
|
|
const val TABLE_NAME = "sender_keys"
|
|
private const val ID = "_id"
|
|
const val ADDRESS = "address"
|
|
const val DEVICE = "device"
|
|
const val DISTRIBUTION_ID = "distribution_id"
|
|
const val RECORD = "record"
|
|
const val CREATED_AT = "created_at"
|
|
const val CREATE_TABLE = """
|
|
CREATE TABLE $TABLE_NAME (
|
|
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
$ADDRESS TEXT NOT NULL,
|
|
$DEVICE INTEGER NOT NULL,
|
|
$DISTRIBUTION_ID TEXT NOT NULL,
|
|
$RECORD BLOB NOT NULL,
|
|
$CREATED_AT INTEGER NOT NULL,
|
|
UNIQUE($ADDRESS,$DEVICE, $DISTRIBUTION_ID) ON CONFLICT REPLACE
|
|
)
|
|
"""
|
|
}
|
|
|
|
fun store(address: SignalProtocolAddress, distributionId: DistributionId, record: SenderKeyRecord) {
|
|
writableDatabase.withinTransaction { db ->
|
|
val updateCount = db.update(TABLE_NAME)
|
|
.values(RECORD to record.serialize())
|
|
.where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
|
|
.run()
|
|
|
|
if (updateCount <= 0) {
|
|
Log.d(TAG, "New sender key $distributionId from $address")
|
|
val insertValues = contentValuesOf(
|
|
ADDRESS to address.name,
|
|
DEVICE to address.deviceId,
|
|
DISTRIBUTION_ID to distributionId.toString(),
|
|
RECORD to record.serialize(),
|
|
CREATED_AT to System.currentTimeMillis()
|
|
)
|
|
db.insertWithOnConflict(TABLE_NAME, null, insertValues, SQLiteDatabase.CONFLICT_REPLACE)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun load(address: SignalProtocolAddress, distributionId: DistributionId): SenderKeyRecord? {
|
|
return readableDatabase
|
|
.select(RECORD)
|
|
.from(TABLE_NAME)
|
|
.where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
|
|
.run()
|
|
.firstOrNull { cursor ->
|
|
try {
|
|
SenderKeyRecord(CursorUtil.requireBlob(cursor, RECORD))
|
|
} catch (e: InvalidMessageException) {
|
|
Log.w(TAG, e)
|
|
null
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets when the sender key session was created, or -1 if it doesn't exist.
|
|
*/
|
|
fun getCreatedTime(address: SignalProtocolAddress, distributionId: DistributionId): Long {
|
|
return readableDatabase
|
|
.select(CREATED_AT)
|
|
.from(TABLE_NAME)
|
|
.where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
|
|
.run()
|
|
.firstOrNull { cursor ->
|
|
cursor.requireLong(CREATED_AT)
|
|
} ?: -1
|
|
}
|
|
|
|
/**
|
|
* Removes all sender key session state for all devices for the provided recipient-distributionId pair.
|
|
*/
|
|
fun deleteAllFor(addressName: String, distributionId: DistributionId) {
|
|
writableDatabase
|
|
.delete(TABLE_NAME)
|
|
.where("$ADDRESS = ? AND $DISTRIBUTION_ID = ?", addressName, distributionId)
|
|
.run()
|
|
}
|
|
|
|
/**
|
|
* Get metadata for all sender keys created by the local user. Used for debugging.
|
|
*/
|
|
fun getAllCreatedBySelf(): Cursor {
|
|
return readableDatabase
|
|
.select(ID, DISTRIBUTION_ID, CREATED_AT)
|
|
.from(TABLE_NAME)
|
|
.where("$ADDRESS = ?", SignalStore.account().requireAci())
|
|
.orderBy("$CREATED_AT DESC")
|
|
.run()
|
|
}
|
|
|
|
/**
|
|
* Deletes all database state.
|
|
*/
|
|
fun deleteAll() {
|
|
writableDatabase
|
|
.delete(TABLE_NAME)
|
|
.run()
|
|
}
|
|
}
|