Signal-Android/app/src/main/java/org/thoughtcrime/securesms/database/PendingPniSignatureMessageD...

108 wiersze
3.7 KiB
Kotlin

package org.thoughtcrime.securesms.database
import android.content.Context
import androidx.core.content.contentValuesOf
import org.signal.core.util.delete
import org.signal.core.util.exists
import org.signal.core.util.logging.Log
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.FeatureFlags
import org.whispersystems.signalservice.api.messages.SendMessageResult
/**
* Contains records of messages that have been sent with PniSignatures on them.
* When we receive delivery receipts for these messages, we remove entries from the table and can clear
* the `needsPniSignature` flag on the recipient when all are delivered.
*/
class PendingPniSignatureMessageDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
companion object {
private val TAG = Log.tag(PendingPniSignatureMessageDatabase::class.java)
const val TABLE_NAME = "pending_pni_signature_message"
private const val ID = "_id"
private const val RECIPIENT_ID = "recipient_id"
private const val SENT_TIMESTAMP = "sent_timestamp"
private const val DEVICE_ID = "device_id"
const val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY,
$RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientDatabase.TABLE_NAME} (${RecipientDatabase.ID}) ON DELETE CASCADE,
$SENT_TIMESTAMP INTEGER NOT NULL,
$DEVICE_ID INTEGER NOT NULL
)
"""
val CREATE_INDEXES = arrayOf(
"CREATE UNIQUE INDEX pending_pni_recipient_sent_device_index ON $TABLE_NAME ($RECIPIENT_ID, $SENT_TIMESTAMP, $DEVICE_ID)"
)
}
fun insertIfNecessary(recipientId: RecipientId, sentTimestamp: Long, result: SendMessageResult) {
if (!FeatureFlags.phoneNumberPrivacy()) return
if (!result.isSuccess) {
return
}
writableDatabase.withinTransaction { db ->
for (deviceId in result.success.devices) {
val values = contentValuesOf(
RECIPIENT_ID to recipientId.serialize(),
SENT_TIMESTAMP to sentTimestamp,
DEVICE_ID to deviceId
)
db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE)
}
}
}
fun acknowledgeReceipts(recipientId: RecipientId, sentTimestamps: Collection<Long>, deviceId: Int) {
if (!FeatureFlags.phoneNumberPrivacy()) return
writableDatabase.withinTransaction { db ->
val count = db
.delete(TABLE_NAME)
.where("$RECIPIENT_ID = ? AND $SENT_TIMESTAMP IN (?) AND $DEVICE_ID = ?", recipientId, sentTimestamps.joinToString(separator = ","), deviceId)
.run()
if (count <= 0) {
return@withinTransaction
}
val stillPending: Boolean = db.exists(TABLE_NAME, "$RECIPIENT_ID = ? AND $SENT_TIMESTAMP = ?", recipientId, sentTimestamps)
if (!stillPending) {
Log.i(TAG, "All devices for ($recipientId, $sentTimestamps) have acked the PNI signature message. Clearing flag and removing any other pending receipts.")
SignalDatabase.recipients.clearNeedsPniSignature(recipientId)
db
.delete(TABLE_NAME)
.where("$RECIPIENT_ID = ?", recipientId)
.run()
}
}
}
/**
* Deletes all record of pending PNI verification messages. Should only be called after the user changes their number.
*/
fun deleteAll() {
if (!FeatureFlags.phoneNumberPrivacy()) return
writableDatabase.delete(TABLE_NAME).run()
}
fun remapRecipient(oldId: RecipientId, newId: RecipientId) {
writableDatabase
.update(TABLE_NAME)
.values(RECIPIENT_ID to newId.serialize())
.where("$RECIPIENT_ID = ?", oldId)
.run()
}
}