PasswordStore: allow to pass in a specific PGPAgent implementation (for testing)

This commit is contained in:
Lysann Tranvouez 2026-03-11 23:25:46 +01:00
parent 77f85ccdd1
commit e3de11f71c
3 changed files with 15 additions and 10 deletions

View file

@ -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

View file

@ -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() {

View file

@ -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)
}