Introduce KeyImporter protocol to reduce code duplications in SSH key importers

This commit is contained in:
Danny Moesch 2020-02-15 18:12:58 +01:00 committed by Mingshen Sun
parent 6aa39db657
commit 94a5f8c501
14 changed files with 189 additions and 144 deletions

View file

@ -20,6 +20,7 @@
3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032327322C7F710009EBD9C /* KeyFileManager.swift */; }; 3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032327322C7F710009EBD9C /* KeyFileManager.swift */; };
3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */; }; 3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */; };
3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */; }; 3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */; };
30650E7323F847FC005CCD5E /* KeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7223F847FC005CCD5E /* KeyImporter.swift */; };
3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */; }; 3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */; };
30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2321F63C580064FCAC /* NotificationNames.swift */; }; 30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2321F63C580064FCAC /* NotificationNames.swift */; };
30697C2B21F63C5A0064FCAC /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2421F63C590064FCAC /* Globals.swift */; }; 30697C2B21F63C5A0064FCAC /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2421F63C590064FCAC /* Globals.swift */; };
@ -241,6 +242,7 @@
3032327322C7F710009EBD9C /* KeyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManager.swift; sourceTree = "<group>"; }; 3032327322C7F710009EBD9C /* KeyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManager.swift; sourceTree = "<group>"; };
3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManagerTest.swift; sourceTree = "<group>"; }; 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManagerTest.swift; sourceTree = "<group>"; };
3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptographicKeys.swift; sourceTree = "<group>"; }; 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptographicKeys.swift; sourceTree = "<group>"; };
30650E7223F847FC005CCD5E /* KeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyImporter.swift; sourceTree = "<group>"; };
3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPKeyImporter.swift; sourceTree = "<group>"; }; 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPKeyImporter.swift; sourceTree = "<group>"; };
30697C2321F63C580064FCAC /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; }; 30697C2321F63C580064FCAC /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; };
30697C2421F63C590064FCAC /* Globals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = "<group>"; }; 30697C2421F63C590064FCAC /* Globals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = "<group>"; };
@ -704,6 +706,7 @@
DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */, DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */,
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */, A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift */,
DCA049991E335CC800522E8F /* GitRepositorySettingsTableViewController.swift */, DCA049991E335CC800522E8F /* GitRepositorySettingsTableViewController.swift */,
30650E7223F847FC005CCD5E /* KeyImporter.swift */,
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */, DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */,
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */, DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */,
DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */, DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */,
@ -1406,6 +1409,7 @@
DCFB779E1E4F40C7008DE471 /* FillPasswordTableViewCell.swift in Sources */, DCFB779E1E4F40C7008DE471 /* FillPasswordTableViewCell.swift in Sources */,
A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */, A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */,
DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */, DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */,
30650E7323F847FC005CCD5E /* KeyImporter.swift in Sources */,
A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift in Sources */, A217ACE41E9BBBBD00A1A6CF /* GitConfigSettingsTableViewController.swift in Sources */,
9AA710CA23939C68009E3213 /* GitCredentialPassword.swift in Sources */, 9AA710CA23939C68009E3213 /* GitCredentialPassword.swift in Sources */,
DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */, DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */,

View file

