clarify public vs private keys + make prvate key IDs available
This commit is contained in:
parent
4e19d9e714
commit
5a92b6fda7
11 changed files with 56 additions and 30 deletions
|
|
@ -128,7 +128,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
// alert: cancel or try again
|
// alert: cancel or try again
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
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)
|
self.decryptThenShowPasswordLocalKey(keyID: action.title)
|
||||||
}
|
}
|
||||||
alert.addAction(selectKey)
|
alert.addAction(selectKey)
|
||||||
|
|
@ -223,7 +223,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
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)
|
self.saveEditPassword(password: password, keyID: action.title)
|
||||||
}
|
}
|
||||||
alert.addAction(selectKey)
|
alert.addAction(selectKey)
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
private func setPGPKeyTableViewCellDetailText() {
|
private func setPGPKeyTableViewCellDetailText() {
|
||||||
var label = "NotSet".localize()
|
var label = "NotSet".localize()
|
||||||
|
|
||||||
let keyID = (try? PGPAgent.shared.getShortKeyID()) ?? []
|
var keyIDs = Set<String>((try? PGPAgent.shared.getShortKeyIDs(type: .PRIVATE)) ?? [])
|
||||||
if keyID.count == 1 {
|
keyIDs.formUnion((try? PGPAgent.shared.getShortKeyIDs(type: .PUBLIC)) ?? [])
|
||||||
label = keyID.first ?? ""
|
|
||||||
} else if keyID.count > 1 {
|
if keyIDs.count == 1 {
|
||||||
|
label = keyIDs.first ?? ""
|
||||||
|
} else if keyIDs.count > 1 {
|
||||||
label = "Multiple"
|
label = "Multiple"
|
||||||
}
|
}
|
||||||
if Defaults.isYubiKeyEnabled {
|
if Defaults.isYubiKeyEnabled {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func decryptPassword(
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
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)
|
decryptPassword(in: controller, with: passwordPath, using: action.title, completion: completion)
|
||||||
}
|
}
|
||||||
alert.addAction(selectKey)
|
alert.addAction(selectKey)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ func encryptPassword(in controller: UIViewController, with password: Password, k
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let alert = UIAlertController(title: "Cannot Encrypt Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
let alert = UIAlertController(title: "Cannot Encrypt Password", message: AppError.pgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: controller))
|
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)
|
encryptPassword(in: controller, with: password, keyID: action.title, completion: completion)
|
||||||
}
|
}
|
||||||
alert.addAction(selectKey)
|
alert.addAction(selectKey)
|
||||||
|
|
|
||||||
|
|
@ -167,12 +167,17 @@ struct GopenPGPInterface: PGPInterface {
|
||||||
return encryptedData.getBinary()!
|
return encryptedData.getBinary()!
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyID: [String] {
|
func getKeyIDs(type: PGPKey) -> [String] {
|
||||||
publicKeys.keys.map { $0.uppercased() }
|
switch type {
|
||||||
|
case .PUBLIC:
|
||||||
|
return publicKeys.keys.map { $0.uppercased() }
|
||||||
|
case .PRIVATE:
|
||||||
|
return privateKeys.keys.map { $0.uppercased() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var shortKeyID: [String] {
|
func getShortKeyIDs(type: PGPKey) -> [String] {
|
||||||
publicKeys.keys.map { $0.suffix(8).uppercased() }
|
getKeyIDs(type: type).map { $0.suffix(8).uppercased() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private func findDecryptionKey(message: CryptoPGPMessage, keyIDHint: String?) throws -> CryptoKey? {
|
private func findDecryptionKey(message: CryptoPGPMessage, keyIDHint: String?) throws -> CryptoKey? {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ struct ObjectivePGPInterface: PGPInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptWithAllKeys(plainData: Data) throws -> Data {
|
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 {
|
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data {
|
||||||
|
|
@ -60,11 +61,20 @@ struct ObjectivePGPInterface: PGPInterface {
|
||||||
keyring.findKey(keyID)?.isSecret ?? false
|
keyring.findKey(keyID)?.isSecret ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyID: [String] {
|
func getKeyIDs(type: PGPKey) -> [String] {
|
||||||
keyring.keys.map(\.keyID.longIdentifier)
|
getKeys(type: type).map(\.keyID.longIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
var shortKeyID: [String] {
|
func getShortKeyIDs(type: PGPKey) -> [String] {
|
||||||
keyring.keys.map(\.keyID.shortIdentifier)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,14 @@ public class PGPAgent {
|
||||||
pgpInterface != nil
|
pgpInterface != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getKeyID() throws -> [String] {
|
public func getKeyIDs(type: PGPKey) throws -> [String] {
|
||||||
try checkAndInit()
|
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()
|
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? {
|
public func decrypt(encryptedData: Data, keyID: String, requestPGPKeyPassphrase: @escaping (String) -> String) throws -> Data? {
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@ protocol PGPInterface {
|
||||||
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data
|
func encrypt(plainData: Data, keyIDs: [String]) throws -> Data
|
||||||
|
|
||||||
func containsPublicKey(with keyID: String) -> Bool
|
func containsPublicKey(with keyID: String) -> Bool
|
||||||
|
|
||||||
func containsPrivateKey(with keyID: String) -> Bool
|
func containsPrivateKey(with keyID: String) -> Bool
|
||||||
|
|
||||||
var keyID: [String] { get }
|
func getKeyIDs(type: PGPKey) -> [String]
|
||||||
|
func getShortKeyIDs(type: PGPKey) -> [String]
|
||||||
var shortKeyID: [String] { get }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
UIAlertAction(title: "Select Key", style: .default) { _ in
|
||||||
let selectKeyAlert = UIAlertController(title: "Select from imported keys", message: nil, preferredStyle: .actionSheet)
|
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)
|
let action = UIAlertAction(title: keyID, style: .default, handler: handler)
|
||||||
selectKeyAlert.addAction(action)
|
selectKeyAlert.addAction(action)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ final class PGPAgentTest: XCTestCase {
|
||||||
try importKeys(testKeyInfo.publicKey, testKeyInfo.privateKey)
|
try importKeys(testKeyInfo.publicKey, testKeyInfo.privateKey)
|
||||||
XCTAssert(pgpAgent.isPrepared)
|
XCTAssert(pgpAgent.isPrepared)
|
||||||
try pgpAgent.initKeys()
|
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 [
|
try [
|
||||||
(true, true),
|
(true, true),
|
||||||
(true, false),
|
(true, false),
|
||||||
|
|
@ -183,6 +184,9 @@ final class PGPAgentTest: XCTestCase {
|
||||||
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys)
|
try importKeys(RSA2048_RSA4096.publicKeys | ED25519.publicKey, RSA2048_RSA4096.privateKeys)
|
||||||
try pgpAgent.initKeys()
|
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])
|
let encryptedData = try pgpAgent.encrypt(plainData: testData, keyIDs: RSA2048_RSA4096.fingerprints + [ED25519.fingerprint])
|
||||||
|
|
||||||
try [RSA2048.fingerprint, RSA4096.fingerprint].forEach { keyID in
|
try [RSA2048.fingerprint, RSA4096.fingerprint].forEach { keyID in
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,13 @@ class MockPGPInterface: PGPInterface {
|
||||||
return privateKeyIDs.contains { $0.hasSuffix(keyID.lowercased()) }
|
return privateKeyIDs.contains { $0.hasSuffix(keyID.lowercased()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyID: [String] { [] } // currently not relevant in these tests
|
func getKeyIDs(type _: PGPKey) -> [String] {
|
||||||
var shortKeyID: [String] { [] } // currently not relevant in these tests
|
// currently irrelevant for the tests
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getShortKeyIDs(type _: PGPKey) -> [String] {
|
||||||
|
// currently irrelevant for the tests
|
||||||
|
[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue