That fuck shit the fascists are using
1package org.tm.archive.database
2
3import android.content.Context
4import androidx.core.content.contentValuesOf
5import org.signal.core.util.Base64
6import org.signal.core.util.SqlUtil
7import org.signal.core.util.deleteAll
8import org.signal.core.util.logging.Log
9import org.signal.core.util.requireInt
10import org.signal.core.util.requireLong
11import org.signal.core.util.requireNonNullString
12import org.signal.libsignal.protocol.InvalidKeyException
13import org.signal.libsignal.protocol.ecc.Curve
14import org.signal.libsignal.protocol.ecc.ECKeyPair
15import org.signal.libsignal.protocol.state.SignedPreKeyRecord
16import org.whispersystems.signalservice.api.push.ServiceId
17import java.io.IOException
18import java.util.LinkedList
19
20class SignedPreKeyTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper) {
21 companion object {
22 private val TAG = Log.tag(SignedPreKeyTable::class.java)
23
24 const val TABLE_NAME = "signed_prekeys"
25 const val ID = "_id"
26 const val ACCOUNT_ID = "account_id"
27 const val KEY_ID = "key_id"
28 const val PUBLIC_KEY = "public_key"
29 const val PRIVATE_KEY = "private_key"
30 const val SIGNATURE = "signature"
31 const val TIMESTAMP = "timestamp"
32
33 const val CREATE_TABLE = """
34 CREATE TABLE $TABLE_NAME (
35 $ID INTEGER PRIMARY KEY,
36 $ACCOUNT_ID TEXT NOT NULL,
37 $KEY_ID INTEGER NOT NULL,
38 $PUBLIC_KEY TEXT NOT NULL,
39 $PRIVATE_KEY TEXT NOT NULL,
40 $SIGNATURE TEXT NOT NULL,
41 $TIMESTAMP INTEGER DEFAULT 0,
42 UNIQUE($ACCOUNT_ID, $KEY_ID)
43 )
44 """
45
46 const val PNI_ACCOUNT_ID = "PNI"
47 }
48
49 fun get(serviceId: ServiceId, keyId: Int): SignedPreKeyRecord? {
50 readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor ->
51 if (cursor.moveToFirst()) {
52 try {
53 val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
54 val privateKey = Curve.decodePrivatePoint(Base64.decode(cursor.requireNonNullString(PRIVATE_KEY)))
55 val signature = Base64.decode(cursor.requireNonNullString(SIGNATURE))
56 val timestamp = cursor.requireLong(TIMESTAMP)
57 return SignedPreKeyRecord(keyId, timestamp, ECKeyPair(publicKey, privateKey), signature)
58 } catch (e: InvalidKeyException) {
59 Log.w(TAG, e)
60 } catch (e: IOException) {
61 Log.w(TAG, e)
62 }
63 }
64 }
65 return null
66 }
67
68 fun getAll(serviceId: ServiceId): List<SignedPreKeyRecord> {
69 val results: MutableList<SignedPreKeyRecord> = LinkedList()
70
71 readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId()), null, null, null).use { cursor ->
72 while (cursor.moveToNext()) {
73 try {
74 val keyId = cursor.requireInt(KEY_ID)
75 val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
76 val privateKey = Curve.decodePrivatePoint(Base64.decode(cursor.requireNonNullString(PRIVATE_KEY)))
77 val signature = Base64.decode(cursor.requireNonNullString(SIGNATURE))
78 val timestamp = cursor.requireLong(TIMESTAMP)
79 results.add(SignedPreKeyRecord(keyId, timestamp, ECKeyPair(publicKey, privateKey), signature))
80 } catch (e: InvalidKeyException) {
81 Log.w(TAG, e)
82 } catch (e: IOException) {
83 Log.w(TAG, e)
84 }
85 }
86 }
87
88 return results
89 }
90
91 fun insert(serviceId: ServiceId, keyId: Int, record: SignedPreKeyRecord) {
92 val contentValues = contentValuesOf(
93 ACCOUNT_ID to serviceId.toAccountId(),
94 KEY_ID to keyId,
95 PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()),
96 PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize()),
97 SIGNATURE to Base64.encodeWithPadding(record.signature),
98 TIMESTAMP to record.timestamp
99 )
100 writableDatabase.replace(TABLE_NAME, null, contentValues)
101 }
102
103 fun delete(serviceId: ServiceId, keyId: Int) {
104 writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId))
105 }
106
107 fun debugDeleteAll() {
108 writableDatabase.deleteAll(OneTimePreKeyTable.TABLE_NAME)
109 }
110
111 private fun ServiceId.toAccountId(): String {
112 return when (this) {
113 is ServiceId.ACI -> this.toString()
114 is ServiceId.PNI -> PNI_ACCOUNT_ID
115 }
116 }
117}