Seperate PGPAgent from PasswordStore and add tests
This commit is contained in:
parent
0862c1388e
commit
6ae4a02a01
14 changed files with 526 additions and 179 deletions
|
|
@ -96,6 +96,9 @@
|
|||
A2A61C171EEF90CB00CFE063 /* OneTimePassword.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA671DE1E7A73B100D3ABE1 /* OneTimePassword.framework */; };
|
||||
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */; };
|
||||
A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */; };
|
||||
A2AA934422DE30DD00D79A00 /* PGPAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2AA934322DE30DD00D79A00 /* PGPAgent.swift */; };
|
||||
A2AA934622DE3A8000D79A00 /* PGPAgentTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2AA934522DE3A8000D79A00 /* PGPAgentTest.swift */; };
|
||||
A2AA934822DE3F0200D79A00 /* TestPGPKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2AA934722DE3F0200D79A00 /* TestPGPKeys.swift */; };
|
||||
DA2679F1424EA94B5B8997FB /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE627E8F3DACEDD8FA220081 /* Pods_pass.framework */; };
|
||||
DC037CA61E4B883900609409 /* OpenSourceComponentsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */; };
|
||||
DC037CA81E4B898100609409 /* BasicStaticTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CA71E4B898100609409 /* BasicStaticTableViewController.swift */; };
|
||||
|
|
@ -301,6 +304,9 @@
|
|||
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SliderTableViewCell.xib; sourceTree = "<group>"; };
|
||||
A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilsExtension.swift; sourceTree = "<group>"; };
|
||||
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = "<group>"; };
|
||||
A2AA934322DE30DD00D79A00 /* PGPAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPAgent.swift; sourceTree = "<group>"; };
|
||||
A2AA934522DE3A8000D79A00 /* PGPAgentTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPAgentTest.swift; sourceTree = "<group>"; };
|
||||
A2AA934722DE3F0200D79A00 /* TestPGPKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestPGPKeys.swift; sourceTree = "<group>"; };
|
||||
A2BC54C71EEE5669001FAFBD /* Objective-CBridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Objective-CBridgingHeader.h"; sourceTree = "<group>"; };
|
||||
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenSourceComponentsTableViewController.swift; sourceTree = "<group>"; };
|
||||
DC037CA71E4B898100609409 /* BasicStaticTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicStaticTableViewController.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -490,6 +496,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
30B0485F209A5141001013CA /* PasswordTest.swift */,
|
||||
A2AA934522DE3A8000D79A00 /* PGPAgentTest.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -566,6 +573,7 @@
|
|||
A26075871EEC6F34005DB03E /* passKitTests.swift */,
|
||||
307BF39821BC2297003A082D /* TestBase.swift */,
|
||||
A26075891EEC6F34005DB03E /* Info.plist */,
|
||||
A2AA934722DE3F0200D79A00 /* TestPGPKeys.swift */,
|
||||
);
|
||||
path = passKitTests;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -601,6 +609,7 @@
|
|||
30697C4021F63CAB0064FCAC /* Password.swift */,
|
||||
30697C3F21F63CAA0064FCAC /* PasswordEntity.swift */,
|
||||
30697C4321F63CAB0064FCAC /* PasswordStore.swift */,
|
||||
A2AA934322DE30DD00D79A00 /* PGPAgent.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1250,6 +1259,7 @@
|
|||
30697C3E21F63C990064FCAC /* String+Utilities.swift in Sources */,
|
||||
302B2C9822C2BDE700D831EE /* AppKeychain.swift in Sources */,
|
||||
3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */,
|
||||
A2AA934422DE30DD00D79A00 /* PGPAgent.swift in Sources */,
|
||||
30697C3B21F63C990064FCAC /* String+Localization.swift in Sources */,
|
||||
302E85612125ECC70031BA64 /* Parser.swift in Sources */,
|
||||
30697C4621F63CAB0064FCAC /* GitCredential.swift in Sources */,
|
||||
|
|
@ -1275,10 +1285,12 @@
|
|||
30A1D2AC21B32C2A00E2D1F7 /* TokenBuilderTest.swift in Sources */,
|
||||
301F646D216166AA0071A4CE /* AdditionFieldTest.swift in Sources */,
|
||||
30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */,
|
||||
A2AA934622DE3A8000D79A00 /* PGPAgentTest.swift in Sources */,
|
||||
30B04860209A5141001013CA /* PasswordTest.swift in Sources */,
|
||||
307BF39921BC2298003A082D /* TestBase.swift in Sources */,
|
||||
30697C5F21F674800064FCAC /* String+UtilitiesTest.swift in Sources */,
|
||||
3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */,
|
||||
A2AA934822DE3F0200D79A00 /* TestPGPKeys.swift in Sources */,
|
||||
30A1D2AA21B32A0100E2D1F7 /* OtpTypeTest.swift in Sources */,
|
||||
301F6468216165290071A4CE /* ConstantsTest.swift in Sources */,
|
||||
30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavourTest.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveAddPasswordSegue" {
|
||||
// check PGP key
|
||||
guard passwordStore.privateKey != nil else {
|
||||
guard passwordStore.pgpAgent?.imported ?? false else {
|
||||
let alertTitle = "CannotAddPassword".localize()
|
||||
let alertMessage = "PgpKeyNotSet.".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
@objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = rememberPGPPassphraseSwitch.isOn
|
||||
if rememberPGPPassphraseSwitch.isOn == false {
|
||||
passwordStore.pgpKeyPassphrase = nil
|
||||
passwordStore.pgpAgent?.passphrase = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class PGPKeyArmorSettingTableViewController: AutoCellHeightUITableViewController
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||
pgpPassphrase = passwordStore.pgpAgent?.passphrase
|
||||
|
||||
scanPublicKeyCell?.textLabel?.text = "ScanPublicKeyQrCodes".localize()
|
||||
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class PGPKeySettingTableViewController: AutoCellHeightUITableViewController {
|
|||
super.viewDidLoad()
|
||||
pgpPublicKeyURLTextField.text = SharedDefaults[.pgpPublicKeyURL]?.absoluteString
|
||||
pgpPrivateKeyURLTextField.text = SharedDefaults[.pgpPrivateKeyURL]?.absoluteString
|
||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||
pgpPassphrase = passwordStore.pgpAgent?.passphrase
|
||||
}
|
||||
|
||||
private func validatePGPKeyURL(input: String?) -> Bool {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = passphrase
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
self.passwordStore.pgpAgent?.passphrase = nil
|
||||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
|
|
|
|||
|
|
@ -385,13 +385,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
SVProgressHUD.show(withStatus: "Decrypting".localize())
|
||||
}
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = passphrase
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
||||
private func decryptThenCopyPassword(from indexPath: IndexPath) {
|
||||
guard self.passwordStore.privateKey != nil else {
|
||||
guard self.passwordStore.pgpAgent?.imported ?? false else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -412,7 +412,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
self.passwordStore.pgpAgent?.passphrase = nil
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -453,7 +453,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "showPasswordDetail" {
|
||||
guard self.passwordStore.hasPgpKey else {
|
||||
guard self.passwordStore.pgpAgent?.imported ?? false else {
|
||||
Utils.alert(title: "CannotShowPassword".localize(), message: "SetPgpKey.".localize(), controller: self, completion: nil)
|
||||
if let s = sender as? UITableViewCell {
|
||||
let selectedIndexPath = tableView.indexPath(for: s)!
|
||||
|
|
@ -462,7 +462,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return false
|
||||
}
|
||||
} else if identifier == "addPasswordSegue" {
|
||||
guard self.passwordStore.hasPgpKey, self.passwordStore.storeRepository != nil else {
|
||||
guard self.passwordStore.pgpAgent?.imported ?? false && self.passwordStore.storeRepository != nil else {
|
||||
Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
SharedDefaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!.trimmed)
|
||||
SharedDefaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!.trimmed)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = controller.pgpPassphrase
|
||||
}
|
||||
SharedDefaults[.pgpKeySource] = "url"
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .PUBLIC)
|
||||
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .PRIVATE)
|
||||
try self.passwordStore.pgpAgent?.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .PUBLIC)
|
||||
try self.passwordStore.pgpAgent?.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .PRIVATE)
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent?.pgpKeyID
|
||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize(), controller: self, completion: nil)
|
||||
|
|
@ -57,17 +57,17 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
||||
SharedDefaults[.pgpKeySource] = "armor"
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = controller.pgpPassphrase
|
||||
}
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.initPGPKey(with: controller.armorPublicKeyTextView.text ?? "", keyType: .PUBLIC)
|
||||
try self.passwordStore.initPGPKey(with: controller.armorPrivateKeyTextView.text ?? "", keyType: .PRIVATE)
|
||||
try self.passwordStore.pgpAgent?.initPGPKey(with: controller.armorPublicKeyTextView.text ?? "", keyType: .PUBLIC)
|
||||
try self.passwordStore.pgpAgent?.initPGPKey(with: controller.armorPrivateKeyTextView.text ?? "", keyType: .PRIVATE)
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent?.pgpKeyID
|
||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
@ -89,10 +89,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
SVProgressHUD.show(withStatus: "FetchingPgpKey".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.pgpKeyImportFromFileSharing()
|
||||
try self.passwordStore.initPGPKeys()
|
||||
try self.passwordStore.pgpAgent?.pgpKeyImportFromFileSharing()
|
||||
try self.passwordStore.pgpAgent?.initPGPKeys()
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpAgent?.pgpKeyID
|
||||
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
|
||||
private func setPGPKeyTableViewCellDetailText() {
|
||||
if let pgpKeyID = self.passwordStore.pgpKeyID {
|
||||
if let pgpKeyID = self.passwordStore.pgpAgent?.pgpKeyID {
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
|
||||
} else {
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||
|
|
@ -200,7 +200,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
let savePassphraseAlert = UIAlertController(title: "Passphrase".localize(), message: "WantToSavePassphrase?".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: UIAlertAction.Style.default) { _ in
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
self.passwordStore.pgpAgent?.passphrase = nil
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = false
|
||||
self.saveImportedPGPKey()
|
||||
})
|
||||
|
|
@ -209,7 +209,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase".localize(), message: "FillInPgpPassphrase.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Ok".localize(), style: UIAlertAction.Style.default, handler: {_ in
|
||||
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
||||
self.passwordStore.pgpAgent?.passphrase = alert.textFields?.first?.text
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||
self.saveImportedPGPKey()
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
|
||||
guard self.passwordStore.privateKey != nil else {
|
||||
guard self.passwordStore.pgpAgent?.imported ?? false else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
self.passwordStore.pgpAgent?.passphrase = nil
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +200,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = passphrase
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
|
||||
guard self.passwordStore.privateKey != nil else {
|
||||
guard self.passwordStore.pgpAgent?.imported ?? false else {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
self.passwordStore.pgpAgent?.passphrase = nil
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +227,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||
self.passwordStore.pgpAgent?.passphrase = passphrase
|
||||
}
|
||||
return passphrase
|
||||
}
|
||||
|
|
|
|||
171
passKit/Models/PGPAgent.swift
Normal file
171
passKit/Models/PGPAgent.swift
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
//
|
||||
// PGPAgent.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ObjectivePGP
|
||||
import KeychainAccess
|
||||
import Gopenpgpwrapper
|
||||
|
||||
public class PGPAgent {
|
||||
|
||||
public var imported: Bool {
|
||||
get {
|
||||
return (publicKey != nil || publicKeyV2 != nil) && (privateKey != nil || privateKeyV2 != nil)
|
||||
}
|
||||
}
|
||||
|
||||
public var pgpKeyID: String?
|
||||
// PGP passphrase
|
||||
public var passphrase: String? {
|
||||
set {
|
||||
AppKeychain.add(string: newValue, for: "pgpKeyPassphrase")
|
||||
}
|
||||
get {
|
||||
return AppKeychain.get(for: "pgpKeyPassphrase")
|
||||
}
|
||||
}
|
||||
|
||||
// Gopenpgpwrapper
|
||||
private var publicKey: GopenpgpwrapperKey? {
|
||||
didSet {
|
||||
pgpKeyID = publicKey?.getID()
|
||||
}
|
||||
}
|
||||
private var privateKey: GopenpgpwrapperKey?
|
||||
// ObjectivePGP
|
||||
private let keyring = ObjectivePGP.defaultKeyring
|
||||
private var publicKeyV2: Key? {
|
||||
didSet {
|
||||
pgpKeyID = publicKeyV2?.keyID.shortIdentifier
|
||||
}
|
||||
}
|
||||
private var privateKeyV2: Key?
|
||||
|
||||
public func initPGPKeys() throws {
|
||||
try initPGPKey(.PUBLIC)
|
||||
try initPGPKey(.PRIVATE)
|
||||
}
|
||||
|
||||
public func initPGPKey(_ keyType: PgpKey) throws {
|
||||
// Read the key data from keychain.
|
||||
guard let pgpKeyData: Data = AppKeychain.get(for: keyType.getKeychainKey()) else {
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
|
||||
// Remove the key data from keychain temporary, in case the following step crashes repeatedly.
|
||||
AppKeychain.removeContent(for: keyType.getKeychainKey())
|
||||
|
||||
// Try GopenpgpwrapperReadKey first.
|
||||
if let key = GopenpgpwrapperReadKey(pgpKeyData) {
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKey = key
|
||||
case .PRIVATE:
|
||||
self.privateKey = key
|
||||
}
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
return
|
||||
}
|
||||
|
||||
// Try ObjectivePGP as a backup plan.
|
||||
// [ObjectivePGP.readKeys MAY CRASH!!!]
|
||||
if let keys = try? ObjectivePGP.readKeys(from: pgpKeyData),
|
||||
let key = keys.first {
|
||||
keyring.import(keys: keys)
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKeyV2 = key
|
||||
case .PRIVATE:
|
||||
self.privateKeyV2 = key
|
||||
}
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
return
|
||||
}
|
||||
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
|
||||
public func initPGPKey(from url: URL, keyType: PgpKey) throws {
|
||||
let pgpKeyData = try Data(contentsOf: url)
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func initPGPKey(with armorKey: String, keyType: PgpKey) throws {
|
||||
let pgpKeyData = armorKey.data(using: .ascii)!
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func pgpKeyImportFromFileSharing() throws {
|
||||
try KeyFileManager.PublicPgp.importKeyAndDeleteFile()
|
||||
try KeyFileManager.PrivatePgp.importKeyAndDeleteFile()
|
||||
}
|
||||
|
||||
public func decrypt(encryptedData: Data, requestPGPKeyPassphrase: () -> String) throws -> Data? {
|
||||
guard privateKey != nil || privateKeyV2 != nil else {
|
||||
throw AppError.PgpPublicKeyNotExist
|
||||
}
|
||||
let passphrase = self.passphrase ?? requestPGPKeyPassphrase()
|
||||
// Try Gopenpgp.
|
||||
if privateKey != nil {
|
||||
if let decryptedData = privateKey?.decrypt(encryptedData, passphrase: passphrase) {
|
||||
return decryptedData
|
||||
}
|
||||
}
|
||||
// Try ObjectivePGP.
|
||||
if privateKeyV2 != nil {
|
||||
if let decryptedData = try? ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys, passphraseForKey: {(_) in passphrase}) {
|
||||
print(decryptedData.base64EncodedString())
|
||||
return decryptedData
|
||||
}
|
||||
}
|
||||
throw AppError.Decryption
|
||||
}
|
||||
|
||||
public func encrypt(plainData: Data) throws -> Data {
|
||||
guard publicKey != nil || publicKeyV2 != nil else {
|
||||
throw AppError.PgpPublicKeyNotExist
|
||||
}
|
||||
// Try Gopenpgp.
|
||||
if publicKey != nil {
|
||||
if let encryptedData = publicKey?.encrypt(plainData, armor: SharedDefaults[.encryptInArmored]) {
|
||||
return encryptedData
|
||||
}
|
||||
}
|
||||
// Try ObjectivePGP.
|
||||
if publicKeyV2 != nil {
|
||||
if let encryptedData = try? ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil) {
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
return Armor.armored(encryptedData, as: .message).data(using: .utf8)!
|
||||
} else {
|
||||
return encryptedData
|
||||
}
|
||||
}
|
||||
}
|
||||
throw AppError.Encryption
|
||||
}
|
||||
|
||||
public func removePGPKeys() {
|
||||
try? FileManager.default.removeItem(atPath: Globals.pgpPublicKeyPath)
|
||||
try? FileManager.default.removeItem(atPath: Globals.pgpPrivateKeyPath)
|
||||
SharedDefaults.remove(.pgpKeySource)
|
||||
SharedDefaults.remove(.pgpPrivateKeyURL)
|
||||
SharedDefaults.remove(.pgpPublicKeyURL)
|
||||
SharedDefaults.remove(.pgpPublicKeyArmor)
|
||||
SharedDefaults.remove(.pgpPrivateKeyArmor)
|
||||
AppKeychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
AppKeychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
passphrase = nil
|
||||
publicKey = nil
|
||||
privateKey = nil
|
||||
publicKeyV2 = nil
|
||||
privateKeyV2 = nil
|
||||
keyring.deleteAll()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,9 +11,7 @@ import CoreData
|
|||
import UIKit
|
||||
import SwiftyUserDefaults
|
||||
import ObjectiveGit
|
||||
import ObjectivePGP
|
||||
import KeychainAccess
|
||||
import Gopenpgpwrapper
|
||||
|
||||
public class PasswordStore {
|
||||
public static let shared = PasswordStore()
|
||||
|
|
@ -27,28 +25,9 @@ public class PasswordStore {
|
|||
public let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
|
||||
public let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp")
|
||||
|
||||
public let pgpAgent: PGPAgent?
|
||||
|
||||
public var storeRepository: GTRepository?
|
||||
public var pgpKeyID: String?
|
||||
public var hasPgpKey: Bool {
|
||||
get {
|
||||
return (publicKey != nil || publicKeyV2 != nil) && (privateKey != nil || privateKeyV2 != nil)
|
||||
}
|
||||
}
|
||||
// Gopenpgpwrapper
|
||||
public var publicKey: GopenpgpwrapperKey? {
|
||||
didSet {
|
||||
pgpKeyID = publicKey?.getID()
|
||||
}
|
||||
}
|
||||
public var privateKey: GopenpgpwrapperKey?
|
||||
// ObjectivePGP
|
||||
public let keyring = ObjectivePGP.defaultKeyring
|
||||
public var publicKeyV2: Key? {
|
||||
didSet {
|
||||
pgpKeyID = publicKeyV2?.keyID.shortIdentifier
|
||||
}
|
||||
}
|
||||
public var privateKeyV2: Key?
|
||||
|
||||
public var gitSignatureForNow: GTSignature? {
|
||||
get {
|
||||
|
|
@ -57,15 +36,6 @@ public class PasswordStore {
|
|||
return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())
|
||||
}
|
||||
}
|
||||
|
||||
public var pgpKeyPassphrase: String? {
|
||||
set {
|
||||
AppKeychain.add(string: newValue, for: "pgpKeyPassphrase")
|
||||
}
|
||||
get {
|
||||
return AppKeychain.get(for: "pgpKeyPassphrase")
|
||||
}
|
||||
}
|
||||
|
||||
public var gitPassword: String? {
|
||||
set {
|
||||
|
|
@ -134,6 +104,8 @@ public class PasswordStore {
|
|||
}
|
||||
|
||||
private init() {
|
||||
self.pgpAgent = PGPAgent()
|
||||
|
||||
// File migration to group
|
||||
migrateIfNeeded()
|
||||
backwardCompatibility()
|
||||
|
|
@ -143,7 +115,7 @@ public class PasswordStore {
|
|||
if fm.fileExists(atPath: storeURL.path) {
|
||||
try storeRepository = GTRepository.init(url: storeURL)
|
||||
}
|
||||
try initPGPKeys()
|
||||
try self.pgpAgent?.initPGPKeys()
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
|
@ -189,10 +161,6 @@ public class PasswordStore {
|
|||
if (self.gitPassword != nil || self.gitSSHPrivateKeyPassphrase != nil) && SharedDefaults[.isRememberGitCredentialPassphraseOn] == false {
|
||||
SharedDefaults[.isRememberGitCredentialPassphraseOn] = true
|
||||
}
|
||||
// For the renamed isRememberPGPPassphraseOn (20171008)
|
||||
if self.pgpKeyPassphrase != nil && SharedDefaults[.isRememberPGPPassphraseOn] == false {
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = true
|
||||
}
|
||||
}
|
||||
|
||||
private func importExistingKeysIntoKeychain() {
|
||||
|
|
@ -208,54 +176,6 @@ public class PasswordStore {
|
|||
AppKeychain.add(string: armorKey, for: SshKey.PRIVATE.getKeychainKey())
|
||||
}
|
||||
|
||||
public func initPGPKeys() throws {
|
||||
try initPGPKey(.PUBLIC)
|
||||
try initPGPKey(.PRIVATE)
|
||||
}
|
||||
|
||||
private func initPGPKey(_ keyType: PgpKey) throws {
|
||||
// Read the key data from keychain.
|
||||
let pgpKeyData: Data? = AppKeychain.get(for: keyType.getKeychainKey())
|
||||
|
||||
// Try GopenpgpwrapperReadKey first.
|
||||
if let key = GopenpgpwrapperReadKey(pgpKeyData) {
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKey = key
|
||||
case .PRIVATE:
|
||||
self.privateKey = key
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Try ObjectivePGP as a backup plan.
|
||||
if let keys = try? ObjectivePGP.readKeys(from: pgpKeyData!),
|
||||
let key = keys.first {
|
||||
keyring.import(keys: keys)
|
||||
switch keyType {
|
||||
case .PUBLIC:
|
||||
self.publicKeyV2 = key
|
||||
case .PRIVATE:
|
||||
self.privateKeyV2 = key
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
throw AppError.KeyImport
|
||||
}
|
||||
|
||||
public func initPGPKey(from url: URL, keyType: PgpKey) throws {
|
||||
let pgpKeyData = try Data(contentsOf: url)
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func initPGPKey(with armorKey: String, keyType: PgpKey) throws {
|
||||
let pgpKeyData = armorKey.data(using: .ascii)!
|
||||
AppKeychain.add(data: pgpKeyData, for: keyType.getKeychainKey())
|
||||
try initPGPKey(keyType)
|
||||
}
|
||||
|
||||
public func repositoryExisted() -> Bool {
|
||||
let fm = FileManager()
|
||||
return fm.fileExists(atPath: Globals.repositoryPath)
|
||||
|
|
@ -758,20 +678,13 @@ public class PasswordStore {
|
|||
}
|
||||
}
|
||||
|
||||
public func erase() {
|
||||
publicKey = nil
|
||||
privateKey = nil
|
||||
publicKeyV2 = nil
|
||||
privateKeyV2 = nil
|
||||
keyring.deleteAll()
|
||||
|
||||
try? fm.removeItem(at: storeURL)
|
||||
public func erase() {try? fm.removeItem(at: storeURL)
|
||||
try? fm.removeItem(at: tempStoreURL)
|
||||
|
||||
try? fm.removeItem(atPath: Globals.pgpPublicKeyPath)
|
||||
try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath)
|
||||
try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
|
||||
self.pgpAgent?.removePGPKeys()
|
||||
|
||||
AppKeychain.removeAllContent()
|
||||
|
||||
deleteCoreData(entityName: "PasswordEntity")
|
||||
|
|
@ -828,66 +741,27 @@ public class PasswordStore {
|
|||
return try storeRepository.localCommitsRelative(toRemoteBranch: remoteBranch)
|
||||
}
|
||||
|
||||
|
||||
|
||||
public func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? {
|
||||
let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.getPath())
|
||||
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
||||
var passphrase = self.pgpKeyPassphrase
|
||||
if passphrase == nil {
|
||||
passphrase = requestPGPKeyPassphrase()
|
||||
guard let decryptedData = try self.pgpAgent?.decrypt(encryptedData: encryptedData, requestPGPKeyPassphrase: requestPGPKeyPassphrase) else {
|
||||
throw AppError.Decryption
|
||||
}
|
||||
// Try Gopenpgp.
|
||||
if let decryptedData = privateKey?.decrypt(encryptedData, passphrase: passphrase) {
|
||||
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
||||
let url = try passwordEntity.getURL()
|
||||
return Password(name: passwordEntity.getName(), url: url, plainText: plainText)
|
||||
}
|
||||
// Try ObjectivePGP.
|
||||
if let decryptedData = try? ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys, passphraseForKey: {(_) in passphrase}) {
|
||||
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
||||
let url = try passwordEntity.getURL()
|
||||
return Password(name: passwordEntity.getName(), url: url, plainText: plainText)
|
||||
}
|
||||
throw AppError.Decryption
|
||||
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
|
||||
let url = try passwordEntity.getURL()
|
||||
return Password(name: passwordEntity.getName(), url: url, plainText: plainText)
|
||||
}
|
||||
|
||||
public func encrypt(password: Password) throws -> Data {
|
||||
guard publicKey != nil || keyring.keys.count > 0 else {
|
||||
throw AppError.PgpPublicKeyNotExist
|
||||
}
|
||||
let plainData = password.plainData
|
||||
// Try Gopenpgp.
|
||||
if let encryptedData = publicKey?.encrypt(plainData, armor: SharedDefaults[.encryptInArmored]) {
|
||||
return encryptedData
|
||||
guard let encryptedData = try self.pgpAgent?.encrypt(plainData: plainData) else {
|
||||
throw AppError.Encryption
|
||||
}
|
||||
// Try ObjectivePGP.
|
||||
if let encryptedData = try? ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil) {
|
||||
if SharedDefaults[.encryptInArmored] {
|
||||
return Armor.armored(encryptedData, as: .message).data(using: .utf8)!
|
||||
} else {
|
||||
return encryptedData
|
||||
}
|
||||
}
|
||||
throw AppError.Encryption
|
||||
return encryptedData
|
||||
}
|
||||
|
||||
public func removePGPKeys() {
|
||||
try? fm.removeItem(atPath: Globals.pgpPublicKeyPath)
|
||||
try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath)
|
||||
SharedDefaults.remove(.pgpKeySource)
|
||||
SharedDefaults.remove(.pgpPrivateKeyURL)
|
||||
SharedDefaults.remove(.pgpPublicKeyURL)
|
||||
SharedDefaults.remove(.pgpPublicKeyArmor)
|
||||
SharedDefaults.remove(.pgpPrivateKeyArmor)
|
||||
AppKeychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
|
||||
AppKeychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
|
||||
pgpKeyPassphrase = nil
|
||||
publicKey = nil
|
||||
privateKey = nil
|
||||
publicKeyV2 = nil
|
||||
privateKeyV2 = nil
|
||||
keyring.deleteAll()
|
||||
self.pgpAgent?.removePGPKeys()
|
||||
}
|
||||
|
||||
public func removeGitSSHKeys() {
|
||||
|
|
@ -910,9 +784,4 @@ public class PasswordStore {
|
|||
public func gitSSHKeyImportFromFileSharing() throws {
|
||||
try KeyFileManager.PrivateSsh.importKeyAndDeleteFile()
|
||||
}
|
||||
|
||||
public func pgpKeyImportFromFileSharing() throws {
|
||||
try KeyFileManager.PublicPgp.importKeyAndDeleteFile()
|
||||
try KeyFileManager.PrivatePgp.importKeyAndDeleteFile()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
83
passKitTests/Models/PGPAgentTest.swift
Normal file
83
passKitTests/Models/PGPAgentTest.swift
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// PGPAgent.swift
|
||||
// passKitTests
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import passKit
|
||||
|
||||
class PGPAgentTest: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
print("setup")
|
||||
AppKeychain.removeAllContent()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
print("tearDown")
|
||||
AppKeychain.removeAllContent()
|
||||
}
|
||||
|
||||
func encrypt_decrypt(pgpAgent: PGPAgent) {
|
||||
// Encrypt and decrypt.
|
||||
let plainData = "Hello World!".data(using: .utf8)!
|
||||
let encryptedData = try? pgpAgent.encrypt(plainData: plainData)
|
||||
XCTAssertNotNil(encryptedData)
|
||||
let decryptedData = try? pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
XCTAssertEqual(plainData, decryptedData)
|
||||
}
|
||||
|
||||
func testInitPGPKey() {
|
||||
let pgpAgent = PGPAgent()
|
||||
|
||||
// [RSA2048] Setup keys.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.imported)
|
||||
self.encrypt_decrypt(pgpAgent: pgpAgent)
|
||||
let pgpAgent2 = PGPAgent()
|
||||
try? pgpAgent2.initPGPKeys() // load from the keychain
|
||||
self.encrypt_decrypt(pgpAgent: pgpAgent2)
|
||||
|
||||
// [RSA2048] Setup keys. The private key is a subkey.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_SUBKEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.imported)
|
||||
self.encrypt_decrypt(pgpAgent: pgpAgent)
|
||||
|
||||
// [ED25519] Setup keys.
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertTrue(pgpAgent.imported)
|
||||
self.encrypt_decrypt(pgpAgent: pgpAgent)
|
||||
}
|
||||
|
||||
func testInitPGPKeyBadPrivateKeys() {
|
||||
let pgpAgent = PGPAgent()
|
||||
let plainData = "Hello World!".data(using: .utf8)!
|
||||
|
||||
// [RSA2048] Setup the public key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PUBLIC)
|
||||
let encryptedData = try? pgpAgent.encrypt(plainData: plainData)
|
||||
XCTAssertNotNil(encryptedData)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
// Wrong private key: a public key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PUBLIC_KEY, keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
// Wrong private key: an unmatched private key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_ED25519_PRIVATE_KEY, keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
|
||||
/// Wrong private key: a corrupted private key.
|
||||
try? pgpAgent.initPGPKey(with: PGP_RSA2048_PRIVATE_KEY.replacingOccurrences(of: "1", with: ""), keyType: .PRIVATE)
|
||||
XCTAssertThrowsError(try pgpAgent.decrypt(encryptedData: encryptedData!, requestPGPKeyPassphrase: requestPGPKeyPassphrase))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
212
passKitTests/TestPGPKeys.swift
Normal file
212
passKitTests/TestPGPKeys.swift
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
//
|
||||
// TestPGPKeys.swift
|
||||
// passKitTests
|
||||
//
|
||||
// Created by Yishi Lin on 2019/7/17.
|
||||
// Copyright © 2019 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import passKit
|
||||
|
||||
func requestPGPKeyPassphrase() -> String {
|
||||
return "passforios"
|
||||
}
|
||||
|
||||
let PGP_RSA2048_PUBLIC_KEY = """
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBF0uBLkBCADGYAW5yJQ/lLHmHdb/l0bhYyLnhuyWTaOWIEHGiDnpjO71vBPD
|
||||
WMPxPulj/GGdqzR4lUUanPG1yJwXTjNutjMBZ/o+ixgdqja391b4L8VyF5Lb7pHX
|
||||
c6uvbR6p1Tj72PJrVj6Ev71VdnsHNOLUDqWZL4b0dNXPf3sM4ry5yS6Ej6ho9o/l
|
||||
nuYbe9WfLqUctSM+TsXd84ptc6luIHZN+cojrNGAh3RLYuVFeJjkLkvHdJBWJQS2
|
||||
zJ0iAA6T0NbfPGrVL6tMaB7NwMDN33Ql3ARfaHf7/d8DXGYyGUYZFqyKagGUaBxN
|
||||
arXfzv9gIyc109D8pPMN5QUiEo9K4x3xNpLhABEBAAG0KnBhc3Nmb3Jpb3MgPGRl
|
||||
dmVsb3BlckBwYXNzZm9yaW9zLm1zc3VuLm1lPokBTgQTAQgAOAIbAwULCQgHAgYV
|
||||
CgkICwIEFgIDAQIeAQIXgBYhBEcSKGJxIg2ymYg+pwYuZ42hAk2uBQJdLgWNAAoJ
|
||||
EAYuZ42hAk2uYjIH/iPsoJD+KfJ/c7GTSLbeMtQtuIv2sCiSc+BiXp+EFjbNS7oS
|
||||
cEYiG/FX1zuivr3wvDGbE/oVLvdTK8tDJvCh17SZZUGeTmflgByig+1/kp5JUj2x
|
||||
FOH3xXCVCnh+FWB24QHLiFpwgzGuZgCKMn45PcZB7Zmo/wJsKYb040zKltQWmzg8
|
||||
rZ1vOKlMgAGgdNQOu+u+8OE6x/dedYvJZePvwND4Rva+EwS+MaEZZAn76ypEblhF
|
||||
pRZsTb6+PeTY+IWRnne7xUvYRmZLXhqoHq/c0hXXz2xAGmpigd50HUQRUOYtsuBi
|
||||
RxXLwFIlfPpziomMTdhnOFVDL6UVLL+jqJDPHWu5AQ0EXS4EuQEIAMwr3I+NUsY+
|
||||
Iwyyz6C84z90kHPs9zOBvGc73Tgc70lXHUklwQaqLSmLbHQzk6Ykw/o1snQ8Oz2f
|
||||
AjPlBr9/zWJgOvnFH+FrjpfEpmz4WjmoxBK610JINkKW4Fn4VT/NrBL9LtjaZOLp
|
||||
0XA6fh8TXTOsz80jDj1VPvNAsu78FC+zXFDvOJpX+bCv3vabO9/ihKL/emvgqzxD
|
||||
LO9IapPfL1rPvCmfaNZ8hRV8ebHOW0pVLfyOYn4pvwtL/uYIINv1CYAwOGVW1sth
|
||||
8kS8Acj4VTDkynuobxiLDTpNrRUbt0iPn/2nJ8m1qq9hqWgO2z01UkSKrusDiMNH
|
||||
TnHFepgG8NMAEQEAAYkBPAQYAQgAJhYhBEcSKGJxIg2ymYg+pwYuZ42hAk2uBQJd
|
||||
LgS5AhsMBQkDwmcAAAoJEAYuZ42hAk2u+rkIAKEwherMhNV+kZpZMoYLop9ULTNx
|
||||
RQtBhNK5No7MpGzJnGbJzXo2+CaB7wlOzzDympIVxth+St7S4BiSdMxrnQVzzZOf
|
||||
Lfvc6+AyWBwpM32i/s5piTCwn+RoQzYHQpiRBmeGRBXC2tTkAh+zXhed7yZR5mMK
|
||||
lsVq9BRfVFxbkh9S1YWLUC29n32eiAo/6nLyJw/AOlv37ThYPnIeSqrASs0Jh69C
|
||||
iNbGUq2SzH1yj1cxWvhZqXA8WpbU/pZM6LR6eIeLOa+BTp0Ax6j2QQ3N3bKEcOTz
|
||||
ncsjMsi8gUJaucHKKRcGXY0AlWAbvH1ytWboh+CgS493JfZbNRCXTWA/BDE=
|
||||
=2FVp
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
"""
|
||||
|
||||
let PGP_RSA2048_PRIVATE_KEY = """
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
=qgCJ
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
"""
|
||||
|
||||
let PGP_RSA2048_PRIVATE_SUBKEY = """
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
XY0AlWAbvH1ytWboh+CgS493JfZbNRCXTWA/BDE=
|
||||
=qBfw
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
"""
|
||||
|
||||
let PGP_ED25519_PUBLIC_KEY = """
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEXS4TMRYJKwYBBAHaRw8BAQdAW/U3l3/bMWFxHaCQ3Kr8Wel5322hgiVGO39K
|
||||
mk+NLYO0KnBhc3Nmb3Jpb3MgPGRldmVsb3BlckBwYXNzZm9yaW9zLm1zc3VuLm1l
|
||||
PoiQBBMWCAA4FiEEX8ywgauK9IlymZ4q51Csv+lERIMFAl0uEzECGwMFCwkIBwIG
|
||||
FQoJCAsCBBYCAwECHgECF4AACgkQ51Csv+lERIM0RgEAtw6VI0hbhIiSCZuHfePn
|
||||
3XmXQnSkfYw6OrND86vNPEgBAIcymV45aM3IUMi7cczlNemdc4vzvZ2sahN4I9bp
|
||||
zygDuDgEXS4TMRIKKwYBBAGXVQEFAQEHQDEc6qSqOJHTY/QBMBCuH2NPbc3jfJKe
|
||||
3zN15IWfji9hAwEIB4h4BBgWCAAgFiEEX8ywgauK9IlymZ4q51Csv+lERIMFAl0u
|
||||
EzECGwwACgkQ51Csv+lERIMOsAEA43pkVP9br/TmESz/IuTZBfVAexAA3Q9DRL7M
|
||||
NcZVu2wA/js8TfomM2QBmZYPSZFPzA1nI1FzzgPhFgy6fGLgpZUL
|
||||
=4EF6
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
"""
|
||||
|
||||
let PGP_ED25519_PRIVATE_KEY = """
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
lIYEXS4TMRYJKwYBBAHaRw8BAQdAW/U3l3/bMWFxHaCQ3Kr8Wel5322hgiVGO39K
|
||||
mk+NLYP+BwMCw1EywRMGVRHmRf963xPpOVBluE38pFvriDQXbceoPZVdgyr+M2Ef
|
||||
3HFn8t/ZyTzeZQZIgmlAFNgiDaz3I+CISN89uVFt7yJVGzbuvjgVSrQqcGFzc2Zv
|
||||
cmlvcyA8ZGV2ZWxvcGVyQHBhc3Nmb3Jpb3MubXNzdW4ubWU+iJAEExYIADgWIQRf
|
||||
zLCBq4r0iXKZnirnUKy/6UREgwUCXS4TMQIbAwULCQgHAgYVCgkICwIEFgIDAQIe
|
||||
AQIXgAAKCRDnUKy/6UREgzRGAQC3DpUjSFuEiJIJm4d94+fdeZdCdKR9jDo6s0Pz
|
||||
q808SAEAhzKZXjlozchQyLtxzOU16Z1zi/O9naxqE3gj1unPKAOciwRdLhMxEgor
|
||||
BgEEAZdVAQUBAQdAMRzqpKo4kdNj9AEwEK4fY09tzeN8kp7fM3XkhZ+OL2EDAQgH
|
||||
/gcDAsJwqoLIpKyw5lJwU83TfgSJJLrBR6KGLB1oZigRAasw++69iC19yUS6FY3M
|
||||
mRiOrYeBatYCoXY8xolbStkhZl2y9KYlPcFNWOQvVKtuUT2IeAQYFggAIBYhBF/M
|
||||
sIGrivSJcpmeKudQrL/pRESDBQJdLhMxAhsMAAoJEOdQrL/pRESDDrABAON6ZFT/
|
||||
W6/05hEs/yLk2QX1QHsQAN0PQ0S+zDXGVbtsAP47PE36JjNkAZmWD0mRT8wNZyNR
|
||||
c84D4RYMunxi4KWVCw==
|
||||
=nV4i
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
"""
|
||||
|
||||
let PGP_ED25519_PRIVATE_SUBKEY = """
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
lDsEXS4TMRYJKwYBBAHaRw8BAQdAW/U3l3/bMWFxHaCQ3Kr8Wel5322hgiVGO39K
|
||||
mk+NLYP/AGUAR05VAbQqcGFzc2ZvcmlvcyA8ZGV2ZWxvcGVyQHBhc3Nmb3Jpb3Mu
|
||||
bXNzdW4ubWU+iJAEExYIADgWIQRfzLCBq4r0iXKZnirnUKy/6UREgwUCXS4TMQIb
|
||||
AwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRDnUKy/6UREgzRGAQC3DpUjSFuE
|
||||
iJIJm4d94+fdeZdCdKR9jDo6s0Pzq808SAEAhzKZXjlozchQyLtxzOU16Z1zi/O9
|
||||
naxqE3gj1unPKAOciwRdLhMxEgorBgEEAZdVAQUBAQdAMRzqpKo4kdNj9AEwEK4f
|
||||
Y09tzeN8kp7fM3XkhZ+OL2EDAQgH/gcDAk55ulCfKROW5kyrg18FeoHR+DNPhKVV
|
||||
7R2CyAinW5c4+SiLk+P4Zbgue1JEmCNqhckywVx6LOFoR3OdJRFumfuacB82QUY+
|
||||
p9VjMutDAO+IeAQYFggAIBYhBF/MsIGrivSJcpmeKudQrL/pRESDBQJdLhMxAhsM
|
||||
AAoJEOdQrL/pRESDDrABAON6ZFT/W6/05hEs/yLk2QX1QHsQAN0PQ0S+zDXGVbts
|
||||
AP47PE36JjNkAZmWD0mRT8wNZyNRc84D4RYMunxi4KWVCw==
|
||||
=4Sfz
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
"""
|
||||
Loading…
Add table
Add a link
Reference in a new issue