@ -1031,9 +1031,11 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
</navigationItem> </navigationItem>
<connections> <connections>
<outlet property="privateKeyURLTextField" destination="4iJ-oB-R1f" id="scx-lz-dUW"/> <outlet property="privateKeyURLTextField" destination="4iJ-oB-R1f" id="scx-lz-dUW"/>
<segue destination="bXG-pY-DH6" kind="unwind" identifier="importSSHKeySegue" unwindAction="importSSHKeyWithSegue:" id="vGk-Xa-meP"/>
</connections> </connections>
</tableViewController> </tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="eY3-aM-BJB" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="eY3-aM-BJB" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="bXG-pY-DH6" userLabel="Exit" sceneMemberID="exit"/>
</objects> </objects>
<point key="canvasLocation" x="6990" y="2239"/> <point key="canvasLocation" x="6990" y="2239"/>
</scene> </scene>
@ -1558,9 +1560,11 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
<outlet property="armorPrivateKeyTextView" destination="23o-MP-wQY" id="ybK-Ba-vJt"/> <outlet property="armorPrivateKeyTextView" destination="23o-MP-wQY" id="ybK-Ba-vJt"/>
<outlet property="scanPrivateKeyCell" destination="jXO-n0-Mvx" id="Zdb-wm-7Ls"/> <outlet property="scanPrivateKeyCell" destination="jXO-n0-Mvx" id="Zdb-wm-7Ls"/>
<segue destination="LZE-gF-IcM" kind="show" identifier="showSSHScannerSegue" id="oxP-I1-Mke"/> <segue destination="LZE-gF-IcM" kind="show" identifier="showSSHScannerSegue" id="oxP-I1-Mke"/>
<segue destination="Vrv-hO-eSS" kind="unwind" identifier="importSSHKeySegue" unwindAction="importSSHKeyWithSegue:" id="zgs-se-tr3"/>
</connections> </connections>
</tableViewController> </tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="qJO-AN-K9p" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="qJO-AN-K9p" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="Vrv-hO-eSS" userLabel="Exit" sceneMemberID="exit"/>
</objects> </objects>
<point key="canvasLocation" x="6083" y="3668"/> <point key="canvasLocation" x="6083" y="3668"/>
</scene> </scene>

View file

@ -213,78 +213,65 @@ class GitRepositorySettingsTableViewController: UITableViewController {
} }
} }
@IBAction func importSSHKey(segue: UIStoryboardSegue) {
guard let sourceController = segue.source as? KeyImporter, sourceController.isReadyToUse() else {
return
}
importSSHKey(using: sourceController)
}
private func importSSHKey(using keyImporter: KeyImporter) {
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do {
try keyImporter.importKeys()
DispatchQueue.main.async {
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
SVProgressHUD.dismiss(withDelay: 1)
}
Defaults.gitSSHKeySource = type(of: keyImporter).keySource
self.gitAuthenticationMethod = .key
self.sshLabel?.isEnabled = true
} catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self)
}
}
}
// MARK: - Helper Functions // MARK: - Helper Functions
private func showSSHKeyActionSheet() { private func showSSHKeyActionSheet() {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
var urlActionTitle = "DownloadFromUrl".localize() optionMenu.addAction(UIAlertAction(title: SSHKeyUrlImportTableViewController.menuLabel, style: .default) { _ in
var armorActionTitle = "AsciiArmorEncryptedKey".localize()
var fileActionTitle = "ITunesFileSharing".localize()
switch Defaults.gitSSHKeySource {
case .url: urlActionTitle = "\(urlActionTitle)"
case .armor: armorActionTitle = "\(armorActionTitle)"
case .file: fileActionTitle = "\(fileActionTitle)"
case .none: break
}
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
} })
optionMenu.addAction(urlAction) optionMenu.addAction(UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
})
if isReadyToUse() {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in
self.importSSHKey(using: self)
})
} else {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in
let title = "Tips".localize()
let message = "SshCopyPrivateKeyToPass.".localize()
Utils.alert(title: title, message: message, controller: self)
})
} }
optionMenu.addAction(armorAction)
let fileAction: UIAlertAction = {
if KeyFileManager.PrivateSsh.doesKeyFileExist() {
fileActionTitle.append(" (\("Import".localize()))")
let action = UIAlertAction(title: fileActionTitle, style: .default) { _ in
do {
try self.passwordStore.gitSSHKeyImportFromFileSharing()
Defaults.gitSSHKeySource = .file
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
SVProgressHUD.dismiss(withDelay: 1)
self.sshLabel?.isEnabled = true
self.gitAuthenticationMethod = .key
self.updateAuthenticationMethodCheckView(for: self.gitAuthenticationMethod)
} catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self)
}
}
return action
} else {
fileActionTitle.append(" (\("Tips".localize()))")
let action = UIAlertAction(title: fileActionTitle, style: .default) { _ in
let title = "Tips".localize()
let message = "SshCopyPrivateKeyToPass.".localize()
Utils.alert(title: title, message: message, controller: self)
}
return action
}
}()
optionMenu.addAction(fileAction)
if Defaults.gitSSHKeySource != nil { if Defaults.gitSSHKeySource != nil {
let deleteAction = UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in optionMenu.addAction(UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in
self.passwordStore.removeGitSSHKeys() self.passwordStore.removeGitSSHKeys()
Defaults.gitSSHKeySource = nil Defaults.gitSSHKeySource = nil
self.sshLabel?.isEnabled = false self.sshLabel?.isEnabled = false
self.updateAuthenticationMethodCheckView(for: .password) self.gitAuthenticationMethod = .password
} })
optionMenu.addAction(deleteAction)
} }
optionMenu.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil))
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
optionMenu.addAction(cancelAction)
optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell
optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds
present(optionMenu, animated: true)
self.present(optionMenu, animated: true)
} }
private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? { private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
@ -313,5 +300,18 @@ class GitRepositorySettingsTableViewController: UITableViewController {
""" """
Utils.alert(title: "Git URL Format", message: message, controller: self) Utils.alert(title: "Git URL Format", message: message, controller: self)
} }
}
extension GitRepositorySettingsTableViewController: KeyImporter {
static let keySource = KeySource.itunes
static let label = "ITunesFileSharing".localize()
func isReadyToUse() -> Bool {
return KeyFileManager.PrivateSsh.doesKeyFileExist()
}
func importKeys() throws {
try KeyFileManager.PrivateSsh.importKeyFromFileSharing()
}
} }

