diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift index 98aa66a..37efdd1 100644 --- a/pass/Controllers/PasswordDetailTableViewController.swift +++ b/pass/Controllers/PasswordDetailTableViewController.swift @@ -128,7 +128,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // alert: cancel or try again let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) - let selectKey = UIAlertAction.selectKey(controller: self) { action in + let selectKey = UIAlertAction.selectKey(type: .PRIVATE, controller: self) { action in self.decryptThenShowPasswordLocalKey(keyID: action.title) } alert.addAction(selectKey) @@ -223,7 +223,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni SVProgressHUD.dismiss() let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) - let selectKey = UIAlertAction.selectKey(controller: self) { action in + let selectKey = UIAlertAction.selectKey(type: .PUBLIC, controller: self) { action in self.saveEditPassword(password: password, keyID: action.title) } alert.addAction(selectKey) diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index b715069..b0a3e61 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -89,10 +89,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele private func setPGPKeyTableViewCellDetailText() { var label = "NotSet".localize() - let keyID = (try? PGPAgent.shared.getShortKeyID()) ?? [] - if keyID.count == 1 { - label = keyID.first ?? "" - } else if keyID.count > 1 { + var keyIDs = Set((try? PGPAgent.shared.getShortKeyIDs(type: .PRIVATE)) ?? []) + keyIDs.formUnion((try? PGPAgent.shared.getShortKeyIDs(type: .PUBLIC)) ?? []) + + if keyIDs.count == 1 { + label = keyIDs.first ?? "" + } else if keyIDs.count > 1 { label = "Multiple" } if Defaults.isYubiKeyEnabled { diff --git a/pass/Services/PasswordDecryptor.swift b/pass/Services/PasswordDecryptor.swift index 49e7845..8824bb3 100644 --- a/pass/Services/PasswordDecryptor.swift +++ b/pass/Services/PasswordDecryptor.swift @@ -40,7 +40,7 @@ func decryptPassword( DispatchQueue.main.async { let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: controller)) - let selectKey = UIAlertAction.selectKey(controller: controller) { action in + let selectKey = UIAlertAction.selectKey(type: PGPKey.PRIVATE, controller: controller) { action in decryptPassword(in: controller, with: passwordPath, using: action.title, completion: completion) } alert.addAction(selectKey) diff --git a/pass/Services/PasswordEncryptor.swift b/pass/Services/PasswordEncryptor.swift index 254f045..6159881 100644 --- a/pass/Services/PasswordEncryptor.swift +++ b/pass/Services/PasswordEncryptor.swift @@ -19,7 +19,7 @@ func encryptPassword(in controller: UIViewController, with password: Password, k DispatchQueue.main.async { let alert = UIAlertController(title: "Cannot Encrypt Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: controller)) - let selectKey = UIAlertAction.selectKey(controller: controller) { action in + let selectKey = UIAlertAction.selectKey(type: .PUBLIC, controller: controller) { action in encryptPassword(in: controller, with: password, keyID: action.title, completion: completion) } alert.addAction(selectKey) diff --git a/passKit/Crypto/GopenPGPInterface.swift b/passKit/Crypto/GopenPGPInterface.swift index c185add..3917df1 100644 --- a/passKit/Crypto/GopenPGPInterface.swift +++ b/passKit/Crypto/GopenPGPInterface.swift @@ -167,12 +167,17 @@ struct GopenPGPInterface: PGPInterface { return encryptedData.getBinary()! } - var keyID: [String] { - publicKeys.keys.map { $0.uppercased() } + func getKeyIDs(type: PGPKey) -> [String] { + switch type { + case .PUBLIC: + return publicKeys.keys.map { $0.uppercased() } + case .PRIVATE: + return privateKeys.keys.map { $0.uppercased() } + } } - var shortKeyID: [String] { - publicKeys.keys.map { $0.suffix(8).uppercased() } + func getShortKeyIDs(type: PGPKey) -> [String] { + getKeyIDs(type: type).map { $0.suffix(8).uppercased() } } private func findDecryptionKey(message: CryptoPGPMessage, keyIDHint: String?) throws -> CryptoKey? { diff --git a/passKit/Crypto/ObjectivePGPInterface.swift b/passKit/Crypto/ObjectivePGPInterface.swift index cf13082..e1425c3 100644 --- a/passKit/Crypto/ObjectivePGPInterface.swift +++ b/passKit/Crypto/ObjectivePGPInterface.swift @@ -34,7 +34,8 @@ struct ObjectivePGPInterface: PGPInterface { } func encryptWithAllKeys(plainData: Data) throws -> Data { - try encrypt(plainData: plainData, keyIDs: keyID) + let keys = keyring.keys.filter { $0.isPublic && $0.isSecret } + return try encrypt(plainData: plainData, keyIDs: keys.map(\.keyID.longIdentifier)) } func encrypt(plainData: Data, keyIDs: [String]) throws -> Data { @@ -60,11 +61,20 @@ struct ObjectivePGPInterface: PGPInterface { keyring.findKey(keyID)?.isSecret ?? false } - var keyID: [String] { - keyring.keys.map(\.keyID.longIdentifier) + func getKeyIDs(type: PGPKey) -> [String] { + getKeys(type: type).map(\.keyID.longIdentifier) } - var shortKeyID: [String] { - keyring.keys.map(\.keyID.shortIdentifier) + func getShortKeyIDs(type: PGPKey) -> [String] { + getKeys(type: type).map(\.keyID.shortIdentifier) + } + + private func getKeys(type: PGPKey) -> [Key] { + switch type { + case .PUBLIC: + keyring.keys.filter(\.isPublic) + case .PRIVATE: + keyring.keys.filter(\.isSecret) + } } } diff --git a/passKit/Crypto/PGPAgent.swift b/passKit/Crypto/PGPAgent.swift index 44b3443..9ce335d 100644 --- a/passKit/Crypto/PGPAgent.swift +++ b/passKit/Crypto/PGPAgent.swift @@ -43,14 +43,14 @@ public class PGPAgent { pgpInterface != nil } - public func getKeyID() throws -> [String] { + public func getKeyIDs(type: PGPKey) throws -> [String] { try checkAndInit() - return pgpInterface?.keyID ?? [] + return pgpInterface?.getKeyIDs(type: type).sorted() ?? [] } - public func getShortKeyID() throws -> [String] { + public func getShortKeyIDs(type: PGPKey) throws -> [String] { try checkAndInit() - return pgpInterface?.shortKeyID.sorted() ?? [] + return pgpInterface?.getShortKeyIDs(type: type).sorted() ?? [] } public func decrypt(encryptedData: Data, keyID: String, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Data? { diff --git a/passKit/Crypto/PGPInterface.swift b/passKit/Crypto/PGPInterface.swift index aff2344..2afce6d 100644 --- a/passKit/Crypto/PGPInterface.swift +++ b/passKit/Crypto/PGPInterface.swift @@ -14,10 +14,8 @@ protocol PGPInterface { func encrypt(plainData: Data, keyIDs: [String]) throws -> Data func containsPublicKey(with keyID: String) -> Bool - func containsPrivateKey(with keyID: String) -> Bool - var keyID: [String] { get } - - var shortKeyID: [String] { get } + func getKeyIDs(type: PGPKey) -> [String] + func getShortKeyIDs(type: PGPKey) -> [String] } diff --git a/passKit/Extensions/UIAlertActionExtension.swift b/passKit/Extensions/UIAlertActionExtension.swift index b49ba07..d258e3b 100644 --- a/passKit/Extensions/UIAlertActionExtension.swift +++ b/passKit/Extensions/UIAlertActionExtension.swift @@ -38,10 +38,10 @@ public extension UIAlertAction { } } - static func selectKey(controller: UIViewController, handler: ((UIAlertAction) -> Void)?) -> UIAlertAction { + static func selectKey(type: PGPKey, controller: UIViewController, handler: ((UIAlertAction) -> Void)?) -> UIAlertAction { UIAlertAction(title: "Select Key", style: .default) { _ in let selectKeyAlert = UIAlertController(title: "Select from imported keys", message: nil, preferredStyle: .actionSheet) - try? PGPAgent.shared.getShortKeyID().forEach { keyID in + try? PGPAgent.shared.getShortKeyIDs(type: type).forEach { keyID in let action = UIAlertAction(title: keyID, style: .default, handler: handler) selectKeyAlert.addAction(action) } diff --git a/passKitTests/Crypto/PGPAgentTest.swift b/passKitTests/Crypto/PGPAgentTest.swift index b90e17f..531ecc1 100644 --- a/passKitTests/Crypto/PGPAgentTest.swift +++ b/passKitTests/Crypto/PGPAgentTest.swift @@ -48,7 +48,8 @@ final class PGPAgentTest: XCTestCase { try importKeys(testKeyInfo.publicKey, testKeyInfo.privateKey) XCTAssert(pgpAgent.isPrepared) try pgpAgent.initKeys() - XCTAssert(try pgpAgent.getKeyID().first!.lowercased().hasSuffix(testKeyInfo.fingerprint)) + XCTAssert(try pgpAgent.getKeyIDs(type: .PUBLIC).first!.lowercased().hasSuffix(testKeyInfo.fingerprint)) + XCTAssert(try pgpAgent.getKeyIDs(type: .PRIVATE).first!.lowercased().hasSuffix(testKeyInfo.fingerprint)) try [ (true, true), (true, false), @@ -183,6 +184,9 @@ final class PGPAgentTest: XCTestCase { try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys) try pgpAgent.initKeys() + XCTAssertEqual(try pgpAgent.getKeyIDs(type: .PUBLIC).map(\.localizedLowercase).sorted(), (RSA2048_RSA4096.longFingerprints + [ED25519.longFingerprint]).sorted()) + XCTAssertEqual(try pgpAgent.getKeyIDs(type: .PRIVATE).map(\.localizedLowercase).sorted(), RSA2048_RSA4096.longFingerprints.sorted()) + let encryptedData = try pgpAgent.encrypt(plainData: testData, keyIDs: RSA2048_RSA4096.fingerprints + [ED25519.fingerprint]) try [RSA2048.fingerprint, RSA4096.fingerprint].forEach { keyID in diff --git a/passKitTests/Mocks/MockPGPInterface.swift b/passKitTests/Mocks/MockPGPInterface.swift index b6402b9..9593669 100644 --- a/passKitTests/Mocks/MockPGPInterface.swift +++ b/passKitTests/Mocks/MockPGPInterface.swift @@ -89,6 +89,13 @@ class MockPGPInterface: PGPInterface { return privateKeyIDs.contains { $0.hasSuffix(keyID.lowercased()) } } - var keyID: [String] { [] } // currently not relevant in these tests - var shortKeyID: [String] { [] } // currently not relevant in these tests + func getKeyIDs(type _: PGPKey) -> [String] { + // currently irrelevant for the tests + [] + } + + func getShortKeyIDs(type _: PGPKey) -> [String] { + // currently irrelevant for the tests + [] + } }