That fuck shit the fascists are using
1package org.tm.archive.database
2
3import android.app.Application
4import android.content.Context
5import androidx.annotation.VisibleForTesting
6import com.tm.androidcopysdk.api.IArchiveMessageDao
7import com.tm.androidcopysdk.api.IDatabase
8import net.zetetic.database.sqlcipher.SQLiteOpenHelper
9import org.archiver.data.TeleAttachmentTable
10import org.archiver.data.TeleMessageTable
11import org.signal.core.util.SqlUtil
12import org.signal.core.util.logging.Log
13import org.signal.core.util.withinTransaction
14import org.tm.archive.crypto.AttachmentSecret
15import org.tm.archive.crypto.DatabaseSecret
16import org.tm.archive.crypto.MasterSecret
17import org.tm.archive.database.helpers.ClassicOpenHelper
18import org.tm.archive.database.helpers.PreKeyMigrationHelper
19import org.tm.archive.database.helpers.SQLCipherMigrationHelper
20import org.tm.archive.database.helpers.SessionStoreMigrationHelper
21import org.tm.archive.database.helpers.SignalDatabaseMigrations
22import org.tm.archive.database.model.AvatarPickerDatabase
23import org.tm.archive.jobs.PreKeysSyncJob
24import org.tm.archive.migrations.LegacyMigrationJob
25import org.tm.archive.migrations.LegacyMigrationJob.DatabaseUpgradeListener
26import org.tm.archive.service.KeyCachingService
27import org.tm.archive.util.TextSecurePreferences
28import java.io.File
29
30open class SignalDatabase(private val context: Application, databaseSecret: DatabaseSecret, attachmentSecret: AttachmentSecret) :
31 SQLiteOpenHelper(
32 context,
33 DATABASE_NAME,
34 databaseSecret.asString(),
35 null,
36 SignalDatabaseMigrations.DATABASE_VERSION,
37 0,
38 SqlCipherErrorHandler(DATABASE_NAME),
39 SqlCipherDatabaseHook(),
40 true
41 ),
42 SignalDatabaseOpenHelper, IDatabase<Long> { // TM_SA implement IDatabase
43
44 val messageTable: MessageTable = TeleMessageTable(context, this) // TM_SA TeleMessageTable
45 val attachmentTable: AttachmentTable = TeleAttachmentTable(context, this, attachmentSecret) // TM_SA TeleAttachmentTable
46 val mediaTable: MediaTable = MediaTable(context, this)
47 val threadTable: ThreadTable = ThreadTable(context, this)
48 val identityTable: IdentityTable = IdentityTable(context, this)
49 val draftTable: DraftTable = DraftTable(context, this)
50 val groupTable: GroupTable = GroupTable(context, this)
51 val recipientTable: RecipientTable = RecipientTable(context, this)
52 val groupReceiptTable: GroupReceiptTable = GroupReceiptTable(context, this)
53 val preKeyDatabase: OneTimePreKeyTable = OneTimePreKeyTable(context, this)
54 val signedPreKeyTable: SignedPreKeyTable = SignedPreKeyTable(context, this)
55 val sessionTable: SessionTable = SessionTable(context, this)
56 val senderKeyTable: SenderKeyTable = SenderKeyTable(context, this)
57 val senderKeySharedTable: SenderKeySharedTable = SenderKeySharedTable(context, this)
58 val pendingRetryReceiptTable: PendingRetryReceiptTable = PendingRetryReceiptTable(context, this)
59 val searchTable: SearchTable = SearchTable(context, this)
60 val stickerTable: StickerTable = StickerTable(context, this, attachmentSecret)
61 val storageIdDatabase: UnknownStorageIdTable = UnknownStorageIdTable(context, this)
62 val remappedRecordTables: RemappedRecordTables = RemappedRecordTables(context, this)
63 val mentionTable: MentionTable = MentionTable(context, this)
64 val paymentTable: PaymentTable = PaymentTable(context, this)
65 val chatColorsTable: ChatColorsTable = ChatColorsTable(context, this)
66 val emojiSearchTable: EmojiSearchTable = EmojiSearchTable(context, this)
67 val messageSendLogTables: MessageSendLogTables = MessageSendLogTables(context, this)
68 val avatarPickerDatabase: AvatarPickerDatabase = AvatarPickerDatabase(context, this)
69 val reactionTable: ReactionTable = ReactionTable(context, this)
70 val notificationProfileDatabase: NotificationProfileDatabase = NotificationProfileDatabase(context, this)
71 val donationReceiptTable: DonationReceiptTable = DonationReceiptTable(context, this)
72 val distributionListTables: DistributionListTables = DistributionListTables(context, this)
73 val storySendTable: StorySendTable = StorySendTable(context, this)
74 val cdsTable: CdsTable = CdsTable(context, this)
75 val remoteMegaphoneTable: RemoteMegaphoneTable = RemoteMegaphoneTable(context, this)
76 val pendingPniSignatureMessageTable: PendingPniSignatureMessageTable = PendingPniSignatureMessageTable(context, this)
77 val callTable: CallTable = CallTable(context, this)
78 val kyberPreKeyTable: KyberPreKeyTable = KyberPreKeyTable(context, this)
79 val callLinkTable: CallLinkTable = CallLinkTable(context, this)
80
81 override fun onOpen(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
82 db.setForeignKeyConstraintsEnabled(true)
83 }
84
85 override fun onCreate(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
86 db.execSQL(MessageTable.CREATE_TABLE)
87 db.execSQL(AttachmentTable.CREATE_TABLE)
88 db.execSQL(ThreadTable.CREATE_TABLE)
89 db.execSQL(IdentityTable.CREATE_TABLE)
90 db.execSQL(DraftTable.CREATE_TABLE)
91 executeStatements(db, GroupTable.CREATE_TABLES)
92 db.execSQL(RecipientTable.CREATE_TABLE)
93 db.execSQL(GroupReceiptTable.CREATE_TABLE)
94 db.execSQL(OneTimePreKeyTable.CREATE_TABLE)
95 db.execSQL(SignedPreKeyTable.CREATE_TABLE)
96 db.execSQL(SessionTable.CREATE_TABLE)
97 db.execSQL(SenderKeyTable.CREATE_TABLE)
98 db.execSQL(SenderKeySharedTable.CREATE_TABLE)
99 db.execSQL(PendingRetryReceiptTable.CREATE_TABLE)
100 db.execSQL(StickerTable.CREATE_TABLE)
101 db.execSQL(UnknownStorageIdTable.CREATE_TABLE)
102 db.execSQL(MentionTable.CREATE_TABLE)
103 db.execSQL(PaymentTable.CREATE_TABLE)
104 db.execSQL(ChatColorsTable.CREATE_TABLE)
105 db.execSQL(EmojiSearchTable.CREATE_TABLE)
106 db.execSQL(AvatarPickerDatabase.CREATE_TABLE)
107 db.execSQL(ReactionTable.CREATE_TABLE)
108 db.execSQL(DonationReceiptTable.CREATE_TABLE)
109 db.execSQL(StorySendTable.CREATE_TABLE)
110 db.execSQL(CdsTable.CREATE_TABLE)
111 db.execSQL(RemoteMegaphoneTable.CREATE_TABLE)
112 db.execSQL(PendingPniSignatureMessageTable.CREATE_TABLE)
113 db.execSQL(CallLinkTable.CREATE_TABLE)
114 db.execSQL(CallTable.CREATE_TABLE)
115 db.execSQL(KyberPreKeyTable.CREATE_TABLE)
116 executeStatements(db, SearchTable.CREATE_TABLE)
117 executeStatements(db, RemappedRecordTables.CREATE_TABLE)
118 executeStatements(db, MessageSendLogTables.CREATE_TABLE)
119 executeStatements(db, NotificationProfileDatabase.CREATE_TABLE)
120 executeStatements(db, DistributionListTables.CREATE_TABLE)
121
122 executeStatements(db, RecipientTable.CREATE_INDEXS)
123 executeStatements(db, MessageTable.CREATE_INDEXS)
124 executeStatements(db, AttachmentTable.CREATE_INDEXS)
125 executeStatements(db, ThreadTable.CREATE_INDEXS)
126 executeStatements(db, DraftTable.CREATE_INDEXS)
127 executeStatements(db, GroupTable.CREATE_INDEXS)
128 executeStatements(db, GroupReceiptTable.CREATE_INDEXES)
129 executeStatements(db, StickerTable.CREATE_INDEXES)
130 executeStatements(db, UnknownStorageIdTable.CREATE_INDEXES)
131 executeStatements(db, MentionTable.CREATE_INDEXES)
132 executeStatements(db, PaymentTable.CREATE_INDEXES)
133 executeStatements(db, MessageSendLogTables.CREATE_INDEXES)
134 executeStatements(db, NotificationProfileDatabase.CREATE_INDEXES)
135 executeStatements(db, DonationReceiptTable.CREATE_INDEXS)
136 executeStatements(db, StorySendTable.CREATE_INDEXS)
137 executeStatements(db, DistributionListTables.CREATE_INDEXES)
138 executeStatements(db, PendingPniSignatureMessageTable.CREATE_INDEXES)
139 executeStatements(db, CallTable.CREATE_INDEXES)
140 executeStatements(db, ReactionTable.CREATE_INDEXES)
141 executeStatements(db, KyberPreKeyTable.CREATE_INDEXES)
142
143 executeStatements(db, SearchTable.CREATE_TRIGGERS)
144 executeStatements(db, MessageSendLogTables.CREATE_TRIGGERS)
145
146 DistributionListTables.insertInitialDistributionListAtCreationTime(db)
147
148 if (context.getDatabasePath(ClassicOpenHelper.NAME).exists()) {
149 val legacyHelper = ClassicOpenHelper(context)
150 val legacyDb = legacyHelper.writableDatabase
151 SQLCipherMigrationHelper.migratePlaintext(context, legacyDb, db)
152 val masterSecret = KeyCachingService.getMasterSecret(context)
153 if (masterSecret != null) SQLCipherMigrationHelper.migrateCiphertext(context, masterSecret, legacyDb, db, null) else TextSecurePreferences.setNeedsSqlCipherMigration(context, true)
154 if (!PreKeyMigrationHelper.migratePreKeys(context, db)) {
155 PreKeysSyncJob.enqueue()
156 }
157 SessionStoreMigrationHelper.migrateSessions(context, db)
158 PreKeyMigrationHelper.cleanUpPreKeys(context)
159 }
160 }
161
162 override fun onUpgrade(db: net.zetetic.database.sqlcipher.SQLiteDatabase, oldVersion: Int, newVersion: Int) {
163 // The caller of onUpgrade starts a transaction, which prevents us from turning off foreign keys.
164 // At this point it hasn't done anything, so we can just end it and then start it again ourselves.
165 db.endTransaction()
166
167 Log.i(TAG, "Upgrading database: $oldVersion, $newVersion")
168 val startTime = System.currentTimeMillis()
169 db.setForeignKeyConstraintsEnabled(false)
170 try {
171 // Transactions and version bumps are handled in the migrate method
172 SignalDatabaseMigrations.migrate(context, db, oldVersion, newVersion)
173 } finally {
174 db.setForeignKeyConstraintsEnabled(true)
175
176 // We have to re-begin the transaction for the calling code (see comment at start of method)
177 db.beginTransaction()
178 }
179
180 SignalDatabaseMigrations.migratePostTransaction(context, oldVersion)
181 Log.i(TAG, "Upgrade complete. Took " + (System.currentTimeMillis() - startTime) + " ms.")
182 }
183
184 override fun getReadableDatabase(): net.zetetic.database.sqlcipher.SQLiteDatabase {
185 throw UnsupportedOperationException("Call getSignalReadableDatabase() instead!")
186 }
187
188 override fun getWritableDatabase(): net.zetetic.database.sqlcipher.SQLiteDatabase {
189 throw UnsupportedOperationException("Call getSignalWritableDatabase() instead!")
190 }
191
192 open val rawReadableDatabase: net.zetetic.database.sqlcipher.SQLiteDatabase
193 get() = super.getReadableDatabase()
194
195 open val rawWritableDatabase: net.zetetic.database.sqlcipher.SQLiteDatabase
196 get() = super.getWritableDatabase()
197
198 open val signalReadableDatabase: SQLiteDatabase
199 get() = SQLiteDatabase(super.getReadableDatabase())
200
201 open val signalWritableDatabase: SQLiteDatabase
202 get() = SQLiteDatabase(super.getWritableDatabase())
203
204 override fun getSqlCipherDatabase(): net.zetetic.database.sqlcipher.SQLiteDatabase {
205 return super.getWritableDatabase()
206 }
207
208 open fun markCurrent(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
209 db.version = SignalDatabaseMigrations.DATABASE_VERSION
210 }
211
212 private fun executeStatements(db: net.zetetic.database.sqlcipher.SQLiteDatabase, statements: Array<String>) {
213 for (statement in statements) db.execSQL(statement)
214 }
215
216 companion object {
217 private val TAG = Log.tag(SignalDatabase::class.java)
218 private const val DATABASE_NAME = "signal.db"
219
220 @JvmStatic
221 @Volatile
222 var instance: SignalDatabase? = null
223 private set
224
225 @JvmStatic
226 fun init(application: Application, databaseSecret: DatabaseSecret, attachmentSecret: AttachmentSecret) {
227 if (instance == null) {
228 synchronized(SignalDatabase::class.java) {
229 if (instance == null) {
230 instance = SignalDatabase(application, databaseSecret, attachmentSecret)
231 }
232 }
233 }
234 }
235
236 @JvmStatic
237 @VisibleForTesting
238 fun setSignalDatabaseInstanceForTesting(signalDatabase: SignalDatabase) {
239 this.instance = signalDatabase
240 }
241
242 @JvmStatic
243 val rawDatabase: net.zetetic.database.sqlcipher.SQLiteDatabase
244 get() = instance!!.rawWritableDatabase
245
246 @JvmStatic
247 val backupDatabase: net.zetetic.database.sqlcipher.SQLiteDatabase
248 get() = instance!!.rawReadableDatabase
249
250 @JvmStatic
251 @get:JvmName("inTransaction")
252 val inTransaction: Boolean
253 get() = instance!!.rawWritableDatabase.inTransaction()
254
255 @JvmStatic
256 fun runPostSuccessfulTransaction(dedupeKey: String, task: Runnable) {
257 instance!!.signalWritableDatabase.runPostSuccessfulTransaction(dedupeKey, task)
258 }
259
260 @JvmStatic
261 fun runPostSuccessfulTransaction(task: Runnable) {
262 instance!!.signalWritableDatabase.runPostSuccessfulTransaction(task)
263 }
264
265 @JvmStatic
266 fun databaseFileExists(context: Context): Boolean {
267 return context.getDatabasePath(DATABASE_NAME).exists()
268 }
269
270 @JvmStatic
271 fun getDatabaseFile(context: Context): File {
272 return context.getDatabasePath(DATABASE_NAME)
273 }
274
275 /**
276 * After restoring a backup, we want to make sure that we run all of the onUpgrade logic necessary to bring the databases up to our current versions.
277 * There's also some cleanup we wan tto do to remove any possibly bad/stale data.
278 */
279 @JvmStatic
280 fun runPostBackupRestoreTasks(database: net.zetetic.database.sqlcipher.SQLiteDatabase) {
281 synchronized(SignalDatabase::class.java) {
282 database.setForeignKeyConstraintsEnabled(false)
283 database.beginTransaction()
284 try {
285 instance!!.onUpgrade(database, database.getVersion(), -1)
286 instance!!.markCurrent(database)
287 instance!!.messageTable.deleteAbandonedMessages()
288 instance!!.messageTable.trimEntriesForExpiredMessages()
289 instance!!.reactionTable.deleteAbandonedReactions()
290 instance!!.searchTable.fullyResetTables()
291 instance!!.rawWritableDatabase.execSQL("DROP TABLE IF EXISTS key_value")
292 instance!!.rawWritableDatabase.execSQL("DROP TABLE IF EXISTS megaphone")
293 instance!!.rawWritableDatabase.execSQL("DROP TABLE IF EXISTS job_spec")
294 instance!!.rawWritableDatabase.execSQL("DROP TABLE IF EXISTS constraint_spec")
295 instance!!.rawWritableDatabase.execSQL("DROP TABLE IF EXISTS dependency_spec")
296 database.setTransactionSuccessful()
297 } finally {
298 database.endTransaction()
299 database.setForeignKeyConstraintsEnabled(true)
300 }
301
302 instance!!.rawWritableDatabase.close()
303 triggerDatabaseAccess()
304 }
305 }
306
307 @JvmStatic
308 fun hasTable(table: String): Boolean {
309 return SqlUtil.tableExists(instance!!.rawReadableDatabase, table)
310 }
311
312 @JvmStatic
313 fun triggerDatabaseAccess() {
314 instance!!.signalWritableDatabase
315 }
316
317 @Deprecated("Only used for a legacy migration.")
318 @JvmStatic
319 fun onApplicationLevelUpgrade(
320 context: Context,
321 masterSecret: MasterSecret,
322 fromVersion: Int,
323 listener: DatabaseUpgradeListener?
324 ) {
325 instance!!.signalWritableDatabase
326 var legacyOpenHelper: ClassicOpenHelper? = null
327 if (fromVersion < LegacyMigrationJob.ASYMMETRIC_MASTER_SECRET_FIX_VERSION) {
328 legacyOpenHelper = ClassicOpenHelper(context)
329 legacyOpenHelper.onApplicationLevelUpgrade(context, masterSecret, fromVersion, listener)
330 }
331
332 if (fromVersion < LegacyMigrationJob.SQLCIPHER && TextSecurePreferences.getNeedsSqlCipherMigration(context)) {
333 if (legacyOpenHelper == null) {
334 legacyOpenHelper = ClassicOpenHelper(context)
335 }
336
337 SQLCipherMigrationHelper.migrateCiphertext(
338 context,
339 masterSecret,
340 legacyOpenHelper.writableDatabase,
341 instance!!.rawWritableDatabase,
342 listener
343 )
344 }
345 }
346
347 @JvmStatic
348 fun <T> runInTransaction(block: (SQLiteDatabase) -> T): T {
349 return instance!!.signalWritableDatabase.withinTransaction {
350 block(it)
351 }
352 }
353
354 @get:JvmStatic
355 @get:JvmName("attachments")
356 val attachments: AttachmentTable
357 get() = instance!!.attachmentTable
358
359 @get:JvmStatic
360 @get:JvmName("avatarPicker")
361 val avatarPicker: AvatarPickerDatabase
362 get() = instance!!.avatarPickerDatabase
363
364 @get:JvmStatic
365 @get:JvmName("cds")
366 val cds: CdsTable
367 get() = instance!!.cdsTable
368
369 @get:JvmStatic
370 @get:JvmName("chatColors")
371 val chatColors: ChatColorsTable
372 get() = instance!!.chatColorsTable
373
374 @get:JvmStatic
375 @get:JvmName("distributionLists")
376 val distributionLists: DistributionListTables
377 get() = instance!!.distributionListTables
378
379 @get:JvmStatic
380 @get:JvmName("donationReceipts")
381 val donationReceipts: DonationReceiptTable
382 get() = instance!!.donationReceiptTable
383
384 @get:JvmStatic
385 @get:JvmName("drafts")
386 val drafts: DraftTable
387 get() = instance!!.draftTable
388
389 @get:JvmStatic
390 @get:JvmName("emojiSearch")
391 val emojiSearch: EmojiSearchTable
392 get() = instance!!.emojiSearchTable
393
394 @get:JvmStatic
395 @get:JvmName("groupReceipts")
396 val groupReceipts: GroupReceiptTable
397 get() = instance!!.groupReceiptTable
398
399 @get:JvmStatic
400 @get:JvmName("groups")
401 val groups: GroupTable
402 get() = instance!!.groupTable
403
404 @get:JvmStatic
405 @get:JvmName("identities")
406 val identities: IdentityTable
407 get() = instance!!.identityTable
408
409 @get:JvmStatic
410 @get:JvmName("kyberPreKeys")
411 val kyberPreKeys: KyberPreKeyTable
412 get() = instance!!.kyberPreKeyTable
413
414 @get:JvmStatic
415 @get:JvmName("media")
416 val media: MediaTable
417 get() = instance!!.mediaTable
418
419 @get:JvmStatic
420 @get:JvmName("mentions")
421 val mentions: MentionTable
422 get() = instance!!.mentionTable
423
424 @get:JvmStatic
425 @get:JvmName("messages")
426 val messages: MessageTable
427 get() = instance!!.messageTable
428
429 @get:JvmStatic
430 @get:JvmName("messageLog")
431 val messageLog: MessageSendLogTables
432 get() = instance!!.messageSendLogTables
433
434 @get:JvmStatic
435 @get:JvmName("messageSearch")
436 val messageSearch: SearchTable
437 get() = instance!!.searchTable
438
439 @get:JvmStatic
440 @get:JvmName("notificationProfiles")
441 val notificationProfiles: NotificationProfileDatabase
442 get() = instance!!.notificationProfileDatabase
443
444 @get:JvmStatic
445 @get:JvmName("payments")
446 val payments: PaymentTable
447 get() = instance!!.paymentTable
448
449 @get:JvmStatic
450 @get:JvmName("pendingRetryReceipts")
451 val pendingRetryReceipts: PendingRetryReceiptTable
452 get() = instance!!.pendingRetryReceiptTable
453
454 @get:JvmStatic
455 @get:JvmName("oneTimePreKeys")
456 val oneTimePreKeys: OneTimePreKeyTable
457 get() = instance!!.preKeyDatabase
458
459 @get:JvmStatic
460 @get:JvmName("pendingPniSignatureMessages")
461 val pendingPniSignatureMessages: PendingPniSignatureMessageTable
462 get() = instance!!.pendingPniSignatureMessageTable
463
464 @get:JvmStatic
465 @get:JvmName("recipients")
466 val recipients: RecipientTable
467 get() = instance!!.recipientTable
468
469 @get:JvmStatic
470 @get:JvmName("signedPreKeys")
471 val signedPreKeys: SignedPreKeyTable
472 get() = instance!!.signedPreKeyTable
473
474 @get:JvmStatic
475 @get:JvmName("threads")
476 val threads: ThreadTable
477 get() = instance!!.threadTable
478
479 @get:JvmStatic
480 @get:JvmName("reactions")
481 val reactions: ReactionTable
482 get() = instance!!.reactionTable
483
484 @get:JvmStatic
485 @get:JvmName("remappedRecords")
486 val remappedRecords: RemappedRecordTables
487 get() = instance!!.remappedRecordTables
488
489 @get:JvmStatic
490 @get:JvmName("senderKeys")
491 val senderKeys: SenderKeyTable
492 get() = instance!!.senderKeyTable
493
494 @get:JvmStatic
495 @get:JvmName("senderKeyShared")
496 val senderKeyShared: SenderKeySharedTable
497 get() = instance!!.senderKeySharedTable
498
499 @get:JvmStatic
500 @get:JvmName("sessions")
501 val sessions: SessionTable
502 get() = instance!!.sessionTable
503
504 @get:JvmStatic
505 @get:JvmName("stickers")
506 val stickers: StickerTable
507 get() = instance!!.stickerTable
508
509 @get:JvmStatic
510 @get:JvmName("storySends")
511 val storySends: StorySendTable
512 get() = instance!!.storySendTable
513
514 @get:JvmStatic
515 @get:JvmName("unknownStorageIds")
516 val unknownStorageIds: UnknownStorageIdTable
517 get() = instance!!.storageIdDatabase
518
519 @get:JvmStatic
520 @get:JvmName("remoteMegaphones")
521 val remoteMegaphones: RemoteMegaphoneTable
522 get() = instance!!.remoteMegaphoneTable
523
524 @get:JvmStatic
525 @get:JvmName("calls")
526 val calls: CallTable
527 get() = instance!!.callTable
528
529 @get:JvmStatic
530 @get:JvmName("callLinks")
531 val callLinks: CallLinkTable
532 get() = instance!!.callLinkTable
533 }
534 // TM_SA implement IDatabase start
535 override fun beginTransaction() {}
536
537 override fun endTransaction() {}
538
539 override fun isInTransaction(): Boolean = false
540
541 override fun messageDao(): IArchiveMessageDao<Long> = messageTable as TeleMessageTable
542
543 override fun setTransactionSuccessful() {}
544 // TM_SA implement IDatabase end
545}