mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Ensure owned call links are revoked on delete.
This commit is contained in:
committed by
Cody Henthorne
parent
03a212eee4
commit
290b0fe46f
@@ -6,6 +6,7 @@ import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
import org.signal.core.util.Serializer
|
||||
import org.signal.core.util.SqlUtil
|
||||
import org.signal.core.util.delete
|
||||
import org.signal.core.util.insertInto
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.readToList
|
||||
@@ -32,7 +33,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkState
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
@@ -221,6 +221,64 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteNonAdminCallLinks(roomIds: Set<CallLinkRoomId>) {
|
||||
val queries = SqlUtil.buildCollectionQuery(ROOM_ID, roomIds)
|
||||
|
||||
queries.forEach {
|
||||
writableDatabase.delete(TABLE_NAME)
|
||||
.where("${it.where} AND $ADMIN_KEY IS NULL", it.whereArgs)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
|
||||
fun getAdminCallLinks(roomIds: Set<CallLinkRoomId>): Set<CallLink> {
|
||||
val queries = SqlUtil.buildCollectionQuery(ROOM_ID, roomIds)
|
||||
|
||||
return queries.map {
|
||||
writableDatabase
|
||||
.select()
|
||||
.from(TABLE_NAME)
|
||||
.where("${it.where} AND $ADMIN_KEY IS NOT NULL", it.whereArgs)
|
||||
.run()
|
||||
.readToList { CallLinkDeserializer.deserialize(it) }
|
||||
}.flatten().toSet()
|
||||
}
|
||||
|
||||
fun deleteAllNonAdminCallLinksExcept(roomIds: Set<CallLinkRoomId>) {
|
||||
if (roomIds.isEmpty()) {
|
||||
writableDatabase.delete(TABLE_NAME)
|
||||
.where("$ADMIN_KEY IS NULL")
|
||||
.run()
|
||||
} else {
|
||||
SqlUtil.buildCollectionQuery(ROOM_ID, roomIds, collectionOperator = SqlUtil.CollectionOperator.NOT_IN).forEach {
|
||||
writableDatabase.delete(TABLE_NAME)
|
||||
.where("${it.where} AND $ADMIN_KEY IS NULL", it.whereArgs)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllAdminCallLinksExcept(roomIds: Set<CallLinkRoomId>): Set<CallLink> {
|
||||
return if (roomIds.isEmpty()) {
|
||||
writableDatabase
|
||||
.select()
|
||||
.from(TABLE_NAME)
|
||||
.where("$ADMIN_KEY IS NOT NULL")
|
||||
.run()
|
||||
.readToList { CallLinkDeserializer.deserialize(it) }
|
||||
.toSet()
|
||||
} else {
|
||||
SqlUtil.buildCollectionQuery(ROOM_ID, roomIds, collectionOperator = SqlUtil.CollectionOperator.NOT_IN).map {
|
||||
writableDatabase
|
||||
.select()
|
||||
.from(TABLE_NAME)
|
||||
.where("${it.where} AND $ADMIN_KEY IS NOT NULL", it.whereArgs)
|
||||
.run()
|
||||
.readToList { CallLinkDeserializer.deserialize(it) }
|
||||
}.flatten().toSet()
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryCallLinks(query: String?, offset: Int, limit: Int, asCount: Boolean): Cursor {
|
||||
//language=sql
|
||||
val noCallEvent = """
|
||||
@@ -289,7 +347,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
override fun deserialize(data: Cursor): CallLink {
|
||||
return CallLink(
|
||||
recipientId = data.requireLong(RECIPIENT_ID).let { if (it > 0) RecipientId.from(it) else RecipientId.UNKNOWN },
|
||||
roomId = CallLinkRoomId.fromBytes(Base64.decode(data.requireNonNullString(ROOM_ID))),
|
||||
roomId = CallLinkRoomId.DatabaseSerializer.deserialize(data.requireNonNullString(ROOM_ID)),
|
||||
credentials = CallLinkCredentials(
|
||||
linkKeyBytes = data.requireNonNullBlob(ROOT_KEY),
|
||||
adminPassBytes = data.requireBlob(ADMIN_KEY)
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.CallSyncEventJob
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent
|
||||
import java.util.UUID
|
||||
@@ -207,6 +208,48 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
||||
.run()
|
||||
}
|
||||
|
||||
fun getCallLinkRoomIdsFromCallRowIds(callRowIds: Set<Long>): Set<CallLinkRoomId> {
|
||||
return SqlUtil.buildCollectionQuery("$TABLE_NAME.$ID", callRowIds).map { query ->
|
||||
//language=sql
|
||||
val statement = """
|
||||
SELECT ${CallLinkTable.ROOM_ID} FROM $TABLE_NAME
|
||||
INNER JOIN ${CallLinkTable.TABLE_NAME} ON ${CallLinkTable.TABLE_NAME}.${CallLinkTable.RECIPIENT_ID} = $PEER
|
||||
WHERE $TYPE = ${Type.serialize(Type.AD_HOC_CALL)} AND ${query.where}
|
||||
""".toSingleLine()
|
||||
|
||||
readableDatabase.query(statement, query.whereArgs).readToList {
|
||||
CallLinkRoomId.DatabaseSerializer.deserialize(it.requireNonNullString(CallLinkTable.ROOM_ID))
|
||||
}
|
||||
}.flatten().toSet()
|
||||
}
|
||||
|
||||
/**
|
||||
* If a call link has been revoked, or if we do not have a CallLink table entry for an AD_HOC_CALL type
|
||||
* event, we mark it deleted.
|
||||
*/
|
||||
fun updateAdHocCallEventDeletionTimestamps() {
|
||||
//language=sql
|
||||
val statement = """
|
||||
UPDATE $TABLE_NAME
|
||||
SET $DELETION_TIMESTAMP = ${System.currentTimeMillis()}, $EVENT = ${Event.serialize(Event.DELETE)}
|
||||
WHERE $TYPE = ${Type.serialize(Type.AD_HOC_CALL)}
|
||||
AND (
|
||||
(NOT EXISTS (SELECT 1 FROM ${CallLinkTable.TABLE_NAME} WHERE ${CallLinkTable.RECIPIENT_ID} = $PEER))
|
||||
OR
|
||||
(SELECT ${CallLinkTable.REVOKED} FROM ${CallLinkTable.TABLE_NAME} WHERE ${CallLinkTable.RECIPIENT_ID} = $PEER)
|
||||
)
|
||||
RETURNING *
|
||||
""".toSingleLine()
|
||||
|
||||
val toSync = writableDatabase.query(statement).readToList {
|
||||
Call.deserialize(it)
|
||||
}.toSet()
|
||||
|
||||
CallSyncEventJob.enqueueDeleteSyncEvents(toSync)
|
||||
ApplicationDependencies.getDeletedCallEventManager().scheduleIfNecessary()
|
||||
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||
}
|
||||
|
||||
/**
|
||||
* If a non-ad-hoc call has been deleted from the message database, then we need to
|
||||
* set its deletion_timestamp to now.
|
||||
@@ -706,13 +749,13 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
||||
.run()
|
||||
}
|
||||
|
||||
fun deleteCallEvents(callRowIds: Set<Long>) {
|
||||
fun deleteNonAdHocCallEvents(callRowIds: Set<Long>) {
|
||||
val messageIds = getMessageIds(callRowIds)
|
||||
SignalDatabase.messages.deleteCallUpdates(messageIds)
|
||||
updateCallEventDeletionTimestamps()
|
||||
}
|
||||
|
||||
fun deleteAllCallEventsExcept(callRowIds: Set<Long>, missedOnly: Boolean) {
|
||||
fun deleteAllNonAdHocCallEventsExcept(callRowIds: Set<Long>, missedOnly: Boolean) {
|
||||
val callFilter = if (missedOnly) {
|
||||
"$EVENT = ${Event.serialize(Event.MISSED)} AND $DELETION_TIMESTAMP = 0"
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user