View file

@ -0,0 +1,36 @@
//
// KeyImporter.swift
// pass
//
// Created by Danny Moesch on 15.02.20.
// Copyright © 2020 Bob Sun. All rights reserved.
//
import passKit
protocol KeyImporter {
static var keySource: KeySource { get }
static var label: String { get }
static var menuLabel: String { get }
func isReadyToUse() -> Bool
func importKeys() throws
}
extension KeyImporter {
static var isCurrentKeySource: Bool {
return Defaults.gitSSHKeySource == Self.keySource
}
static var menuLabel: String {
if isCurrentKeySource {
return "\(Self.label)"
}
return Self.label
}
}

View file

@ -10,13 +10,11 @@ import UIKit
import passKit import passKit
class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate { class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
@IBOutlet weak var armorPublicKeyTextView: UITextView! @IBOutlet weak var armorPublicKeyTextView: UITextView!
@IBOutlet weak var armorPrivateKeyTextView: UITextView! @IBOutlet weak var armorPrivateKeyTextView: UITextView!
@IBOutlet weak var scanPublicKeyCell: UITableViewCell! @IBOutlet weak var scanPublicKeyCell: UITableViewCell!
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell! @IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
let passwordStore = PasswordStore.shared
let keychain = AppKeychain.shared
class ScannedPGPKey { class ScannedPGPKey {
enum KeyType { enum KeyType {
@ -132,7 +130,7 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
extension PGPKeyArmorImportTableViewController: PGPKeyImporter { extension PGPKeyArmorImportTableViewController: PGPKeyImporter {
static let keySource = PGPKeySource.armor static let keySource = KeySource.armor
static let label = "AsciiArmorEncryptedKey".localize() static let label = "AsciiArmorEncryptedKey".localize()
func isReadyToUse() -> Bool { func isReadyToUse() -> Bool {
@ -152,10 +150,6 @@ extension PGPKeyArmorImportTableViewController: PGPKeyImporter {
try KeyFileManager.PrivatePgp.importKey(from: armorPrivateKeyTextView.text ?? "") try KeyFileManager.PrivatePgp.importKey(from: armorPrivateKeyTextView.text ?? "")
} }
func doAfterImport() {
}
func saveImportedKeys() { func saveImportedKeys() {
performSegue(withIdentifier: "savePGPKeySegue", sender: self) performSegue(withIdentifier: "savePGPKeySegue", sender: self)
} }

View file

@ -13,9 +13,6 @@ class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var pgpPublicKeyFile: UITableViewCell! @IBOutlet weak var pgpPublicKeyFile: UITableViewCell!
@IBOutlet weak var pgpPrivateKeyFile: UITableViewCell! @IBOutlet weak var pgpPrivateKeyFile: UITableViewCell!
private let passwordStore = PasswordStore.shared
private let keychain = AppKeychain.shared
private var publicKey: String? = nil private var publicKey: String? = nil
private var privateKey: String? = nil private var privateKey: String? = nil
@ -72,7 +69,7 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
extension PGPKeyFileImportTableViewController: PGPKeyImporter { extension PGPKeyFileImportTableViewController: PGPKeyImporter {
static let keySource = PGPKeySource.files static let keySource = KeySource.file
static let label = "LoadFromFiles".localize() static let label = "LoadFromFiles".localize()
func isReadyToUse() -> Bool { func isReadyToUse() -> Bool {

View file

@ -8,17 +8,7 @@
import passKit import passKit
protocol PGPKeyImporter { protocol PGPKeyImporter: KeyImporter {
static var keySource: PGPKeySource { get }
static var label: String { get }
static var menuLabel: String { get }
func isReadyToUse() -> Bool
func importKeys() throws
func doAfterImport() func doAfterImport()
@ -26,12 +16,13 @@ protocol PGPKeyImporter {
} }
extension PGPKeyImporter { extension PGPKeyImporter {
static var menuLabel: String { static var isCurrentKeySource: Bool {
if Defaults.pgpKeySource == Self.keySource { return Defaults.pgpKeySource == Self.keySource
return "\(Self.label)" }
}
return Self.label func doAfterImport() {
} }
} }

View file

@ -14,9 +14,6 @@ class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var pgpPublicKeyURLTextField: UITextField! @IBOutlet weak var pgpPublicKeyURLTextField: UITextField!
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField! @IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
let passwordStore = PasswordStore.shared
let keychain = AppKeychain.shared
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
pgpPublicKeyURLTextField.text = Defaults.pgpPublicKeyURL?.absoluteString pgpPublicKeyURLTextField.text = Defaults.pgpPublicKeyURL?.absoluteString
@ -46,7 +43,7 @@ class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
extension PGPKeyUrlImportTableViewController: PGPKeyImporter { extension PGPKeyUrlImportTableViewController: PGPKeyImporter {
static let keySource = PGPKeySource.url static let keySource = KeySource.url
static let label = "DownloadFromUrl".localize() static let label = "DownloadFromUrl".localize()
func isReadyToUse() -> Bool { func isReadyToUse() -> Bool {

View file

@ -10,11 +10,11 @@ import UIKit
import passKit import passKit
class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate { class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
@IBOutlet weak var armorPrivateKeyTextView: UITextView! @IBOutlet weak var armorPrivateKeyTextView: UITextView!
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell! @IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
var gitSSHPrivateKeyPassphrase: String? var gitSSHPrivateKeyPassphrase: String?
let passwordStore = PasswordStore.shared
class ScannedSSHKey { class ScannedSSHKey {
var segments = [String]() var segments = [String]()
@ -60,10 +60,7 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
} }
@IBAction func doneButtonTapped(_ sender: Any) { @IBAction func doneButtonTapped(_ sender: Any) {
AppKeychain.shared.add(string: armorPrivateKeyTextView.text, for: SshKey.PRIVATE.getKeychainKey()) performSegue(withIdentifier: "importSSHKeySegue", sender: self)
Defaults.gitSSHKeySource = .armor
Defaults.gitAuthenticationMethod = .key
self.navigationController!.popViewController(animated: true)
} }
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
@ -109,5 +106,22 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
@IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) { @IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) {
} }
}
extension SSHKeyArmorImportTableViewController: KeyImporter {
static let keySource = KeySource.armor
static let label = "AsciiArmorEncryptedKey".localize()
func isReadyToUse() -> Bool {
guard !armorPrivateKeyTextView.text.isEmpty else {
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKey.".localize(), controller: self)
return false
}
return true
}
func importKeys() throws {
try KeyFileManager.PrivateSsh.importKey(from: armorPrivateKeyTextView.text ?? "")
}
} }

View file

@ -6,34 +6,55 @@
// Copyright © 2017 Bob Sun. All rights reserved. // Copyright © 2017 Bob Sun. All rights reserved.
// //
import UIKit
import SVProgressHUD import SVProgressHUD
import passKit import passKit
class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController { class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var privateKeyURLTextField: UITextField! @IBOutlet weak var privateKeyURLTextField: UITextField!
let passwordStore = PasswordStore.shared
@IBAction func doneButtonTapped(_ sender: UIButton) { override func viewDidLoad() {
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else { super.viewDidLoad()
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self, completion: nil) privateKeyURLTextField.text = Defaults.gitSSHPrivateKeyURL?.absoluteString
return
}
do {
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: SshKey.PRIVATE.getFileSharingPath()), options: .atomic)
try self.passwordStore.gitSSHKeyImportFromFileSharing()
Defaults.gitSSHKeySource = .file
Defaults.gitAuthenticationMethod = .key
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
SVProgressHUD.dismiss(withDelay: 1)
} catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
}
Defaults.gitSSHKeySource = .url
self.navigationController!.popViewController(animated: true)
} }
@IBAction func doneButtonTapped(_ sender: UIButton) {
if getScheme(from: privateKeyURLTextField.text?.trimmed) == "http" {
let savePassphraseAlert = UIAlertController(title: "HttpNotSecure".localize(), message: "ReallyUseHttp?".localize(), preferredStyle: .alert)
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in })
savePassphraseAlert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
self.performSegue(withIdentifier: "importSSHKeySegue", sender: self)
})
return present(savePassphraseAlert, animated: true)
}
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
private func getScheme(from url: String?) -> String? {
return url.flatMap(URL.init(string:))?.scheme
}
}
extension SSHKeyUrlImportTableViewController: KeyImporter {
static let keySource = KeySource.url
static let label = "DownloadFromUrl".localize()
func isReadyToUse() -> Bool {
guard let scheme = getScheme(from: privateKeyURLTextField.text?.trimmed) else {
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
return false
}
guard scheme == "https" || scheme == "http" else {
Utils.alert(title: "CannotSave".localize(), message: "UseEitherHttpsOrHttp.".localize(), controller: self)
return false
}
return true
}
func importKeys() throws {
Defaults.gitSSHPrivateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed)
try KeyFileManager.PrivateSsh.importKey(from: Defaults.gitSSHPrivateKeyURL!)
}
} }

View file

@ -153,19 +153,18 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
} }
if Defaults.pgpKeySource != nil { if Defaults.pgpKeySource != nil {
let deleteAction = UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in optionMenu.addAction(UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in
self.keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey()) self.keychain.removeContent(for: PgpKey.PUBLIC.getKeychainKey())
self.keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey()) self.keychain.removeContent(for: PgpKey.PRIVATE.getKeychainKey())
PGPAgent.shared.uninitKeys() PGPAgent.shared.uninitKeys()
self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize() self.pgpKeyTableViewCell.detailTextLabel?.text = "NotSet".localize()
Defaults.pgpKeySource = nil Defaults.pgpKeySource = nil
} })
optionMenu.addAction(deleteAction)
} }
optionMenu.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)) optionMenu.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil))
optionMenu.popoverPresentationController?.sourceView = pgpKeyTableViewCell optionMenu.popoverPresentationController?.sourceView = pgpKeyTableViewCell
optionMenu.popoverPresentationController?.sourceRect = pgpKeyTableViewCell.bounds optionMenu.popoverPresentationController?.sourceRect = pgpKeyTableViewCell.bounds
self.present(optionMenu, animated: true, completion: nil) present(optionMenu, animated: true)
} }
func showPasscodeActionSheet() { func showPasscodeActionSheet() {
@ -243,7 +242,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
extension SettingsTableViewController: PGPKeyImporter { extension SettingsTableViewController: PGPKeyImporter {
static let keySource = PGPKeySource.itunes static let keySource = KeySource.itunes
static let label = "ITunesFileSharing".localize() static let label = "ITunesFileSharing".localize()
func isReadyToUse() -> Bool { func isReadyToUse() -> Bool {
@ -255,11 +254,7 @@ extension SettingsTableViewController: PGPKeyImporter {
try KeyFileManager.PrivatePgp.importKeyFromFileSharing() try KeyFileManager.PrivatePgp.importKeyFromFileSharing()
} }
func doAfterImport() {
}
func saveImportedKeys() { func saveImportedKeys() {
self.savePGPKey(using: self) savePGPKey(using: self)
} }
} }

View file

@ -101,7 +101,7 @@
"CannotSelectSshKey" = "Cannot Select SSH Key"; "CannotSelectSshKey" = "Cannot Select SSH Key";
"PleaseSetupSshKeyFirst." = "Please setup SSH key first."; "PleaseSetupSshKeyFirst." = "Please setup SSH key first.";
"RemoveSShKeys" = "Remove Git SSH Keys"; "RemoveSShKeys" = "Remove Git SSH Keys";
"SetPrivateKeyUrl." = "Please set private key URL first."; "SetPrivateKeyUrl." = "Please set a valid private key URL first.";
"SshCopyPrivateKeyToPass." = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish."; "SshCopyPrivateKeyToPass." = "Copy your ASCII-armored private key to Pass with the name \"ssh_key\" (without quotes) via iTunes. Then come back and click \"iTunes File Sharing\" to finish.";
// QR code scanning // QR code scanning
@ -113,8 +113,8 @@
"ScanPrivateKey." = "Please scan private key."; "ScanPrivateKey." = "Please scan private key.";
"ScanPrivateKeyQrCodes" = "Scan Private Key QR codes"; "ScanPrivateKeyQrCodes" = "Scan Private Key QR codes";
"ScanPublicKeyQrCodes" = "Scan Public Key QR codes"; "ScanPublicKeyQrCodes" = "Scan Public Key QR codes";
"SetPrivateKey." = "Please set private key first."; "SetPrivateKey." = "Please set the private key first.";
"SetPublicKey." = "Please set public key first."; "SetPublicKey." = "Please set the public key first.";
"NoQrCodeDetected." = "No QR code detected."; "NoQrCodeDetected." = "No QR code detected.";
"NoStringValue" = "No string value"; "NoStringValue" = "No string value";
"CameraAccessDenied." = "Camera access denied."; "CameraAccessDenied." = "Camera access denied.";
@ -126,7 +126,7 @@
"FillInPgpPassphrase." = "Please fill in the passphrase of your PGP secret key."; "FillInPgpPassphrase." = "Please fill in the passphrase of your PGP secret key.";
"WantToSavePassphrase?" = "Do you want to save the passphrase for later decryption?"; "WantToSavePassphrase?" = "Do you want to save the passphrase for later decryption?";
"CannotSavePgpKey" = "Cannot Save PGP Key"; "CannotSavePgpKey" = "Cannot Save PGP Key";
"SetPgpKeyUrlsFirst." = "Please set PGP key URLs first."; "SetPgpKeyUrlsFirst." = "Please set valid PGP key URLs first.";
"FetchingPgpKey" = "Fetching PGP Key"; "FetchingPgpKey" = "Fetching PGP Key";
"RememberToRemoveKey" = "Remember to Remove the Keys"; "RememberToRemoveKey" = "Remember to Remove the Keys";
"RememberToRemoveKeyFromServer." = "Remember to remove the keys from the server."; "RememberToRemoveKeyFromServer." = "Remember to remove the keys from the server.";

View file

@ -11,20 +11,16 @@ import SwiftyUserDefaults
public var Defaults = DefaultsAdapter(defaults: UserDefaults(suiteName: Globals.groupIdentifier)!, keyStore: DefaultsKeys()) public var Defaults = DefaultsAdapter(defaults: UserDefaults(suiteName: Globals.groupIdentifier)!, keyStore: DefaultsKeys())
public enum PGPKeySource: String, DefaultsSerializable { public enum KeySource: String, DefaultsSerializable {
case url, armor, files, itunes case url, armor, file, itunes
} }
public enum GitAuthenticationMethod: String, DefaultsSerializable { public enum GitAuthenticationMethod: String, DefaultsSerializable {
case password, key case password, key
} }
public enum GitSSHKeySource: String, DefaultsSerializable {
case file, armor, url
}
public extension DefaultsKeys { public extension DefaultsKeys {
var pgpKeySource: DefaultsKey<PGPKeySource?> { .init("pgpKeySource") } var pgpKeySource: DefaultsKey<KeySource?> { .init("pgpKeySource") }
var pgpPublicKeyURL: DefaultsKey<URL?> { .init("pgpPublicKeyURL") } var pgpPublicKeyURL: DefaultsKey<URL?> { .init("pgpPublicKeyURL") }
var pgpPrivateKeyURL: DefaultsKey<URL?> { .init("pgpPrivateKeyURL") } var pgpPrivateKeyURL: DefaultsKey<URL?> { .init("pgpPrivateKeyURL") }
@ -39,7 +35,7 @@ public extension DefaultsKeys {
var gitUsername: DefaultsKey<String> { .init("gitUsername", defaultValue: "git") } var gitUsername: DefaultsKey<String> { .init("gitUsername", defaultValue: "git") }
var gitBranchName: DefaultsKey<String> { .init("gitBranchName", defaultValue: "master") } var gitBranchName: DefaultsKey<String> { .init("gitBranchName", defaultValue: "master") }
var gitSSHPrivateKeyURL: DefaultsKey<URL?> { .init("gitSSHPrivateKeyURL") } var gitSSHPrivateKeyURL: DefaultsKey<URL?> { .init("gitSSHPrivateKeyURL") }
var gitSSHKeySource: DefaultsKey<GitSSHKeySource?> { .init("gitSSHKeySource") } var gitSSHKeySource: DefaultsKey<KeySource?> { .init("gitSSHKeySource") }
var gitSignatureName: DefaultsKey<String?> { .init("gitSignatureName") } var gitSignatureName: DefaultsKey<String?> { .init("gitSignatureName") }
var gitSignatureEmail: DefaultsKey<String?> { .init("gitSignatureEmail") } var gitSignatureEmail: DefaultsKey<String?> { .init("gitSignatureEmail") }

View file

@ -698,8 +698,4 @@ public class PasswordStore {
AppKeychain.shared.removeContent(for: SshKey.PRIVATE.getKeychainKey()) AppKeychain.shared.removeContent(for: SshKey.PRIVATE.getKeychainKey())
gitSSHPrivateKeyPassphrase = nil gitSSHPrivateKeyPassphrase = nil
} }
public func gitSSHKeyImportFromFileSharing() throws {
try KeyFileManager.PrivateSsh.importKeyFromFileSharing()
}
} }