That fuck shit the fascists are using
at master 129 lines 4.4 kB view raw
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.delete 8import org.signal.core.util.deleteAll 9import org.signal.core.util.logging.Log 10import org.signal.core.util.requireNonNullString 11import org.signal.core.util.update 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.PreKeyRecord 16import org.whispersystems.signalservice.api.push.ServiceId 17import java.io.IOException 18 19class OneTimePreKeyTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper) { 20 companion object { 21 private val TAG = Log.tag(OneTimePreKeyTable::class.java) 22 23 const val TABLE_NAME = "one_time_prekeys" 24 const val ID = "_id" 25 const val ACCOUNT_ID = "account_id" 26 const val KEY_ID = "key_id" 27 const val PUBLIC_KEY = "public_key" 28 const val PRIVATE_KEY = "private_key" 29 const val STALE_TIMESTAMP = "stale_timestamp" 30 31 const val CREATE_TABLE = """ 32 CREATE TABLE $TABLE_NAME ( 33 $ID INTEGER PRIMARY KEY, 34 $ACCOUNT_ID TEXT NOT NULL, 35 $KEY_ID INTEGER NOT NULL, 36 $PUBLIC_KEY TEXT NOT NULL, 37 $PRIVATE_KEY TEXT NOT NULL, 38 $STALE_TIMESTAMP INTEGER NOT NULL DEFAULT 0, 39 UNIQUE($ACCOUNT_ID, $KEY_ID) 40 ) 41 """ 42 43 const val PNI_ACCOUNT_ID = "PNI" 44 } 45 46 fun get(serviceId: ServiceId, keyId: Int): PreKeyRecord? { 47 readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId), null, null, null).use { cursor -> 48 if (cursor.moveToFirst()) { 49 try { 50 val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0) 51 val privateKey = Curve.decodePrivatePoint(Base64.decode(cursor.requireNonNullString(PRIVATE_KEY))) 52 return PreKeyRecord(keyId, ECKeyPair(publicKey, privateKey)) 53 } catch (e: InvalidKeyException) { 54 Log.w(TAG, e) 55 } catch (e: IOException) { 56 Log.w(TAG, e) 57 } 58 } 59 } 60 61 return null 62 } 63 64 fun insert(serviceId: ServiceId, keyId: Int, record: PreKeyRecord) { 65 val contentValues = contentValuesOf( 66 ACCOUNT_ID to serviceId.toAccountId(), 67 KEY_ID to keyId, 68 PUBLIC_KEY to Base64.encodeWithPadding(record.keyPair.publicKey.serialize()), 69 PRIVATE_KEY to Base64.encodeWithPadding(record.keyPair.privateKey.serialize()) 70 ) 71 72 writableDatabase.replace(TABLE_NAME, null, contentValues) 73 } 74 75 fun delete(serviceId: ServiceId, keyId: Int) { 76 val database = databaseHelper.signalWritableDatabase 77 database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId.toAccountId(), keyId)) 78 } 79 80 fun markAllStaleIfNecessary(serviceId: ServiceId, staleTime: Long) { 81 writableDatabase 82 .update(TABLE_NAME) 83 .values(STALE_TIMESTAMP to staleTime) 84 .where("$ACCOUNT_ID = ? AND $STALE_TIMESTAMP = 0", serviceId.toAccountId()) 85 .run() 86 } 87 88 /** 89 * Deletes all keys that have been stale since before the specified threshold. 90 * We will always keep at least [minCount] items, preferring more recent ones. 91 */ 92 fun deleteAllStaleBefore(serviceId: ServiceId, threshold: Long, minCount: Int) { 93 val count = writableDatabase 94 .delete(TABLE_NAME) 95 .where( 96 """ 97 $ACCOUNT_ID = ? 98 AND $STALE_TIMESTAMP > 0 99 AND $STALE_TIMESTAMP < $threshold 100 AND $ID NOT IN ( 101 SELECT $ID 102 FROM $TABLE_NAME 103 WHERE $ACCOUNT_ID = ? 104 ORDER BY 105 CASE $STALE_TIMESTAMP WHEN 0 THEN 1 ELSE 0 END DESC, 106 $STALE_TIMESTAMP DESC, 107 $ID DESC 108 LIMIT $minCount 109 ) 110 """, 111 serviceId.toAccountId(), 112 serviceId.toAccountId() 113 ) 114 .run() 115 116 Log.i(TAG, "Deleted $count stale one-time EC prekeys.") 117 } 118 119 fun debugDeleteAll() { 120 writableDatabase.deleteAll(TABLE_NAME) 121 } 122 123 private fun ServiceId.toAccountId(): String { 124 return when (this) { 125 is ServiceId.ACI -> this.toString() 126 is ServiceId.PNI -> PNI_ACCOUNT_ID 127 } 128 } 129}