diff --git a/SignalServiceKit/MessageBackup/Archivers/ChatItem/MessageBackupTSMessageEditHistoryArchiver.swift b/SignalServiceKit/MessageBackup/Archivers/ChatItem/MessageBackupTSMessageEditHistoryArchiver.swift index d9d1c0165e..fee001c82c 100644 --- a/SignalServiceKit/MessageBackup/Archivers/ChatItem/MessageBackupTSMessageEditHistoryArchiver.swift +++ b/SignalServiceKit/MessageBackup/Archivers/ChatItem/MessageBackupTSMessageEditHistoryArchiver.swift @@ -161,6 +161,39 @@ final class MessageBackupTSMessageEditHistoryArchiver context: MessageBackup.ChatArchivingContext, builder: Builder ) -> MessageBackup.ArchiveInteractionResult { + let unexpectedRevisionsMessageType: ArchiveFrameError.ErrorType.UnexpectedRevisionsMessageType? + switch latestRevisionDetails.chatItemType { + case .remoteDeletedMessage: + // Remote-deleted messages with edit history delete the contents of + // their prior revisions, but leave the revisions around as + // placeholders. We don't want to archive those, nor do we need to + // produce an error, so we bail early. + return .success(()) + case .standardMessage, .directStoryReplyMessage: + // These message types are the only ones expected/allowed to have + // edit history we want to archive. If we unexpectedly find it on + // another message type, we'll drop it and record an error. + unexpectedRevisionsMessageType = nil + case .contactMessage: + unexpectedRevisionsMessageType = .contactMessgae + case .stickerMessage: + unexpectedRevisionsMessageType = .stickerMessage + case .updateMessage: + unexpectedRevisionsMessageType = .updateMessage + case .paymentNotification: + unexpectedRevisionsMessageType = .paymentNotification + case .giftBadge: + unexpectedRevisionsMessageType = .giftBadge + case .viewOnceMessage: + unexpectedRevisionsMessageType = .viewOnceMessage + } + if let unexpectedRevisionsMessageType { + return .partialFailure((), [.archiveFrameError( + .unexpectedRevisionsOnMessage(unexpectedRevisionsMessageType), + latestRevisionMessage.uniqueInteractionId + )]) + } + var partialErrors = [ArchiveFrameError]() /// The edit history, from oldest revision to newest. This ordering diff --git a/SignalServiceKit/MessageBackup/Archivers/MessageBackupErrors.swift b/SignalServiceKit/MessageBackup/Archivers/MessageBackupErrors.swift index 1fcd878ee2..284e5fe7fb 100644 --- a/SignalServiceKit/MessageBackup/Archivers/MessageBackupErrors.swift +++ b/SignalServiceKit/MessageBackup/Archivers/MessageBackupErrors.swift @@ -14,6 +14,16 @@ extension MessageBackup { /// Error while archiving a single frame. public struct ArchiveFrameError: MessageBackupLoggableError { public enum ErrorType { + /// Message types for which edit history is unexpected. + public enum UnexpectedRevisionsMessageType { + case contactMessgae + case stickerMessage + case updateMessage + case paymentNotification + case giftBadge + case viewOnceMessage + } + /// An error occurred serializing the proto. /// - Note /// Logging the raw error is safe, as it'll just contain proto field @@ -216,6 +226,9 @@ extension MessageBackup { case adHocCallDoesNotHaveCallLinkAsConversationId /// An ad hoc call has an invalid start timestamp. case invalidAdHocCallTimestamp + + /// A message unexpectedly had edit history. + case unexpectedRevisionsOnMessage(UnexpectedRevisionsMessageType) } private let type: ErrorType @@ -331,7 +344,8 @@ extension MessageBackup { .unviewedViewOnceMessageTooManyAttachments, .callLinkRestrictionsUnknown, .adHocCallDoesNotHaveCallLinkAsConversationId, - .invalidAdHocCallTimestamp: + .invalidAdHocCallTimestamp, + .unexpectedRevisionsOnMessage: // Log any others as we see them. return nil } @@ -396,7 +410,8 @@ extension MessageBackup { .unviewedViewOnceMessageTooManyAttachments, .callLinkRestrictionsUnknown, .adHocCallDoesNotHaveCallLinkAsConversationId, - .invalidAdHocCallTimestamp: + .invalidAdHocCallTimestamp, + .unexpectedRevisionsOnMessage: return .error case .contactThreadMissingAddress: // We've seen real-world databases with TSContactThreads that