mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-21 10:17:56 +00:00
Add protections around exporting unknown recipients in dlists.
This commit is contained in:
committed by
Michelle Tang
parent
107ee5268e
commit
765c1eeab0
@@ -7,19 +7,20 @@ package org.thoughtcrime.securesms.backup.v2.database
|
||||
|
||||
import org.signal.core.util.select
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
||||
import org.thoughtcrime.securesms.backup.v2.exporters.DistributionListArchiveExporter
|
||||
import org.thoughtcrime.securesms.database.DistributionListTables
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListId
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
||||
fun DistributionListTables.getAllForBackup(selfRecipientId: RecipientId): DistributionListArchiveExporter {
|
||||
fun DistributionListTables.getAllForBackup(selfRecipientId: RecipientId, exportState: ExportState): DistributionListArchiveExporter {
|
||||
val cursor = readableDatabase
|
||||
.select()
|
||||
.from(DistributionListTables.ListTable.TABLE_NAME)
|
||||
.run()
|
||||
|
||||
return DistributionListArchiveExporter(cursor, this, selfRecipientId)
|
||||
return DistributionListArchiveExporter(cursor, this, selfRecipientId, exportState)
|
||||
}
|
||||
|
||||
fun DistributionListTables.getMembersForBackup(id: DistributionListId): List<RecipientId> {
|
||||
|
||||
@@ -317,6 +317,11 @@ class ChatItemArchiveExporter(
|
||||
}
|
||||
|
||||
MessageTypes.isGroupV2(record.type) && MessageTypes.isGroupUpdate(record.type) -> {
|
||||
if (builder.authorId != selfRecipientId.toLong() && exportState.recipientIdToAci[builder.authorId] == null) {
|
||||
Log.w(TAG, ExportSkips.groupUpdateHasInvalidAuthor(record.dateSent))
|
||||
continue
|
||||
}
|
||||
|
||||
val update = record.toRemoteGroupUpdate() ?: continue
|
||||
if (update.groupChange!!.updates.isEmpty()) {
|
||||
Log.w(TAG, ExportSkips.groupUpdateHasNoUpdates(record.dateSent))
|
||||
@@ -430,7 +435,7 @@ class ChatItemArchiveExporter(
|
||||
|
||||
if (record.latestRevisionId == null) {
|
||||
builder.revisions = revisionMap.remove(record.id)?.repairRevisions(builder) ?: emptyList()
|
||||
val chatItem = builder.build().validateChatItem(exportState) ?: continue
|
||||
val chatItem = builder.build().validateChatItem(exportState, selfRecipientId) ?: continue
|
||||
buffer += chatItem
|
||||
} else {
|
||||
var previousEdits = revisionMap[record.latestRevisionId]
|
||||
@@ -1340,6 +1345,10 @@ private fun ByteArray.toRemoteBodyRanges(dateSent: Long): List<BackupBodyRange>
|
||||
null
|
||||
}
|
||||
|
||||
if (mention == null && style == null) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
BackupBodyRange(
|
||||
start = it.start,
|
||||
length = it.length,
|
||||
@@ -1589,7 +1598,7 @@ private fun <T> ExecutorService.submitTyped(callable: Callable<T>): Future<T> {
|
||||
return this.submit(callable)
|
||||
}
|
||||
|
||||
private fun ChatItem.validateChatItem(exportState: ExportState): ChatItem? {
|
||||
private fun ChatItem.validateChatItem(exportState: ExportState, selfRecipientId: RecipientId): ChatItem? {
|
||||
if (this.standardMessage == null &&
|
||||
this.contactMessage == null &&
|
||||
this.stickerMessage == null &&
|
||||
@@ -1610,6 +1619,16 @@ private fun ChatItem.validateChatItem(exportState: ExportState): ChatItem? {
|
||||
return null
|
||||
}
|
||||
|
||||
if (this.updateMessage != null && this.updateMessage.canOnlyBeAuthoredBySelf() && this.authorId != selfRecipientId.toLong()) {
|
||||
Log.w(TAG, ExportSkips.individualChatUpdateNotAuthoredBySelf(this.dateSent))
|
||||
return null
|
||||
}
|
||||
|
||||
if (this.incoming != null && exportState.recipientIdToAci[this.authorId] == null && exportState.recipientIdToE164[this.authorId] == null) {
|
||||
Log.w(TAG, ExportSkips.incomingMessageAuthorDoesNotHaveAciOrE164(this.dateSent))
|
||||
return null
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -1621,6 +1640,13 @@ private fun ChatUpdateMessage.isOnlyForIndividualChats(): Boolean {
|
||||
this.simpleUpdate?.type == SimpleChatUpdate.Type.PAYMENTS_ACTIVATED
|
||||
}
|
||||
|
||||
private fun ChatUpdateMessage.canOnlyBeAuthoredBySelf(): Boolean {
|
||||
return this.simpleUpdate?.type == SimpleChatUpdate.Type.REPORTED_SPAM ||
|
||||
this.simpleUpdate?.type == SimpleChatUpdate.Type.MESSAGE_REQUEST_ACCEPTED ||
|
||||
this.simpleUpdate?.type == SimpleChatUpdate.Type.BLOCKED ||
|
||||
this.simpleUpdate?.type == SimpleChatUpdate.Type.UNBLOCKED
|
||||
}
|
||||
|
||||
private fun List<ChatItem>.repairRevisions(current: ChatItem.Builder): List<ChatItem> {
|
||||
return if (current.standardMessage != null) {
|
||||
val filtered = this
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.requireObject
|
||||
import org.thoughtcrime.securesms.backup.v2.ArchiveRecipient
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportOddities
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getMembersForBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.DistributionList
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.DistributionListItem
|
||||
@@ -32,7 +33,8 @@ private val TAG = Log.tag(DistributionListArchiveExporter::class)
|
||||
class DistributionListArchiveExporter(
|
||||
private val cursor: Cursor,
|
||||
private val distributionListTables: DistributionListTables,
|
||||
private val selfRecipientId: RecipientId
|
||||
private val selfRecipientId: RecipientId,
|
||||
private val exportState: ExportState
|
||||
) : Iterator<ArchiveRecipient>, Closeable {
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
@@ -66,7 +68,7 @@ class DistributionListArchiveExporter(
|
||||
deletionTimestamp = record.deletedAtTimestamp
|
||||
)
|
||||
} else {
|
||||
val members = record.members.toRemoteMemberList(selfRecipientId)
|
||||
val members = record.members.toRemoteMemberList(selfRecipientId, exportState)
|
||||
DistributionListItem(
|
||||
distributionId = record.distributionId.asUuid().toByteArray().toByteString(),
|
||||
distributionList = DistributionList(
|
||||
@@ -104,10 +106,11 @@ private fun DistributionListPrivacyMode.toBackupPrivacyMode(memberCount: Int): D
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<RecipientId>.toRemoteMemberList(selfRecipientId: RecipientId): List<Long> {
|
||||
private fun List<RecipientId>.toRemoteMemberList(selfRecipientId: RecipientId, exportState: ExportState): List<Long> {
|
||||
val filtered = this.filter { it != selfRecipientId }.map { it.toLong() }
|
||||
if (filtered.size != this.size) {
|
||||
Log.w(TAG, ExportOddities.distributionListHadSelfAsMember())
|
||||
}
|
||||
return filtered
|
||||
|
||||
return filtered.filter { exportState.recipientIdToAci[it] != null || exportState.recipientIdToE164[it] != null }
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ object RecipientArchiveProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
db.distributionListTables.getAllForBackup(selfRecipientId).use { reader ->
|
||||
db.distributionListTables.getAllForBackup(selfRecipientId, exportState).use { reader ->
|
||||
for (recipient in reader) {
|
||||
exportState.recipientIds.add(recipient.id)
|
||||
emitter.emit(Frame(recipient = recipient))
|
||||
|
||||
Reference in New Issue
Block a user