That fuck shit the fascists are using
at master 112 lines 3.8 kB view raw
1package org.tm.archive.database 2 3import android.content.ContentValues 4import android.content.Context 5import androidx.core.content.contentValuesOf 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.select 12import org.signal.core.util.withinTransaction 13 14/** 15 * Keeps track of the numbers we've previously queried CDS for. 16 * 17 * This is important for rate-limiting: our rate-limiting strategy hinges on keeping 18 * an accurate history of numbers we've queried so that we're only "charged" for 19 * querying new numbers. 20 */ 21class CdsTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper) { 22 companion object { 23 private val TAG = Log.tag(CdsTable::class.java) 24 25 const val TABLE_NAME = "cds" 26 27 private const val ID = "_id" 28 const val E164 = "e164" 29 private const val LAST_SEEN_AT = "last_seen_at" 30 31 const val CREATE_TABLE = """ 32 CREATE TABLE $TABLE_NAME ( 33 $ID INTEGER PRIMARY KEY, 34 $E164 TEXT NOT NULL UNIQUE ON CONFLICT IGNORE, 35 $LAST_SEEN_AT INTEGER DEFAULT 0 36 ) 37 """ 38 } 39 40 fun getAllE164s(): Set<String> { 41 val e164s: MutableSet<String> = mutableSetOf() 42 43 readableDatabase 44 .select(E164) 45 .from(TABLE_NAME) 46 .run() 47 .use { cursor -> 48 while (cursor.moveToNext()) { 49 e164s += cursor.requireNonNullString(E164) 50 } 51 } 52 53 return e164s 54 } 55 56 /** 57 * Saves the set of e164s used after a full refresh. 58 * @param fullE164s All of the e164s used in the last CDS query (previous and new). 59 * @param seenE164s The E164s that were seen in either the system contacts or recipients table. This is different from [fullE164s] in that [fullE164s] 60 * includes every number we've ever seen, even if it's not in our contacts anymore. 61 */ 62 fun updateAfterFullCdsQuery(fullE164s: Set<String>, seenE164s: Set<String>) { 63 val lastSeen = System.currentTimeMillis() 64 65 writableDatabase.withinTransaction { db -> 66 val existingE164s: Set<String> = getAllE164s() 67 val removedE164s: Set<String> = existingE164s - fullE164s 68 val addedE164s: Set<String> = fullE164s - existingE164s 69 70 if (removedE164s.isNotEmpty()) { 71 SqlUtil.buildCollectionQuery(E164, removedE164s) 72 .forEach { db.delete(TABLE_NAME, it.where, it.whereArgs) } 73 } 74 75 if (addedE164s.isNotEmpty()) { 76 val insertValues: List<ContentValues> = addedE164s.map { contentValuesOf(E164 to it) } 77 78 SqlUtil.buildBulkInsert(TABLE_NAME, arrayOf(E164), insertValues) 79 .forEach { db.execSQL(it.where, it.whereArgs) } 80 } 81 82 if (seenE164s.isNotEmpty()) { 83 val contentValues = contentValuesOf(LAST_SEEN_AT to lastSeen) 84 85 SqlUtil.buildCollectionQuery(E164, seenE164s) 86 .forEach { query -> db.update(TABLE_NAME, contentValues, query.where, query.whereArgs) } 87 } 88 } 89 } 90 91 /** 92 * Updates after a partial CDS query. Will not insert new entries. Instead, this will simply update the lastSeen timestamp of any entry we already have. 93 * @param seenE164s The newly-added E164s that we hadn't previously queried for. 94 */ 95 fun updateAfterPartialCdsQuery(seenE164s: Set<String>) { 96 val lastSeen = System.currentTimeMillis() 97 98 writableDatabase.withinTransaction { db -> 99 val contentValues = contentValuesOf(LAST_SEEN_AT to lastSeen) 100 101 SqlUtil.buildCollectionQuery(E164, seenE164s) 102 .forEach { query -> db.update(TABLE_NAME, contentValues, query.where, query.whereArgs) } 103 } 104 } 105 106 /** 107 * Wipes the entire table. 108 */ 109 fun clearAll() { 110 writableDatabase.deleteAll(TABLE_NAME) 111 } 112}