test .gpg-id support
mostly using mocks
This commit is contained in:
parent
38649f96fe
commit
5c416bfb21
2 changed files with 105 additions and 18 deletions
|
|
@ -27,6 +27,18 @@ final class PasswordStoreTest: XCTestCase {
|
|||
passwordStore = PasswordStore(url: localRepoURL, pgpAgent: pgpAgent)
|
||||
}
|
||||
|
||||
private func setUpMockedPGPInterface() -> MockPGPInterface {
|
||||
let mockPGPInterface = MockPGPInterface()
|
||||
keyStore = DictBasedKeychain()
|
||||
pgpAgent = PGPAgent(keyStore: keyStore, pgpInterface: mockPGPInterface)
|
||||
passwordStore = PasswordStore(url: localRepoURL, pgpAgent: pgpAgent)
|
||||
|
||||
// Set pgpKeyPassphrase key so checkAndInit() doesn't re-init and overwrite our mock.
|
||||
keyStore.add(string: "dummy", for: Globals.pgpKeyPassphrase)
|
||||
|
||||
return mockPGPInterface
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
passwordStore.erase()
|
||||
passwordStore = nil
|
||||
|
|
@ -322,31 +334,106 @@ final class PasswordStoreTest: XCTestCase {
|
|||
|
||||
// MARK: - .gpg-id support
|
||||
|
||||
func testCloneAndDecryptMultiKeys() throws {
|
||||
func testReadGPGIDFile() throws {
|
||||
try cloneRepository(.withGPGID)
|
||||
try importMultiplePGPKeys()
|
||||
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
[
|
||||
("work/github.com", ["4712286271220DB299883EA7062E678DA1024DAE"]),
|
||||
("personal/github.com", ["787EAE1A5FA3E749AA34CC6AA0645EBED862027E"]),
|
||||
("shared/github.com", ["4712286271220DB299883EA7062E678DA1024DAE", "787EAE1A5FA3E749AA34CC6AA0645EBED862027E"]),
|
||||
].forEach { path, keyIDs in
|
||||
("", [RSA4096.longFingerprint]),
|
||||
("family", [String(NISTP384.longFingerprint.suffix(16))]),
|
||||
("personal", [RSA4096.longFingerprint]),
|
||||
("shared", [RSA2048.longFingerprint, RSA4096.longFingerprint]),
|
||||
("work", [RSA2048.longFingerprint]),
|
||||
].forEach { path, expectedKeyIDs in
|
||||
let foundKeyIDs = findGPGIDs(from: localRepoURL.appendingPathComponent(path))
|
||||
XCTAssertEqual(foundKeyIDs, keyIDs)
|
||||
XCTAssertEqual(foundKeyIDs, expectedKeyIDs.map { $0.uppercased() })
|
||||
}
|
||||
}
|
||||
|
||||
let personal = try decrypt(path: "personal/github.com.gpg")
|
||||
XCTAssertEqual(personal.plainText, "passwordforpersonal\n")
|
||||
|
||||
let work = try decrypt(path: "work/github.com.gpg")
|
||||
XCTAssertEqual(work.plainText, "passwordforwork\n")
|
||||
func testAddPasswordInRoot_WithSingleEntryInPGPIDFile_EncryptsWithThatKey() throws {
|
||||
let mockPGPInterface = setUpMockedPGPInterface()
|
||||
mockPGPInterface.publicKeyIDs = Set(RSA2048_RSA4096.fingerprints)
|
||||
try cloneRepository(.withGPGID)
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
let testPassword = Password(name: "test", path: "test.gpg", plainText: "testpassword")
|
||||
let testPasswordEntity = try passwordStore.add(password: testPassword)!
|
||||
let testPasswordPlain = try passwordStore.decrypt(passwordEntity: testPasswordEntity, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(testPasswordPlain.plainText, "testpassword")
|
||||
_ = try passwordStore.add(password: testPassword)
|
||||
|
||||
XCTAssertEqual(mockPGPInterface.encryptMultiKeyCalls.count, 1)
|
||||
let encryptCall = mockPGPInterface.encryptMultiKeyCalls.first
|
||||
XCTAssertEqual(encryptCall?.plainData, testPassword.plainData)
|
||||
XCTAssertEqual(encryptCall?.keyIDs, [RSA4096.longFingerprint].map { $0.uppercased() })
|
||||
}
|
||||
|
||||
func testEncryptWithSingleKeyViaGPGIDFileInSubDirectory() throws {
|
||||
let mockPGPInterface = setUpMockedPGPInterface()
|
||||
mockPGPInterface.publicKeyIDs = Set(RSA2048_RSA4096.fingerprints)
|
||||
try cloneRepository(.withGPGID)
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
let testPassword = Password(name: "test", path: "family/test.gpg", plainText: "testpassword")
|
||||
_ = try passwordStore.add(password: testPassword)
|
||||
|
||||
XCTAssertEqual(mockPGPInterface.encryptMultiKeyCalls.count, 1)
|
||||
let encryptCall = mockPGPInterface.encryptMultiKeyCalls.first
|
||||
XCTAssertEqual(encryptCall?.plainData, testPassword.plainData)
|
||||
XCTAssertEqual(encryptCall?.keyIDs, [String(NISTP384.longFingerprint.suffix(16))].map { $0.uppercased() })
|
||||
}
|
||||
|
||||
func testEncryptWithSingleKeyViaGPGIDFileInParentDir() throws {
|
||||
let mockPGPInterface = setUpMockedPGPInterface()
|
||||
mockPGPInterface.publicKeyIDs = Set(RSA2048_RSA4096.fingerprints)
|
||||
try cloneRepository(.withGPGID)
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
// /personal doesn't have its own .gpg-id file, but should inherit from the root .gpg-id file
|
||||
let testPassword = Password(name: "test", path: "personal/test.gpg", plainText: "testpassword")
|
||||
_ = try passwordStore.add(password: testPassword)
|
||||
|
||||
XCTAssertEqual(mockPGPInterface.encryptMultiKeyCalls.count, 1)
|
||||
let encryptCall = mockPGPInterface.encryptMultiKeyCalls.first
|
||||
XCTAssertEqual(encryptCall?.plainData, testPassword.plainData)
|
||||
XCTAssertEqual(encryptCall?.keyIDs, [RSA4096.longFingerprint].map { $0.uppercased() })
|
||||
}
|
||||
|
||||
func testEncryptWithMultipleKeysViaGPGIDFile() throws {
|
||||
let mockPGPInterface = setUpMockedPGPInterface()
|
||||
mockPGPInterface.publicKeyIDs = Set(RSA2048_RSA4096.fingerprints)
|
||||
try cloneRepository(.withGPGID)
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
// /shared uses both RSA2048 and RSA4096
|
||||
let testPassword = Password(name: "test", path: "shared/test.gpg", plainText: "testpassword")
|
||||
_ = try passwordStore.add(password: testPassword)
|
||||
|
||||
XCTAssertEqual(mockPGPInterface.encryptMultiKeyCalls.count, 1)
|
||||
let encryptCall = mockPGPInterface.encryptMultiKeyCalls.first
|
||||
XCTAssertEqual(encryptCall?.plainData, testPassword.plainData)
|
||||
XCTAssertEqual(encryptCall?.keyIDs, RSA2048_RSA4096.longFingerprints.map { $0.uppercased() })
|
||||
}
|
||||
|
||||
func testEncryptWithSingleKeyViaGPGFile_MissingKey() throws {
|
||||
try cloneRepository(.withGPGID)
|
||||
try importSinglePGPKey() // Only import RSA4096, but not RSA2048
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
// /work uses RSA2048, but we didn't import that one
|
||||
let testPassword = Password(name: "test", path: "work/test.gpg", plainText: "testpassword")
|
||||
XCTAssertThrowsError(try passwordStore.add(password: testPassword)) {
|
||||
XCTAssertEqual($0 as? AppError, .pgpPublicKeyNotFound(keyID: RSA2048.longFingerprint.uppercased()))
|
||||
}
|
||||
}
|
||||
|
||||
func testEncryptWithMultipleKeysViaGPGFile_MissingKey() throws {
|
||||
try cloneRepository(.withGPGID)
|
||||
try importSinglePGPKey() // Only import RSA4096, but not RSA2048
|
||||
Defaults.isEnableGPGIDOn = true
|
||||
|
||||
// /shared uses both RSA2048 and RSA4096, but we only imported RSA4096, so encryption should fail since one of the keys is missing
|
||||
let testPassword = Password(name: "test", path: "shared/test.gpg", plainText: "testpassword")
|
||||
XCTAssertThrowsError(try passwordStore.add(password: testPassword)) {
|
||||
XCTAssertEqual($0 as? AppError, .pgpPublicKeyNotFound(keyID: RSA2048.longFingerprint.uppercased()))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue