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.delete
7import org.signal.core.util.deleteAll
8import org.signal.core.util.logging.Log
9import org.signal.core.util.readToSet
10import org.signal.core.util.requireInt
11import org.signal.core.util.requireString
12import org.signal.core.util.select
13import org.signal.core.util.withinTransaction
14import org.signal.libsignal.protocol.SignalProtocolAddress
15import org.tm.archive.recipients.Recipient
16import org.tm.archive.recipients.RecipientId
17import org.whispersystems.signalservice.api.push.DistributionId
18
19/**
20 * Keeps track of which recipients are aware of which distributionIds. For the storage of sender
21 * keys themselves, see [SenderKeyTable].
22 */
23class SenderKeySharedTable internal constructor(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper) {
24 companion object {
25 private val TAG = Log.tag(SenderKeySharedTable::class.java)
26 const val TABLE_NAME = "sender_key_shared"
27 private const val ID = "_id"
28 const val DISTRIBUTION_ID = "distribution_id"
29 const val ADDRESS = "address"
30 const val DEVICE = "device"
31 const val TIMESTAMP = "timestamp"
32 const val CREATE_TABLE = """
33 CREATE TABLE $TABLE_NAME (
34 $ID INTEGER PRIMARY KEY AUTOINCREMENT,
35 $DISTRIBUTION_ID TEXT NOT NULL,
36 $ADDRESS TEXT NOT NULL,
37 $DEVICE INTEGER NOT NULL,
38 $TIMESTAMP INTEGER DEFAULT 0,
39 UNIQUE($DISTRIBUTION_ID,$ADDRESS, $DEVICE) ON CONFLICT REPLACE
40 )
41 """
42 }
43
44/**
45 * Mark that a distributionId has been shared with the provided recipients
46 */
47 fun markAsShared(distributionId: DistributionId, addresses: Collection<SignalProtocolAddress>) {
48 writableDatabase.withinTransaction { db ->
49 for (address in addresses) {
50 val values = contentValuesOf(
51 ADDRESS to address.name,
52 DEVICE to address.deviceId,
53 DISTRIBUTION_ID to distributionId.toString(),
54 TIMESTAMP to System.currentTimeMillis()
55 )
56 db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE)
57 }
58 }
59 }
60
61 /**
62 * Get the set of recipientIds that know about the distributionId in question.
63 */
64 fun getSharedWith(distributionId: DistributionId): Set<SignalProtocolAddress> {
65 return readableDatabase
66 .select(ADDRESS, DEVICE)
67 .from(TABLE_NAME)
68 .where("$DISTRIBUTION_ID = ?", distributionId)
69 .run()
70 .readToSet { cursor ->
71 SignalProtocolAddress(
72 cursor.requireString(ADDRESS),
73 cursor.requireInt(DEVICE)
74 )
75 }
76 }
77
78 /**
79 * Clear the shared statuses for all provided addresses.
80 */
81 fun delete(distributionId: DistributionId, addresses: Collection<SignalProtocolAddress>) {
82 writableDatabase.withinTransaction { db ->
83 for (address in addresses) {
84 db.delete(TABLE_NAME)
85 .where("$DISTRIBUTION_ID = ? AND $ADDRESS = ? AND $DEVICE = ?", distributionId, address.name, address.deviceId)
86 .run()
87 }
88 }
89 }
90
91 /**
92 * Clear all shared statuses for a given distributionId.
93 */
94 fun deleteAllFor(distributionId: DistributionId) {
95 writableDatabase
96 .delete(TABLE_NAME)
97 .where("$DISTRIBUTION_ID = ?", distributionId)
98 .run()
99 }
100
101 /**
102 * Clear the shared status for all distributionIds for a set of addresses.
103 */
104 fun deleteAllFor(addresses: Collection<SignalProtocolAddress>) {
105 writableDatabase.withinTransaction { db ->
106 for (address in addresses) {
107 db.delete(TABLE_NAME)
108 .where("$ADDRESS = ? AND $DEVICE = ?", address.name, address.deviceId)
109 .run()
110 }
111 }
112 }
113
114 /**
115 * Clear the shared status for all distributionIds for a given recipientId.
116 */
117 fun deleteAllFor(recipientId: RecipientId) {
118 val recipient = Recipient.resolved(recipientId)
119 if (recipient.hasServiceId()) {
120 if (recipient.hasAci()) {
121 writableDatabase
122 .delete(TABLE_NAME)
123 .where("$ADDRESS = ?", recipient.requireAci().toString())
124 .run()
125 }
126 if (recipient.hasPni()) {
127 writableDatabase
128 .delete(TABLE_NAME)
129 .where("$ADDRESS = ?", recipient.requirePni().toString())
130 .run()
131 }
132 } else {
133 Log.w(TAG, "Recipient doesn't have a ServiceId! $recipientId")
134 }
135 }
136
137 /**
138 * Clears all database content.
139 */
140 fun deleteAll() {
141 writableDatabase.deleteAll(TABLE_NAME)
142 }
143
144 /**
145 * Gets the shared state of all of our sender keys. Used for debugging.
146 */
147 fun getAllSharedWithCursor(): Cursor {
148 return readableDatabase.query(TABLE_NAME, null, null, null, null, null, "$DISTRIBUTION_ID, $ADDRESS, $DEVICE")
149 }
150}