Stricter rules for when we exclude an attachment from Backups

This commit is contained in:
Sasha Weiss 2026-01-28 13:39:33 -08:00 committed by GitHub
parent 7f0e73ab16
commit 076dc980e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 190 additions and 182 deletions

View File

@ -9,31 +9,26 @@ import LibSignalClient
extension BackupArchive {
public class AccountDataRestoringContext: RestoringContext {
let currentRemoteConfig: RemoteConfig
let backupPurpose: MessageBackupPurpose
/// Will only be nil if there was no earier AccountData frame to set it, which
/// should be treated as an error at read time when processing all subsequent frames.
var backupPlan: BackupPlan?
/// Will only be nil if there was no earier AccountData frame to set it, which
/// should be treated as an error at read time when processing all subsequent frames.
var uploadEra: String?
init(
startTimestampMs: UInt64,
backupPurpose: MessageBackupPurpose,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
currentRemoteConfig: RemoteConfig,
backupPurpose: MessageBackupPurpose,
tx: DBWriteTransaction,
) {
self.currentRemoteConfig = currentRemoteConfig
self.backupPurpose = backupPurpose
super.init(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,

View File

@ -105,23 +105,23 @@ extension BackupArchive {
private let threadCache = SharedMap<ChatId, CachedThreadInfo>()
init(
customChatColorContext: CustomChatColorArchivingContext,
recipientContext: RecipientArchivingContext,
startDate: Date,
remoteConfig: RemoteConfig,
bencher: BackupArchive.ArchiveBencher,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
currentBackupAttachmentUploadEra: String,
customChatColorContext: CustomChatColorArchivingContext,
includedContentFilter: IncludedContentFilter,
recipientContext: RecipientArchivingContext,
startTimestampMs: UInt64,
tx: DBReadTransaction,
) {
self.customChatColorContext = customChatColorContext
self.recipientContext = recipientContext
super.init(
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
startTimestampMs: startTimestampMs,
tx: tx,
)
}
@ -173,7 +173,8 @@ extension BackupArchive {
init(
customChatColorContext: CustomChatColorRestoringContext,
recipientContext: RecipientRestoringContext,
startTimestampMs: UInt64,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
tx: DBWriteTransaction,
@ -181,7 +182,8 @@ extension BackupArchive {
self.customChatColorContext = customChatColorContext
self.recipientContext = recipientContext
super.init(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,
@ -343,19 +345,19 @@ extension BackupArchive {
private let map = SharedMap<CustomChatColor.Key, CustomChatColorId>()
override init(
startDate: Date,
remoteConfig: RemoteConfig,
bencher: BackupArchive.ArchiveBencher,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
currentBackupAttachmentUploadEra: String,
includedContentFilter: IncludedContentFilter,
startTimestampMs: UInt64,
tx: DBReadTransaction,
) {
super.init(
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
startTimestampMs: startTimestampMs,
tx: tx,
)
}
@ -380,15 +382,17 @@ extension BackupArchive {
let accountDataContext: AccountDataRestoringContext
init(
startTimestampMs: UInt64,
accountDataContext: AccountDataRestoringContext,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
accountDataContext: AccountDataRestoringContext,
tx: DBWriteTransaction,
) {
self.accountDataContext = accountDataContext
super.init(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,

View File

@ -108,7 +108,7 @@ public class BackupArchiveChatStyleArchiver: BackupArchiveProtoStreamWriter {
/// in the Backup, we can't use the same timestamp for all colors. To
/// that end, we'll start with "now" and increment as we create more
/// colors.
var chatColorCreationTimestamp = context.startTimestampMs
var chatColorCreationTimestamp = context.startDate.ows_millisecondsSince1970
for chatColorProto in chatColorProtos {
let customChatColorId = BackupArchive.CustomChatColorId(value: chatColorProto.id)
@ -454,9 +454,7 @@ public class BackupArchiveChatStyleArchiver: BackupArchiveProtoStreamWriter {
return .success(nil)
}
return .success(referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
))
return .success(referencedAttachment.asBackupFilePointer(context: context))
}
private func restoreWallpaperAttachment<IDType>(
@ -522,9 +520,9 @@ public class BackupArchiveChatStyleArchiver: BackupArchiveProtoStreamWriter {
for referencedAttachment in results {
backupAttachmentDownloadScheduler.enqueueFromBackupIfNeeded(
referencedAttachment,
restoreStartTimestampMs: context.startTimestampMs,
restoreStartTimestampMs: context.startDate.ows_millisecondsSince1970,
backupPlan: backupPlan,
remoteConfig: context.accountDataContext.currentRemoteConfig,
remoteConfig: context.remoteConfig,
isPrimaryDevice: context.isPrimaryDevice,
tx: context.tx,
)

View File

@ -7,23 +7,28 @@ extension BackupArchive {
public class ChatItemRestoringContext: RestoringContext {
let accountDataContext: AccountDataRestoringContext
let chatContext: ChatRestoringContext
let recipientContext: RecipientRestoringContext
public var uploadEra: String? { chatContext.customChatColorContext.accountDataContext.uploadEra }
init(
accountDataContext: AccountDataRestoringContext,
chatContext: ChatRestoringContext,
recipientContext: RecipientRestoringContext,
startTimestampMs: UInt64,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
tx: DBWriteTransaction,
) {
self.accountDataContext = accountDataContext
self.recipientContext = recipientContext
self.chatContext = chatContext
super.init(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,

View File

@ -304,7 +304,7 @@ public class BackupArchiveChatItemArchiver: BackupArchiveProtoStreamWriter {
context.includedContentFilter.shouldSkipMessageBasedOnExpiration(
expireStartDate: details.expireStartDate,
expiresInMs: details.expiresInMs,
currentTimestamp: context.startTimestampMs,
currentTimestamp: context.startDate.ows_millisecondsSince1970,
)
{
// Skip, but treat as a success.

View File

@ -33,7 +33,7 @@ class BackupArchiveMessageAttachmentArchiver: BackupArchiveProtoStreamWriter {
for referencedAttachment in referencedAttachments {
let pointerProto = referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
context: context,
)
var attachmentProto = BackupProto_MessageAttachment()
@ -59,27 +59,21 @@ class BackupArchiveMessageAttachmentArchiver: BackupArchiveProtoStreamWriter {
referencedAttachment: ReferencedAttachment,
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer {
return referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
)
return referencedAttachment.asBackupFilePointer(context: context)
}
func archiveLinkPreviewAttachment(
referencedAttachment: ReferencedAttachment,
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer {
return referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
)
return referencedAttachment.asBackupFilePointer(context: context)
}
func archiveQuotedReplyThumbnailAttachment(
referencedAttachment: ReferencedAttachment,
context: BackupArchive.ArchivingContext,
) -> BackupProto_MessageAttachment {
let pointerProto = referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
)
let pointerProto = referencedAttachment.asBackupFilePointer(context: context)
var attachmentProto = BackupProto_MessageAttachment()
attachmentProto.pointer = pointerProto
@ -94,18 +88,14 @@ class BackupArchiveMessageAttachmentArchiver: BackupArchiveProtoStreamWriter {
referencedAttachment: ReferencedAttachment,
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer {
return referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
)
return referencedAttachment.asBackupFilePointer(context: context)
}
func archiveStickerAttachment(
referencedAttachment: ReferencedAttachment,
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer {
return referencedAttachment.asBackupFilePointer(
attachmentByteCounter: context.attachmentByteCounter,
)
return referencedAttachment.asBackupFilePointer(context: context)
}
// MARK: Restoring -
@ -374,12 +364,9 @@ class BackupArchiveMessageAttachmentArchiver: BackupArchiveProtoStreamWriter {
)])
}
let accountDataContext = context.chatContext.customChatColorContext.accountDataContext
guard let backupPlan = accountDataContext.backupPlan else {
guard let backupPlan = context.accountDataContext.backupPlan else {
return .messageFailure([.restoreFrameError(
.invalidProtoData(
.accountDataNotFound,
),
.invalidProtoData(.accountDataNotFound),
chatItemId,
)])
}
@ -387,9 +374,9 @@ class BackupArchiveMessageAttachmentArchiver: BackupArchiveProtoStreamWriter {
for referencedAttachment in results {
backupAttachmentDownloadScheduler.enqueueFromBackupIfNeeded(
referencedAttachment,
restoreStartTimestampMs: context.startTimestampMs,
restoreStartTimestampMs: context.startDate.ows_millisecondsSince1970,
backupPlan: backupPlan,
remoteConfig: accountDataContext.currentRemoteConfig,
remoteConfig: context.remoteConfig,
isPrimaryDevice: context.isPrimaryDevice,
tx: context.tx,
)
@ -448,7 +435,7 @@ extension BackupArchive.RestoreFrameError.ErrorType {
extension ReferencedAttachment {
func asBackupFilePointer(
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer {
var proto = BackupProto_FilePointer()
proto.contentType = attachment.mimeType
@ -478,7 +465,7 @@ extension ReferencedAttachment {
}
}
proto.locatorInfo = self.asBackupFilePointerLocatorInfo()
proto.locatorInfo = self.asBackupFilePointerLocatorInfo(context: context)
if
attachment.mediaName != nil,
@ -486,7 +473,7 @@ extension ReferencedAttachment {
attachment.streamInfo?.unencryptedByteCount
?? attachment.mediaTierInfo?.unencryptedByteCount
{
attachmentByteCounter.addToByteCount(
context.attachmentByteCounter.addToByteCount(
attachmentID: attachment.id,
byteCount: Cryptography.estimatedMediaTierCDNSize(unencryptedSize: UInt64(safeCast: unencryptedByteCount)) ?? UInt64(UInt32.max),
)
@ -497,7 +484,9 @@ extension ReferencedAttachment {
return proto
}
private func asBackupFilePointerLocatorInfo() -> BackupProto_FilePointer.LocatorInfo {
private func asBackupFilePointerLocatorInfo(
context: BackupArchive.ArchivingContext,
) -> BackupProto_FilePointer.LocatorInfo {
var locatorInfo = BackupProto_FilePointer.LocatorInfo()
// Include the transit tier cdn info as a fallback, but only
@ -509,7 +498,7 @@ extension ReferencedAttachment {
// When encryption keys don't match: if we reupload (e.g. forward) an
// attachment after 3+ days, we rotate to a new encryption key; transit
// tier info uses this new random key and can't be the fallback here.
let transitTierInfoToExport: Attachment.TransitTierInfo?
var transitTierInfoToExport: Attachment.TransitTierInfo?
if
let latestTransitTierInfo = attachment.latestTransitTierInfo,
latestTransitTierInfo.encryptionKey == attachment.encryptionKey
@ -521,50 +510,56 @@ extension ReferencedAttachment {
transitTierInfoToExport = nil
}
if
let transitTierUploadDate = transitTierInfoToExport.map({ Date(millisecondsSince1970: $0.uploadTimestamp) }),
transitTierUploadDate.addingTimeInterval(context.remoteConfig.messageQueueTime) < context.startDate
{
// This transit tier info is expired, so there's no point in
// exporting it.
transitTierInfoToExport = nil
}
if let transitTierInfoToExport {
locatorInfo.transitCdnKey = transitTierInfoToExport.cdnKey
locatorInfo.transitCdnNumber = transitTierInfoToExport.cdnNumber
locatorInfo.transitTierUploadTimestamp = transitTierInfoToExport.uploadTimestamp
// We may overwrite this below with plaintext hash integrity check,
// which is desired. We only use encrypted digest integrity check
// if we don't have a plaintext hash and DO have a transit tier upload.
switch transitTierInfoToExport.integrityCheck {
case .digestSHA256Ciphertext(let data):
locatorInfo.integrityCheck = .encryptedDigest(data)
case .sha256ContentHash(let data):
locatorInfo.integrityCheck = .plaintextHash(data)
}
}
// If we have absolutely no present-time source of data
// for this attachment, even if we have a plaintext hash because
// we _previously_ had data, don't bother exporting it. Its unrecoverable.
let isTotallyMissingAttachment =
attachment.streamInfo == nil
&& transitTierInfoToExport == nil
&& attachment.mediaTierInfo == nil
if !isTotallyMissingAttachment, let plaintextHash = attachment.sha256ContentHash {
locatorInfo.integrityCheck = .plaintextHash(plaintextHash)
if let mediaTierCdnNumber = attachment.mediaTierInfo?.cdnNumber {
locatorInfo.mediaTierCdnNumber = mediaTierCdnNumber
}
}
// Set fields only if some cdn info is available.
switch locatorInfo.integrityCheck {
case .plaintextHash, .encryptedDigest:
if let mediaTierInfo = attachment.mediaTierInfo {
locatorInfo.key = attachment.encryptionKey
locatorInfo.size = mediaTierInfo.unencryptedByteCount
locatorInfo.integrityCheck = .plaintextHash(mediaTierInfo.sha256ContentHash)
if
let unencryptedByteCount = attachment.streamInfo?.unencryptedByteCount
?? attachment.mediaTierInfo?.unencryptedByteCount
?? attachment.latestTransitTierInfo?.unencryptedByteCount
{
locatorInfo.size = unencryptedByteCount
if let cdnNumber = mediaTierInfo.cdnNumber {
locatorInfo.mediaTierCdnNumber = cdnNumber
}
case .none:
break
} else if let streamInfo = attachment.streamInfo {
locatorInfo.key = attachment.encryptionKey
locatorInfo.size = streamInfo.unencryptedByteCount
locatorInfo.integrityCheck = .plaintextHash(streamInfo.sha256ContentHash)
} else if let transitTierInfoToExport {
locatorInfo.key = attachment.encryptionKey
locatorInfo.size = transitTierInfoToExport.unencryptedByteCount ?? 0
// At the time of writing, TransitTierInfo.integrityCheck prefers
// the encrypted digest even if both are present. (See comment in
// that type's init.) So, manually check for the plaintext hash
// here, falling back to the encrypted digest otherwise.
if let plaintextHash = attachment.sha256ContentHash {
locatorInfo.integrityCheck = .plaintextHash(plaintextHash)
} else {
switch transitTierInfoToExport.integrityCheck {
case .sha256ContentHash(let plaintextHash):
owsFailDebug("Missing Attachment plaintext hash, but had one on TransitTierInfo!")
locatorInfo.integrityCheck = .plaintextHash(plaintextHash)
case .digestSHA256Ciphertext(let encryptedDigest):
locatorInfo.integrityCheck = .encryptedDigest(encryptedDigest)
}
}
} else {
// This attachment isn't uploaded anywhere and this device won't be
// able to upload it in the future. So, we leave a bunch of fields
// unset so any restoring device knows it's unavailable.
}
return locatorInfo

View File

@ -321,9 +321,9 @@ extension BackupArchiveTSIncomingMessageArchiver: BackupArchive.TSMessageEditHis
// 0 == no expiration
expiresInSeconds = 0
}
let expireStartDate: UInt64
let expireStartedAt: UInt64
if chatItem.hasExpireStartDate {
expireStartDate = chatItem.expireStartDate
expireStartedAt = chatItem.expireStartDate
} else if
expiresInSeconds > 0,
incomingDetails.read
@ -331,10 +331,10 @@ extension BackupArchiveTSIncomingMessageArchiver: BackupArchive.TSMessageEditHis
// If marked as read but the chat timer hasn't started,
// thats a bug on the export side but we can recover
// from it now by starting the timer now.
expireStartDate = context.startTimestampMs
expireStartedAt = context.startDate.ows_millisecondsSince1970
} else {
// 0 = hasn't started expiring.
expireStartDate = 0
expireStartedAt = 0
}
let editState: TSEditState
@ -385,7 +385,7 @@ extension BackupArchiveTSIncomingMessageArchiver: BackupArchive.TSMessageEditHis
expiresInSeconds: expiresInSeconds,
// Backed up messages don't set the chat timer; version is irrelevant.
expireTimerVersion: nil,
expireStartedAt: expireStartDate,
expireStartedAt: expireStartedAt,
read: wasReadForInteraction,
serverTimestamp: incomingDetails.dateServerSent,
serverDeliveryTimestamp: 0,

View File

@ -535,18 +535,18 @@ extension BackupArchiveTSOutgoingMessageArchiver: BackupArchive.TSMessageEditHis
return .messageFailure(partialErrors)
}
let expireStartDate: UInt64
let expireStartedAt: UInt64
if chatItem.hasExpireStartDate {
expireStartDate = chatItem.expireStartDate
expireStartedAt = chatItem.expireStartDate
} else if
expiresInSeconds > 0,
TSOutgoingMessage.isEligibleToStartExpireTimer(recipientStates: Array(recipientAddressStates.values))
{
// If there is an expire timer and the message is eligible to start expiring,
// set the expire start time to now even if unset in the proto.
expireStartDate = context.startTimestampMs
expireStartedAt = context.startDate.ows_millisecondsSince1970
} else {
expireStartDate = 0
expireStartedAt = 0
}
let outgoingMessageResult: BackupArchive.RestoreInteractionResult<TSOutgoingMessage> = {
@ -566,7 +566,7 @@ extension BackupArchiveTSOutgoingMessageArchiver: BackupArchive.TSMessageEditHis
expiresInSeconds: expiresInSeconds,
// Backed up messages don't set the chat timer; version is irrelevant.
expireTimerVersion: nil,
expireStartedAt: expireStartDate,
expireStartedAt: expireStartedAt,
isVoiceMessage: false,
isSmsMessageRestoredFromBackup: chatItem.sms,
isViewOnceMessage: false,

View File

@ -133,14 +133,14 @@ extension BackupArchive {
private let callLinkIdMap = SharedMap<CallLinkRecordId, RecipientId>()
init(
bencher: BackupArchive.ArchiveBencher,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
currentBackupAttachmentUploadEra: String,
includedContentFilter: IncludedContentFilter,
localIdentifiers: LocalIdentifiers,
localRecipientId: RecipientId,
localSignalRecipientRowId: SignalRecipient.RowId,
startTimestampMs: UInt64,
startDate: Date,
remoteConfig: RemoteConfig,
bencher: BackupArchive.ArchiveBencher,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
includedContentFilter: IncludedContentFilter,
tx: DBReadTransaction,
) {
self.localIdentifiers = localIdentifiers
@ -161,11 +161,11 @@ extension BackupArchive {
}
super.init(
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
startTimestampMs: startTimestampMs,
tx: tx,
)
}
@ -284,14 +284,16 @@ extension BackupArchive {
init(
localIdentifiers: LocalIdentifiers,
startTimestampMs: UInt64,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
tx: DBWriteTransaction,
) {
self.localIdentifiers = localIdentifiers
super.init(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,

View File

@ -733,7 +733,7 @@ public class BackupArchiveContactRecipientArchiver: BackupArchiveProtoStreamWrit
uniqueId: recipient.uniqueId,
identityKey: identityKey,
isFirstKnownKey: true,
createdAt: Date(millisecondsSince1970: context.startTimestampMs),
createdAt: context.startDate,
verificationState: verificationState,
)
do {

View File

@ -17,51 +17,58 @@ extension BackupArchive {
/// archiving to be updating the database, just reading from it.
/// (The exception to this is enqueuing attachment uploads.)
open class ArchivingContext {
/// The timestamp at which the archiving process started.
let startDate: Date
/// The remote config at the start of archiving.
let remoteConfig: RemoteConfig
/// For benchmarking archive steps.
let bencher: BackupArchive.ArchiveBencher
/// Counts archived attachment bytes for future progress reporting.
let attachmentByteCounter: BackupArchiveAttachmentByteCounter
/// Parameters configuring what content is included in this archive.
let includedContentFilter: IncludedContentFilter
/// The timestamp at which the archiving process started.
let startTimestampMs: UInt64
/// Always set even if BackupPlan is free
let currentBackupAttachmentUploadEra: String
/// The single transaction used to create the archive.
let tx: DBReadTransaction
init(
startDate: Date,
remoteConfig: RemoteConfig,
bencher: BackupArchive.ArchiveBencher,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
currentBackupAttachmentUploadEra: String,
includedContentFilter: IncludedContentFilter,
startTimestampMs: UInt64,
tx: DBReadTransaction,
) {
self.startDate = startDate
self.remoteConfig = remoteConfig
self.bencher = bencher
self.attachmentByteCounter = attachmentByteCounter
self.currentBackupAttachmentUploadEra = currentBackupAttachmentUploadEra
self.includedContentFilter = includedContentFilter
self.startTimestampMs = startTimestampMs
self.tx = tx
}
}
/// Base context class used for restoring from a backup.
open class RestoringContext {
/// The timestamp at which we began restoring.
public let startTimestampMs: UInt64
public let startDate: Date
/// The remote config at the start of restoring.
public let remoteConfig: RemoteConfig
/// Counts restored attachment bytes for future progress reporting.
public let attachmentByteCounter: BackupArchiveAttachmentByteCounter
/// Are we restoring onto a primary?
public let isPrimaryDevice: Bool
/// The single transaction used to restore the archive.
public let tx: DBWriteTransaction
init(
startTimestampMs: UInt64,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
tx: DBWriteTransaction,
) {
self.startTimestampMs = startTimestampMs
self.startDate = startDate
self.remoteConfig = remoteConfig
self.attachmentByteCounter = attachmentByteCounter
self.isPrimaryDevice = isPrimaryDevice
self.tx = tx

View File

@ -233,7 +233,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
backupSettingsStore.setLastBackupDetails(
date: metadata.exportStartTimestamp,
date: metadata.exportStartDate,
backupFileSizeBytes: backupFileSizeBytes,
backupMediaSizeBytes: backupMediaSizeBytes,
tx: tx,
@ -264,7 +264,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
progress progressSink: OWSProgressSink?,
) async throws -> Upload.EncryptedBackupUploadMetadata {
let attachmentByteCounter = BackupArchiveAttachmentByteCounter()
let startTimestamp = dateProvider()
let startDate = dateProvider()
// Filter included content according to the purpose of this backup.
let includedContentFilter = BackupArchive.IncludedContentFilter(
@ -310,14 +310,14 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
let metadata = try await _exportBackup(
localIdentifiers: localIdentifiers,
backupPurpose: backupPurpose.libsignalPurpose,
startTimestamp: startTimestamp,
startDate: startDate,
includedContentFilter: includedContentFilter,
progressSink: progressSink,
attachmentByteCounter: attachmentByteCounter,
benchTitle: "Export encrypted Backup",
openOutputStreamBlock: { exportProgress, tx in
return encryptedStreamProvider.openEncryptedOutputFileStream(
startTimestamp: startTimestamp,
startDate: startDate,
encryptionMetadata: encryptionMetadata,
exportProgress: exportProgress,
attachmentByteCounter: attachmentByteCounter,
@ -340,7 +340,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
localIdentifiers: LocalIdentifiers,
) async throws -> URL {
let attachmentByteCounter = BackupArchiveAttachmentByteCounter()
let startTimestamp = dateProvider()
let startDate = dateProvider()
// For the integration tests, don't filter out any content. The premise
// of the tests is to verify that round-tripping a Backup file is
@ -352,7 +352,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
return try await _exportBackup(
localIdentifiers: localIdentifiers,
backupPurpose: .remoteBackup,
startTimestamp: startTimestamp,
startDate: startDate,
includedContentFilter: includedContentFilter,
progressSink: nil,
attachmentByteCounter: attachmentByteCounter,
@ -369,7 +369,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
private func _exportBackup<OutputStreamMetadata>(
localIdentifiers: LocalIdentifiers,
backupPurpose: MessageBackupPurpose,
startTimestamp: Date,
startDate: Date,
includedContentFilter: BackupArchive.IncludedContentFilter,
progressSink: OWSProgressSink?,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
@ -426,7 +426,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
outputStream: outputStream,
localIdentifiers: localIdentifiers,
backupPurpose: backupPurpose,
startTimestamp: startTimestamp,
startDate: startDate,
attachmentByteCounter: attachmentByteCounter,
includedContentFilter: includedContentFilter,
currentAppVersion: appVersion.currentAppVersion,
@ -446,7 +446,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
outputStream stream: BackupArchiveProtoOutputStream,
localIdentifiers: LocalIdentifiers,
backupPurpose: MessageBackupPurpose,
startTimestamp: Date,
startDate: Date,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
includedContentFilter: BackupArchive.IncludedContentFilter,
currentAppVersion: String,
@ -458,8 +458,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
dateProviderMonotonic: dateProviderMonotonic,
memorySampler: memorySampler,
)
let startTimestampMs = startTimestamp.ows_millisecondsSince1970
let remoteConfig = remoteConfigManager.currentConfig()
let backupVersion = Constants.supportedBackupVersion
let purposeString: String = switch backupPurpose {
case .deviceTransfer: "LinkNSync"
@ -475,13 +474,13 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
var errors = [LoggableErrorAndProto]()
let result = Result<Void, Error>(catching: {
logger.info("Exporting for \(purposeString) with version \(backupVersion), timestamp \(startTimestampMs)")
logger.info("Exporting for \(purposeString) with version \(backupVersion), timestamp \(startDate.ows_millisecondsSince1970)")
try autoreleasepool {
try writeHeader(
stream: stream,
backupVersion: backupVersion,
backupTimeMs: startTimestampMs,
startDate: startDate,
currentAppVersion: currentAppVersion,
firstAppVersion: firstAppVersion,
mediaRootBackupKey: mediaRootBackupKey,
@ -490,14 +489,12 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
try Task.checkCancellation()
let currentBackupAttachmentUploadEra = backupAttachmentUploadEraStore.currentUploadEra(tx: tx)
let customChatColorContext = BackupArchive.CustomChatColorArchivingContext(
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
startTimestampMs: startTimestampMs,
tx: tx,
)
try autoreleasepool {
@ -543,14 +540,14 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
let recipientArchivingContext = BackupArchive.RecipientArchivingContext(
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
localIdentifiers: localIdentifiers,
localRecipientId: localRecipientId,
localSignalRecipientRowId: localSignalRecipientRowId,
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
includedContentFilter: includedContentFilter,
tx: tx,
)
@ -621,13 +618,13 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
let chatArchivingContext = BackupArchive.ChatArchivingContext(
customChatColorContext: customChatColorContext,
recipientContext: recipientArchivingContext,
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
customChatColorContext: customChatColorContext,
includedContentFilter: includedContentFilter,
recipientContext: recipientArchivingContext,
startTimestampMs: startTimestampMs,
tx: tx,
)
let chatArchiveResult = try chatArchiver.archiveChats(
@ -659,11 +656,11 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
let archivingContext = BackupArchive.ArchivingContext(
startDate: startDate,
remoteConfig: remoteConfig,
bencher: bencher,
attachmentByteCounter: attachmentByteCounter,
currentBackupAttachmentUploadEra: currentBackupAttachmentUploadEra,
includedContentFilter: includedContentFilter,
startTimestampMs: startTimestampMs,
tx: tx,
)
let stickerPackArchiveResult = try stickerPackArchiver.archiveStickerPacks(
@ -706,7 +703,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
private func writeHeader(
stream: BackupArchiveProtoOutputStream,
backupVersion: UInt64,
backupTimeMs: UInt64,
startDate: Date,
currentAppVersion: String,
firstAppVersion: String,
mediaRootBackupKey: MediaRootBackupKey,
@ -714,7 +711,7 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
) throws {
var backupInfo = BackupProto_BackupInfo()
backupInfo.version = backupVersion
backupInfo.backupTimeMs = backupTimeMs
backupInfo.backupTimeMs = startDate.ows_millisecondsSince1970
backupInfo.currentAppVersion = currentAppVersion
backupInfo.firstAppVersion = firstAppVersion
@ -930,11 +927,10 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
throw OWSAssertionError("Restoring from backup twice!")
}
let startTimestampMs = dateProvider().ows_millisecondsSince1970
let startDate = dateProvider()
let remoteConfig = remoteConfigManager.currentConfig()
let attachmentByteCounter = BackupArchiveAttachmentByteCounter()
let currentRemoteConfig = remoteConfigManager.currentConfig()
// Drops all indexes on the `TSInteraction` table before doing the
// import, which dramatically speeds up the import. We'll then recreate
// all these indexes in bulk afterwards.
@ -1011,31 +1007,33 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
init(
localIdentifiers: LocalIdentifiers,
startTimestampMs: UInt64,
backupPurpose: MessageBackupPurpose,
startDate: Date,
remoteConfig: RemoteConfig,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
isPrimaryDevice: Bool,
currentRemoteConfig: RemoteConfig,
backupPurpose: MessageBackupPurpose,
tx: DBWriteTransaction,
) {
accountData = BackupArchive.AccountDataRestoringContext(
startTimestampMs: startTimestampMs,
backupPurpose: backupPurpose,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
currentRemoteConfig: currentRemoteConfig,
backupPurpose: backupPurpose,
tx: tx,
)
customChatColor = BackupArchive.CustomChatColorRestoringContext(
startTimestampMs: startTimestampMs,
accountDataContext: accountData,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
accountDataContext: accountData,
tx: tx,
)
recipient = BackupArchive.RecipientRestoringContext(
localIdentifiers: localIdentifiers,
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,
@ -1043,21 +1041,25 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
chat = BackupArchive.ChatRestoringContext(
customChatColorContext: customChatColor,
recipientContext: recipient,
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,
)
chatItem = BackupArchive.ChatItemRestoringContext(
accountDataContext: accountData,
chatContext: chat,
recipientContext: recipient,
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,
)
stickerPack = BackupArchive.RestoringContext(
startTimestampMs: startTimestampMs,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
tx: tx,
@ -1066,11 +1068,11 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
}
let contexts = Contexts(
localIdentifiers: localIdentifiers,
startTimestampMs: startTimestampMs,
backupPurpose: backupPurpose,
startDate: startDate,
remoteConfig: remoteConfig,
attachmentByteCounter: attachmentByteCounter,
isPrimaryDevice: isPrimaryDevice,
currentRemoteConfig: currentRemoteConfig,
backupPurpose: backupPurpose,
tx: tx,
)

View File

@ -50,7 +50,7 @@ open class BackupArchiveManagerMock: BackupArchiveManager {
let source = await progress?.addSource(withLabel: "", unitCount: 1)
source?.incrementCompletedUnitCount(by: 1)
return Upload.EncryptedBackupUploadMetadata(
exportStartTimestamp: Date(),
exportStartDate: Date(),
fileUrl: URL(string: "file://")!,
digest: Data(),
encryptedDataLength: 0,

View File

@ -108,7 +108,7 @@ public class BackupArchiveEncryptedProtoStreamProvider {
/// The caller owns the returned stream, and is responsible for closing it
/// once finished.
func openEncryptedOutputFileStream(
startTimestamp: Date,
startDate: Date,
encryptionMetadata: BackupExportPurpose.EncryptionMetadata,
exportProgress: BackupArchiveExportProgress?,
attachmentByteCounter: BackupArchiveAttachmentByteCounter,
@ -147,7 +147,7 @@ public class BackupArchiveEncryptedProtoStreamProvider {
outputStream,
metadataProvider: {
return Upload.EncryptedBackupUploadMetadata(
exportStartTimestamp: startTimestamp,
exportStartDate: startDate,
fileUrl: fileUrl,
digest: try outputTrackingTransform.digest(),
encryptedDataLength: UInt32(clamping: outputTrackingTransform.count),

View File

@ -104,7 +104,7 @@ public enum Upload {
public struct EncryptedBackupUploadMetadata: UploadMetadata {
/// When we started the export of this backup.
public let exportStartTimestamp: Date
public let exportStartDate: Date
/// File URL of the data consisting of "iv + encrypted data + hmac"
public let fileUrl: URL