That fuck shit the fascists are using
1package org.tm.archive.database
2
3import android.content.Context
4import android.database.Cursor
5import androidx.core.content.contentValuesOf
6import org.signal.core.util.CursorUtil
7import org.signal.core.util.delete
8import org.signal.core.util.deleteAll
9import org.signal.core.util.firstOrNull
10import org.signal.core.util.logging.Log
11import org.signal.core.util.requireLong
12import org.signal.core.util.select
13import org.signal.core.util.update
14import org.signal.core.util.withinTransaction
15import org.signal.libsignal.protocol.InvalidMessageException
16import org.signal.libsignal.protocol.SignalProtocolAddress
17import org.signal.libsignal.protocol.groups.state.SenderKeyRecord
18import org.tm.archive.keyvalue.SignalStore
19import org.whispersystems.signalservice.api.push.DistributionId
20
21/**
22 * Stores all of the sender keys -- both the ones we create, and the ones we're told about.
23 *
24 * When working with SenderKeys, keep this in mind: they're not *really* keys. They're sessions.
25 * The name is largely historical, and there's too much momentum to change it.
26 */
27class SenderKeyTable internal constructor(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper) {
28 companion object {
29 private val TAG = Log.tag(SenderKeyTable::class.java)
30 const val TABLE_NAME = "sender_keys"
31 private const val ID = "_id"
32 const val ADDRESS = "address"
33 const val DEVICE = "device"
34 const val DISTRIBUTION_ID = "distribution_id"
35 const val RECORD = "record"
36 const val CREATED_AT = "created_at"
37 const val CREATE_TABLE = """
38 CREATE TABLE $TABLE_NAME (
39 $ID INTEGER PRIMARY KEY AUTOINCREMENT,
40 $ADDRESS TEXT NOT NULL,
41 $DEVICE INTEGER NOT NULL,
42 $DISTRIBUTION_ID TEXT NOT NULL,
43 $RECORD BLOB NOT NULL,
44 $CREATED_AT INTEGER NOT NULL,
45 UNIQUE($ADDRESS,$DEVICE, $DISTRIBUTION_ID) ON CONFLICT REPLACE
46 )
47 """
48 }
49
50 fun store(address: SignalProtocolAddress, distributionId: DistributionId, record: SenderKeyRecord) {
51 writableDatabase.withinTransaction { db ->
52 val updateCount = db.update(TABLE_NAME)
53 .values(RECORD to record.serialize())
54 .where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
55 .run()
56
57 if (updateCount <= 0) {
58 Log.d(TAG, "New sender key $distributionId from $address")
59 val insertValues = contentValuesOf(
60 ADDRESS to address.name,
61 DEVICE to address.deviceId,
62 DISTRIBUTION_ID to distributionId.toString(),
63 RECORD to record.serialize(),
64 CREATED_AT to System.currentTimeMillis()
65 )
66 db.insertWithOnConflict(TABLE_NAME, null, insertValues, SQLiteDatabase.CONFLICT_REPLACE)
67 }
68 }
69 }
70
71 fun load(address: SignalProtocolAddress, distributionId: DistributionId): SenderKeyRecord? {
72 return readableDatabase
73 .select(RECORD)
74 .from(TABLE_NAME)
75 .where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
76 .run()
77 .firstOrNull { cursor ->
78 try {
79 SenderKeyRecord(CursorUtil.requireBlob(cursor, RECORD))
80 } catch (e: InvalidMessageException) {
81 Log.w(TAG, e)
82 null
83 }
84 }
85 }
86
87 /**
88 * Gets when the sender key session was created, or -1 if it doesn't exist.
89 */
90 fun getCreatedTime(address: SignalProtocolAddress, distributionId: DistributionId): Long {
91 return readableDatabase
92 .select(CREATED_AT)
93 .from(TABLE_NAME)
94 .where("$ADDRESS = ? AND $DEVICE = ? AND $DISTRIBUTION_ID = ?", address.name, address.deviceId, distributionId)
95 .run()
96 .firstOrNull { cursor ->
97 cursor.requireLong(CREATED_AT)
98 } ?: -1
99 }
100
101 /**
102 * Removes all sender key session state for all devices for the provided recipient-distributionId pair.
103 */
104 fun deleteAllFor(addressName: String, distributionId: DistributionId) {
105 writableDatabase
106 .delete(TABLE_NAME)
107 .where("$ADDRESS = ? AND $DISTRIBUTION_ID = ?", addressName, distributionId)
108 .run()
109 }
110
111 /**
112 * Get metadata for all sender keys created by the local user. Used for debugging.
113 */
114 fun getAllCreatedBySelf(): Cursor {
115 return readableDatabase
116 .select(ID, DISTRIBUTION_ID, CREATED_AT)
117 .from(TABLE_NAME)
118 .where("$ADDRESS = ?", SignalStore.account().requireAci())
119 .orderBy("$CREATED_AT DESC")
120 .run()
121 }
122
123 /**
124 * Deletes all database state.
125 */
126 fun deleteAll() {
127 writableDatabase.deleteAll(TABLE_NAME)
128 }
129}