From aec46306bbeabf2ff3aeccb5b0e002dcfeb4e9dd Mon Sep 17 00:00:00 2001 From: Harry <109690906+harry-signal@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:47:54 -0700 Subject: [PATCH] Tombstone unviewed view-once messages in remote backups --- .../BackupArchiveTSMessageContentsArchiver.swift | 11 +++++++---- .../Backups/Archiving/BackupArchive+Contexts.swift | 4 ++++ .../Backups/Archiving/BackupArchiveManagerImpl.swift | 9 +++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/SignalServiceKit/Backups/Archiving/Archivers/ChatItem/BackupArchiveTSMessageContentsArchiver.swift b/SignalServiceKit/Backups/Archiving/Archivers/ChatItem/BackupArchiveTSMessageContentsArchiver.swift index cb45797907..ed420b329c 100644 --- a/SignalServiceKit/Backups/Archiving/Archivers/ChatItem/BackupArchiveTSMessageContentsArchiver.swift +++ b/SignalServiceKit/Backups/Archiving/Archivers/ChatItem/BackupArchiveTSMessageContentsArchiver.swift @@ -185,7 +185,7 @@ class BackupArchiveTSMessageContentsArchiver: BackupArchiveProtoStreamWriter { return archiveViewOnceMessage( message, messageRowId: messageRowId, - context: context.recipientContext + context: context ) } else if message.isStoryReply && !message.isGroupStoryReply { return archiveDirectStoryReplyMessage( @@ -792,13 +792,16 @@ class BackupArchiveTSMessageContentsArchiver: BackupArchiveProtoStreamWriter { private func archiveViewOnceMessage( _ message: TSMessage, messageRowId: Int64, - context: BackupArchive.RecipientArchivingContext + context: BackupArchive.ChatArchivingContext ) -> ArchiveInteractionResult { var partialErrors = [ArchiveFrameError]() var proto = BackupProto_ViewOnceMessage() - if !message.isViewOnceComplete { + if + !context.includedContentFilter.shouldTombstoneViewOnce, + !message.isViewOnceComplete + { let attachmentResult = attachmentsArchiver.archiveBodyAttachments( messageId: message.uniqueInteractionId, messageRowId: messageRowId, @@ -827,7 +830,7 @@ class BackupArchiveTSMessageContentsArchiver: BackupArchiveProtoStreamWriter { let reactions: [BackupProto_Reaction] let reactionsResult = reactionArchiver.archiveReactions( message, - context: context + context: context.recipientContext ) switch reactionsResult.bubbleUp(ChatItemType.self, partialErrors: &partialErrors) { case .continue(let values): diff --git a/SignalServiceKit/Backups/Archiving/BackupArchive+Contexts.swift b/SignalServiceKit/Backups/Archiving/BackupArchive+Contexts.swift index b8ddeb82b0..462d35c772 100644 --- a/SignalServiceKit/Backups/Archiving/BackupArchive+Contexts.swift +++ b/SignalServiceKit/Backups/Archiving/BackupArchive+Contexts.swift @@ -34,6 +34,10 @@ extension BackupArchive { /// "lifetime" was. let minRemainingTimeUntilExpirationMs: UInt64 + /// Unviewed view-once messages should be treated as viewed and + /// tombstoned for this export. + let shouldTombstoneViewOnce: Bool + /// Whether or not the plaintext SVR PIN should be included. let shouldIncludePin: Bool } diff --git a/SignalServiceKit/Backups/Archiving/BackupArchiveManagerImpl.swift b/SignalServiceKit/Backups/Archiving/BackupArchiveManagerImpl.swift index a5b829cd3b..17e1659633 100644 --- a/SignalServiceKit/Backups/Archiving/BackupArchiveManagerImpl.swift +++ b/SignalServiceKit/Backups/Archiving/BackupArchiveManagerImpl.swift @@ -232,6 +232,14 @@ public class BackupArchiveManagerImpl: BackupArchiveManager { return .dayInMs } }(), + shouldTombstoneViewOnce: { + switch backupPurpose { + case .deviceTransfer: + return false + case .remoteBackup: + return true + } + }(), shouldIncludePin: true ) @@ -268,6 +276,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager { let includedContentFilter = BackupArchive.ArchivingContext.IncludedContentFilter( minExpirationTimeMs: 0, minRemainingTimeUntilExpirationMs: 0, + shouldTombstoneViewOnce: false, shouldIncludePin: true )