diff --git a/AuthenticatorBridgeKit/AuthenticatorBridgeItemService.swift b/AuthenticatorBridgeKit/AuthenticatorBridgeItemService.swift index 983c7ff17..e605fc341 100644 --- a/AuthenticatorBridgeKit/AuthenticatorBridgeItemService.swift +++ b/AuthenticatorBridgeKit/AuthenticatorBridgeItemService.swift @@ -201,7 +201,7 @@ public class DefaultAuthenticatorBridgeItemService: AuthenticatorBridgeItemServi context: dataStore.persistentContainer.viewContext, request: fetchRequest ) - .tryMap { dataItems in + .map { dataItems in dataItems.compactMap(\.model) } .asyncTryMap { itemModel in diff --git a/AuthenticatorBridgeKit/SharedCryptographyService.swift b/AuthenticatorBridgeKit/SharedCryptographyService.swift index c91a51116..dad146478 100644 --- a/AuthenticatorBridgeKit/SharedCryptographyService.swift +++ b/AuthenticatorBridgeKit/SharedCryptographyService.swift @@ -57,6 +57,8 @@ public class DefaultAuthenticatorCryptographyService: SharedCryptographyService public func decryptAuthenticatorItems( _ items: [AuthenticatorBridgeItemDataModel] ) async throws -> [AuthenticatorBridgeItemDataView] { + guard !items.isEmpty else { return [] } + let key = try await sharedKeychainRepository.getAuthenticatorKey() let symmetricKey = SymmetricKey(data: key) diff --git a/AuthenticatorBridgeKit/Tests/SharedCryptographyServiceTests.swift b/AuthenticatorBridgeKit/Tests/SharedCryptographyServiceTests.swift index 7596561aa..e374d6da4 100644 --- a/AuthenticatorBridgeKit/Tests/SharedCryptographyServiceTests.swift +++ b/AuthenticatorBridgeKit/Tests/SharedCryptographyServiceTests.swift @@ -30,6 +30,17 @@ final class SharedCryptographyServiceTests: AuthenticatorBridgeKitTestCase { // MARK: Tests + /// Verify that `SharedCryptographyService.decryptAuthenticatorItems()' returns and empty + /// array when the input is an empty array even when the authenticator key is missing. + /// + func test_decryptAuthenticatorItems_returnsEmpty() async throws { + try sharedKeychainRepository.deleteAuthenticatorKey() + await assertAsyncDoesNotThrow { + let result = try await subject.decryptAuthenticatorItems([]) + XCTAssertEqual(result, []) + } + } + /// Verify that `SharedCryptographyService.decryptAuthenticatorItems(:)` correctly /// decrypts an encrypted array of `AuthenticatorBridgeItemDataModel`. /// @@ -44,11 +55,12 @@ final class SharedCryptographyServiceTests: AuthenticatorBridgeKitTestCase { /// when the `SharedKeyRepository` authenticator key is missing. /// func test_decryptAuthenticatorItems_throwsKeyMissingError() async throws { + let encryptedItems = try await subject.encryptAuthenticatorItems(items) let error = AuthenticatorKeychainServiceError.keyNotFound(SharedKeychainItem.authenticatorKey) try sharedKeychainRepository.deleteAuthenticatorKey() await assertAsyncThrows(error: error) { - _ = try await subject.decryptAuthenticatorItems([]) + _ = try await subject.decryptAuthenticatorItems(encryptedItems) } } diff --git a/AuthenticatorBridgeKit/Tests/TestHelpers/MockSharedCryptographyService.swift b/AuthenticatorBridgeKit/Tests/TestHelpers/MockSharedCryptographyService.swift index 4e5c5ff33..db693a0c4 100644 --- a/AuthenticatorBridgeKit/Tests/TestHelpers/MockSharedCryptographyService.swift +++ b/AuthenticatorBridgeKit/Tests/TestHelpers/MockSharedCryptographyService.swift @@ -6,10 +6,14 @@ import Foundation class MockSharedCryptographyService: SharedCryptographyService { var decryptCalled = false var encryptCalled = false + var errorToThrow: Error? func decryptAuthenticatorItems( _ items: [AuthenticatorBridgeItemDataModel] ) async throws -> [AuthenticatorBridgeItemDataView] { + if let errorToThrow { + throw errorToThrow + } decryptCalled = true return items.map { model in AuthenticatorBridgeItemDataView( @@ -27,6 +31,9 @@ class MockSharedCryptographyService: SharedCryptographyService { func encryptAuthenticatorItems( _ items: [AuthenticatorBridgeItemDataView] ) async throws -> [AuthenticatorBridgeItemDataModel] { + if let errorToThrow { + throw errorToThrow + } encryptCalled = true return items.map { view in AuthenticatorBridgeItemDataModel(