Skip to content

Commit

Permalink
Replace individual Backup integration test cases with auto-iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
sashaweiss-signal authored Aug 28, 2024
1 parent daf0c04 commit a47aeeb
Show file tree
Hide file tree
Showing 16 changed files with 225 additions and 1,114 deletions.
100 changes: 4 additions & 96 deletions Signal.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions SignalServiceKit/Environment/AppSetup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,9 @@ public class AppSetup {
storyStore: storyStore,
threadStore: threadStore
),
encryptedStreamProvider: MessageBackupEncryptedProtoStreamProviderImpl(
backupKeyMaterial: messageBackupKeyMaterial
),
groupRecipientArchiver: MessageBackupGroupRecipientArchiver(
disappearingMessageConfigStore: disappearingMessagesConfigurationStore,
groupsV2: groupsV2,
Expand All @@ -970,9 +973,7 @@ public class AppSetup {
localRecipientArchiver: MessageBackupLocalRecipientArchiver(),
messageBackupKeyMaterial: messageBackupKeyMaterial,
releaseNotesRecipientArchiver: MessageBackupReleaseNotesRecipientArchiver(),
streamProvider: MessageBackupProtoStreamProviderImpl(
backupKeyMaterial: messageBackupKeyMaterial
)
plaintextStreamProvider: MessageBackupPlaintextProtoStreamProviderImpl()
)

let externalPendingIDEALDonationStore = ExternalPendingIDEALDonationStoreImpl(keyStoreFactory: keyValueStoreFactory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,39 @@ extension MessageBackup {
}
}

/**
* Creates input and output streams for reading and writing to a backup file on disk.
*
* The backup file is just a sequence of serialized proto bytes, back to back, delimited by varint
* byte sizes so we know how much to read into memory to deserialize the next proto.
* The input and output streams abstract over this, and allow callers to just think in terms of "frames",
* the individual proto objects that we read and write one at a time.
*/
public protocol MessageBackupProtoStreamProvider {
/// Creates streams for reading and writing to a plaintext Backup file on-disk.
///
/// A Backup file is a sequence of concatenated serialized proto bytes delimited
/// by varint byte sizes, which tell us how much to read into memory to
/// deserialize the next proto. The streams provided by this type abstract over
/// this serialized format, allowing callers instead to think in terms of
/// "frames", or individual proto objects that we read or write individually.
///
/// - SeeAlso: ``MessageBackupEncryptedProtoStreamProvider``
public protocol MessageBackupPlaintextProtoStreamProvider {
typealias ProtoStream = MessageBackup.ProtoStream

/// Open an output stream to write a plaintext backup to a file on disk. The
/// caller owns the returned stream, and is responsible for closing it once
/// finished.
func openPlaintextOutputFileStream() -> ProtoStream.OpenOutputStreamResult<URL>

/// Open an input stream to read a plaintext backup from a file on disk. The
/// caller becomes the owner of the stream, and is responsible for closing
/// it once finished.
func openPlaintextInputFileStream(fileUrl: URL) -> ProtoStream.OpenInputStreamResult
}

/// Creates streams for reading and writing to an encrypted Backup file on-disk.
///
/// A Backup file is a sequence of concatenated serialized proto bytes delimited
/// by varint byte sizes, which tell us how much to read into memory to
/// deserialize the next proto. The streams provided by this type abstract over
/// this serialized format, allowing callers instead to think in terms of
/// "frames", or individual proto objects that we read or write individually.
///
/// - SeeAlso: ``MessageBackupPlaintextProtoStreamProvider``
public protocol MessageBackupEncryptedProtoStreamProvider {
typealias ProtoStream = MessageBackup.ProtoStream

/// Open an output stream to write an encrypted backup to a file on disk.
Expand All @@ -52,11 +75,6 @@ public protocol MessageBackupProtoStreamProvider {
tx: DBReadTransaction
) -> ProtoStream.OpenOutputStreamResult<ProtoStream.EncryptionMetadataProvider>

/// Open an output stream to write a plaintext backup to a file on disk. The
/// caller owns the returned stream, and is responsible for closing it once
/// finished.
func openPlaintextOutputFileStream() -> ProtoStream.OpenOutputStreamResult<URL>

/// Open an input stream to read an encrypted backup from a file on disk.
/// The caller becomes the owner of the stream, and is responsible for
/// closing it once finished.
Expand All @@ -65,19 +83,17 @@ public protocol MessageBackupProtoStreamProvider {
localAci: Aci,
tx: DBReadTransaction
) -> ProtoStream.OpenInputStreamResult

/// Open an input stream to read a plaintext backup from a file on disk. The
/// caller becomes the owner of the stream, and is responsible for closing
/// it once finished.
func openPlaintextInputFileStream(fileUrl: URL) -> ProtoStream.OpenInputStreamResult
}

public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvider {
// MARK: -

public class MessageBackupEncryptedProtoStreamProviderImpl: MessageBackupEncryptedProtoStreamProvider {
private let backupKeyMaterial: MessageBackupKeyMaterial
private let genericStreamProvider: GenericStreamProvider

public init(backupKeyMaterial: MessageBackupKeyMaterial) {
self.backupKeyMaterial = backupKeyMaterial
self.genericStreamProvider = GenericStreamProvider()
}

public func openEncryptedOutputFileStream(
Expand All @@ -99,7 +115,9 @@ public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvi

let outputStream: MessageBackupProtoOutputStream
let fileUrl: URL
switch openOutputFileStream(transforms: transforms) {
switch genericStreamProvider.openOutputFileStream(
transforms: transforms
) {
case .success(let _outputStream, let _fileUrl):
outputStream = _outputStream
fileUrl = _fileUrl
Expand All @@ -123,14 +141,6 @@ public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvi
}
}

public func openPlaintextOutputFileStream() -> ProtoStream.OpenOutputStreamResult<URL> {
let transforms: [any StreamTransform] = [
ChunkedOutputStreamTransform(),
]

return openOutputFileStream(transforms: transforms)
}

public func openEncryptedInputFileStream(
fileUrl: URL,
localAci: Aci,
Expand All @@ -148,21 +158,82 @@ public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvi
ChunkedInputStreamTransform(),
]

return openInputFileStream(fileUrl: fileUrl, transforms: transforms)
return genericStreamProvider.openInputFileStream(
fileUrl: fileUrl,
transforms: transforms
)
} catch {
return .unableToOpenFileStream
}
}

private func validateBackupHMAC(localAci: Aci, fileUrl: URL, tx: DBReadTransaction) -> Bool {
do {
let inputStreamResult = genericStreamProvider.openInputFileStream(
fileUrl: fileUrl,
transforms: [
try backupKeyMaterial.createHmacGeneratingStreamTransform(
localAci: localAci,
tx: tx
)
]
)

switch inputStreamResult {
case .success(_, let rawInputStream):
// Read through the input stream. The HmacStreamTransform will both build
// an HMAC of the input data and read the HMAC from the end of the input file.
// Once the end of the stream is reached, the transform will compare the
// HMACs and throw an exception if they differ.
while try rawInputStream.read(maxLength: 32 * 1024).count > 0 {}
try rawInputStream.close()
return true
case .fileNotFound, .unableToOpenFileStream, .hmacValidationFailedOnEncryptedFile:
return false
}
} catch {
return false
}
}
}

public class MessageBackupPlaintextProtoStreamProviderImpl: MessageBackupPlaintextProtoStreamProvider {
private let genericStreamProvider: GenericStreamProvider

init() {
self.genericStreamProvider = GenericStreamProvider()
}

public func openPlaintextOutputFileStream() -> ProtoStream.OpenOutputStreamResult<URL> {
let transforms: [any StreamTransform] = [
ChunkedOutputStreamTransform(),
]

return genericStreamProvider.openOutputFileStream(
transforms: transforms
)
}

public func openPlaintextInputFileStream(fileUrl: URL) -> ProtoStream.OpenInputStreamResult {
let transforms: [any StreamTransform] = [
ChunkedInputStreamTransform(),
]

return openInputFileStream(fileUrl: fileUrl, transforms: transforms)
return genericStreamProvider.openInputFileStream(
fileUrl: fileUrl,
transforms: transforms
)
}
}

private func openOutputFileStream(
// MARK: -

private class GenericStreamProvider {
typealias ProtoStream = MessageBackup.ProtoStream

init() {}

func openOutputFileStream(
transforms: [any StreamTransform]
) -> ProtoStream.OpenOutputStreamResult<URL> {
let fileUrl = OWSFileSystem.temporaryFileUrl(isAvailableWhileDeviceLocked: true)
Expand Down Expand Up @@ -191,7 +262,7 @@ public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvi
return .success(messageBackupOutputStream, fileUrl)
}

private func openInputFileStream(
func openInputFileStream(
fileUrl: URL,
transforms: [any StreamTransform]
) -> ProtoStream.OpenInputStreamResult {
Expand Down Expand Up @@ -224,29 +295,6 @@ public class MessageBackupProtoStreamProviderImpl: MessageBackupProtoStreamProvi
return .success(messageBackupInputStream, rawStream: transformableInputStream)
}

private func validateBackupHMAC(localAci: Aci, fileUrl: URL, tx: DBReadTransaction) -> Bool {
do {
let inputStreamResult = openInputFileStream(fileUrl: fileUrl, transforms: [
try backupKeyMaterial.createHmacGeneratingStreamTransform(localAci: localAci, tx: tx)
])

switch inputStreamResult {
case .success(_, let rawInputStream):
// Read through the input stream. The HmacStreamTransform will both build
// an HMAC of the input data and read the HMAC from the end of the input file.
// Once the end of the stream is reached, the transform will compare the
// HMACs and throw an exception if they differ.
while try rawInputStream.read(maxLength: 32 * 1024).count > 0 {}
try rawInputStream.close()
return true
case .fileNotFound, .unableToOpenFileStream, .hmacValidationFailedOnEncryptedFile:
return false
}
} catch {
return false
}
}

private class StreamDelegate: NSObject, Foundation.StreamDelegate {
private let _hadError = AtomicBool(false, lock: .sharedGlobal)
public var hadError: Bool { _hadError.get() }
Expand Down
17 changes: 10 additions & 7 deletions SignalServiceKit/MessageBackup/MessageBackupManagerImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ public class MessageBackupManagerImpl: MessageBackupManager {
private let dateProvider: DateProvider
private let db: DB
private let distributionListRecipientArchiver: MessageBackupDistributionListRecipientArchiver
private let encryptedStreamProvider: MessageBackupEncryptedProtoStreamProvider
private let groupRecipientArchiver: MessageBackupGroupRecipientArchiver
private let incrementalTSAttachmentMigrator: IncrementalMessageTSAttachmentMigrator
private let kvStore: KeyValueStore
private let localRecipientArchiver: MessageBackupLocalRecipientArchiver
private let messageBackupKeyMaterial: MessageBackupKeyMaterial
private let releaseNotesRecipientArchiver: MessageBackupReleaseNotesRecipientArchiver
private let streamProvider: MessageBackupProtoStreamProvider
private let plaintextStreamProvider: MessageBackupPlaintextProtoStreamProvider

public init(
accountDataArchiver: MessageBackupAccountDataArchiver,
Expand All @@ -55,13 +56,14 @@ public class MessageBackupManagerImpl: MessageBackupManager {
dateProvider: @escaping DateProvider,
db: DB,
distributionListRecipientArchiver: MessageBackupDistributionListRecipientArchiver,
encryptedStreamProvider: MessageBackupEncryptedProtoStreamProvider,
groupRecipientArchiver: MessageBackupGroupRecipientArchiver,
incrementalTSAttachmentMigrator: IncrementalMessageTSAttachmentMigrator,
kvStoreFactory: KeyValueStoreFactory,
localRecipientArchiver: MessageBackupLocalRecipientArchiver,
messageBackupKeyMaterial: MessageBackupKeyMaterial,
releaseNotesRecipientArchiver: MessageBackupReleaseNotesRecipientArchiver,
streamProvider: MessageBackupProtoStreamProvider
plaintextStreamProvider: MessageBackupPlaintextProtoStreamProvider
) {
self.accountDataArchiver = accountDataArchiver
self.attachmentDownloadManager = attachmentDownloadManager
Expand All @@ -74,13 +76,14 @@ public class MessageBackupManagerImpl: MessageBackupManager {
self.dateProvider = dateProvider
self.db = db
self.distributionListRecipientArchiver = distributionListRecipientArchiver
self.encryptedStreamProvider = encryptedStreamProvider
self.groupRecipientArchiver = groupRecipientArchiver
self.incrementalTSAttachmentMigrator = incrementalTSAttachmentMigrator
self.kvStore = kvStoreFactory.keyValueStore(collection: Constants.keyValueStoreCollectionName)
self.localRecipientArchiver = localRecipientArchiver
self.messageBackupKeyMaterial = messageBackupKeyMaterial
self.releaseNotesRecipientArchiver = releaseNotesRecipientArchiver
self.streamProvider = streamProvider
self.plaintextStreamProvider = plaintextStreamProvider
}

// MARK: - Remote backups
Expand Down Expand Up @@ -148,7 +151,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
return try await db.awaitableWrite { tx in
let outputStream: MessageBackupProtoOutputStream
let metadataProvider: MessageBackup.ProtoStream.EncryptionMetadataProvider
switch self.streamProvider.openEncryptedOutputFileStream(
switch self.encryptedStreamProvider.openEncryptedOutputFileStream(
localAci: localIdentifiers.aci,
tx: tx
) {
Expand Down Expand Up @@ -182,7 +185,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
return try await db.awaitableWrite { tx in
let outputStream: MessageBackupProtoOutputStream
let fileUrl: URL
switch self.streamProvider.openPlaintextOutputFileStream() {
switch self.plaintextStreamProvider.openPlaintextOutputFileStream() {
case .success(let _outputStream, let _fileUrl):
outputStream = _outputStream
fileUrl = _fileUrl
Expand Down Expand Up @@ -362,7 +365,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {

try await db.awaitableWrite { tx in
let inputStream: MessageBackupProtoInputStream
switch self.streamProvider.openEncryptedInputFileStream(
switch self.encryptedStreamProvider.openEncryptedInputFileStream(
fileUrl: fileUrl,
localAci: localIdentifiers.aci,
tx: tx
Expand Down Expand Up @@ -398,7 +401,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {

try await db.awaitableWrite { tx in
let inputStream: MessageBackupProtoInputStream
switch self.streamProvider.openPlaintextInputFileStream(
switch self.plaintextStreamProvider.openPlaintextInputFileStream(
fileUrl: fileUrl
) {
case .success(let protoStream, _):
Expand Down

This file was deleted.

Loading

0 comments on commit a47aeeb

Please sign in to comment.