From e3de11f71cc0c18a0deb1a5b1f4118e8a7f7fee6 Mon Sep 17 00:00:00 2001 From: Lysann Tranvouez Date: Wed, 11 Mar 2026 23:25:46 +0100 Subject: [PATCH] PasswordStore: allow to pass in a specific PGPAgent implementation (for testing) --- passKit/Crypto/PGPAgent.swift | 2 +- passKit/Models/PasswordStore.swift | 14 ++++++++------ passKitTests/Models/PasswordStoreTest.swift | 9 ++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/passKit/Crypto/PGPAgent.swift b/passKit/Crypto/PGPAgent.swift index d8e40f8..6ee8c2b 100644 --- a/passKit/Crypto/PGPAgent.swift +++ b/passKit/Crypto/PGPAgent.swift @@ -9,7 +9,7 @@ public class PGPAgent { public static let shared = PGPAgent() - private let keyStore: KeyStore + let keyStore: KeyStore private var pgpInterface: PGPInterface? private var latestDecryptStatus = true diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index b6d01b1..742f13e 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -23,6 +23,7 @@ public class PasswordStore { }() public var storeURL: URL + private let pgpAgent: PGPAgent public var gitRepository: GitRepository? @@ -84,8 +85,9 @@ public class PasswordStore { gitRepository?.numberOfCommits() } - init(url: URL = Globals.repositoryURL) { + init(url: URL = Globals.repositoryURL, pgpAgent: PGPAgent = .shared) { self.storeURL = url + self.pgpAgent = pgpAgent // Migration importExistingKeysIntoKeychain() @@ -359,14 +361,14 @@ public class PasswordStore { eraseStoreData() // Delete PGP key, SSH key and other secrets from the keychain. - AppKeychain.shared.removeAllContent() + pgpAgent.keyStore.removeAllContent() // Delete default settings. Defaults.removeAll() // Delete cache explicitly. PasscodeLock.shared.delete() - PGPAgent.shared.uninitKeys() + pgpAgent.uninitKeys() } // return the number of discarded commits @@ -395,7 +397,7 @@ public class PasswordStore { public func decrypt(passwordEntity: PasswordEntity, keyID: String? = nil, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Password { let url = passwordEntity.fileURL(in: storeURL) let encryptedData = try Data(contentsOf: url) - let data: Data? = try PGPAgent.shared.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) + let data: Data? = try pgpAgent.decrypt(encryptedData: encryptedData, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) guard let decryptedData = data else { throw AppError.decryption } @@ -415,9 +417,9 @@ public class PasswordStore { return [] }() if !keyIDs.isEmpty { - return try PGPAgent.shared.encrypt(plainData: password.plainData, keyIDs: keyIDs) + return try pgpAgent.encrypt(plainData: password.plainData, keyIDs: keyIDs) } - return try PGPAgent.shared.encryptWithAllKeys(plainData: password.plainData) + return try pgpAgent.encryptWithAllKeys(plainData: password.plainData) } public func removeGitSSHKeys() { diff --git a/passKitTests/Models/PasswordStoreTest.swift b/passKitTests/Models/PasswordStoreTest.swift index bb78bbf..accd779 100644 --- a/passKitTests/Models/PasswordStoreTest.swift +++ b/passKitTests/Models/PasswordStoreTest.swift @@ -15,15 +15,18 @@ import XCTest final class PasswordStoreTest: XCTestCase { private let localRepoURL: URL = Globals.sharedContainerURL.appendingPathComponent("Library/password-store-test/") + private var pgpAgent: PGPAgent! = nil private var passwordStore: PasswordStore! = nil override func setUp() { - passwordStore = PasswordStore(url: localRepoURL) + pgpAgent = PGPAgent() + passwordStore = PasswordStore(url: localRepoURL, pgpAgent: pgpAgent) } override func tearDown() { passwordStore.erase() passwordStore = nil + pgpAgent = nil Defaults.removeAll() } @@ -78,7 +81,7 @@ final class PasswordStoreTest: XCTestCase { XCTAssertTrue(AppKeychain.shared.contains(key: PGPKey.PUBLIC.getKeychainKey())) XCTAssertEqual(Defaults.gitSignatureName, "Test User") XCTAssertTrue(PasscodeLock.shared.hasPasscode) - XCTAssertTrue(PGPAgent.shared.isInitialized()) + XCTAssertTrue(pgpAgent.isInitialized()) expectation(forNotification: .passwordStoreUpdated, object: nil) expectation(forNotification: .passwordStoreErased, object: nil) @@ -88,7 +91,7 @@ final class PasswordStoreTest: XCTestCase { XCTAssertFalse(AppKeychain.shared.contains(key: PGPKey.PUBLIC.getKeychainKey())) XCTAssertFalse(Defaults.hasKey(\.gitSignatureName)) XCTAssertFalse(PasscodeLock.shared.hasPasscode) - XCTAssertFalse(PGPAgent.shared.isInitialized()) + XCTAssertFalse(pgpAgent.isInitialized()) waitForExpectations(timeout: 1, handler: nil) }