diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/DistributionListTablesArchiveExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/DistributionListTablesArchiveExtensions.kt index aa5e66dd06..f47f786c4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/DistributionListTablesArchiveExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/DistributionListTablesArchiveExtensions.kt @@ -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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt index 0afc5e63e7..32cf135c27 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt @@ -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 null } + if (mention == null && style == null) { + return emptyList() + } + BackupBodyRange( start = it.start, length = it.length, @@ -1589,7 +1598,7 @@ private fun ExecutorService.submitTyped(callable: Callable): Future { 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.repairRevisions(current: ChatItem.Builder): List { return if (current.standardMessage != null) { val filtered = this diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt index a48499da3a..94098e59a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt @@ -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, 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.toRemoteMemberList(selfRecipientId: RecipientId): List { +private fun List.toRemoteMemberList(selfRecipientId: RecipientId, exportState: ExportState): List { 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 } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt index d9e987ba02..dba0083de6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt @@ -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))