Introduce KeyImporter protocol to reduce code duplications in SSH key importers
This commit is contained in:
parent
6aa39db657
commit
94a5f8c501
14 changed files with 189 additions and 144 deletions
|
|
@ -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 */,
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -213,78 +213,65 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Helper Functions
|
@IBAction func importSSHKey(segue: UIStoryboardSegue) {
|
||||||
|
guard let sourceController = segue.source as? KeyImporter, sourceController.isReadyToUse() else {
|
||||||
private func showSSHKeyActionSheet() {
|
return
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
}
|
||||||
var urlActionTitle = "DownloadFromUrl".localize()
|
importSSHKey(using: sourceController)
|
||||||
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
|
private func importSSHKey(using keyImporter: KeyImporter) {
|
||||||
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
}
|
|
||||||
optionMenu.addAction(urlAction)
|
|
||||||
|
|
||||||
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
|
||||||
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
|
|
||||||
}
|
|
||||||
optionMenu.addAction(armorAction)
|
|
||||||
|
|
||||||
let fileAction: UIAlertAction = {
|
|
||||||
if KeyFileManager.PrivateSsh.doesKeyFileExist() {
|
|
||||||
fileActionTitle.append(" (\("Import".localize()))")
|
|
||||||
let action = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.gitSSHKeyImportFromFileSharing()
|
try keyImporter.importKeys()
|
||||||
Defaults.gitSSHKeySource = .file
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
SVProgressHUD.showSuccess(withStatus: "Imported".localize())
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
self.sshLabel?.isEnabled = true
|
}
|
||||||
|
Defaults.gitSSHKeySource = type(of: keyImporter).keySource
|
||||||
self.gitAuthenticationMethod = .key
|
self.gitAuthenticationMethod = .key
|
||||||
self.updateAuthenticationMethodCheckView(for: self.gitAuthenticationMethod)
|
self.sshLabel?.isEnabled = true
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self)
|
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return action
|
}
|
||||||
|
|
||||||
|
// MARK: - Helper Functions
|
||||||
|
|
||||||
|
private func showSSHKeyActionSheet() {
|
||||||
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
|
optionMenu.addAction(UIAlertAction(title: SSHKeyUrlImportTableViewController.menuLabel, style: .default) { _ in
|
||||||
|
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
|
||||||
|
})
|
||||||
|
optionMenu.addAction(UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in
|
||||||
|
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
|
||||||
|
})
|
||||||
|
|
||||||
|
if isReadyToUse() {
|
||||||
|
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in
|
||||||
|
self.importSSHKey(using: self)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
fileActionTitle.append(" (\("Tips".localize()))")
|
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Tips".localize()))", style: .default) { _ in
|
||||||
let action = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
|
||||||
let title = "Tips".localize()
|
let title = "Tips".localize()
|
||||||
let message = "SshCopyPrivateKeyToPass.".localize()
|
let message = "SshCopyPrivateKeyToPass.".localize()
|
||||||
Utils.alert(title: title, message: message, controller: self)
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
pass/Controllers/KeyImporter.swift
Normal file
36
pass/Controllers/KeyImporter.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,14 +10,12 @@ 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 {
|
||||||
case publicKey, privateKey
|
case publicKey, privateKey
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
@ -27,11 +17,12 @@ 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() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 ?? "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
// Copyright © 2017 Bob Sun. All rights reserved.
|
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import passKit
|
import passKit
|
||||||
|
|
||||||
|
|
@ -14,26 +13,48 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
||||||
|
|
||||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||||
|
|
||||||
let passwordStore = PasswordStore.shared
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
privateKeyURLTextField.text = Defaults.gitSSHPrivateKeyURL?.absoluteString
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
||||||
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else {
|
if getScheme(from: privateKeyURLTextField.text?.trimmed) == "http" {
|
||||||
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self, completion: nil)
|
let savePassphraseAlert = UIAlertController(title: "HttpNotSecure".localize(), message: "ReallyUseHttp?".localize(), preferredStyle: .alert)
|
||||||
return
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
private func getScheme(from url: String?) -> String? {
|
||||||
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: SshKey.PRIVATE.getFileSharingPath()), options: .atomic)
|
return url.flatMap(URL.init(string:))?.scheme
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.";
|
||||||
|
|
|
||||||
|
|
@ -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") }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue