Stricter rules for when we exclude an attachment from Backups
This commit is contained in:
parent
7f0e73ab16
commit
076dc980e8
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user