diff --git a/pass/Controllers/SSHKeySettingTableViewController.swift b/pass/Controllers/SSHKeySettingTableViewController.swift index 65a672e..4986a22 100644 --- a/pass/Controllers/SSHKeySettingTableViewController.swift +++ b/pass/Controllers/SSHKeySettingTableViewController.swift @@ -18,7 +18,7 @@ class SSHKeySettingTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - passphraseTextField.text = Defaults[.gitRepositorySSHPrivateKeyPassphrase] + passphraseTextField.text = Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase")! privateKeyURLTextField.text = Defaults[.gitRepositorySSHPrivateKeyURL]?.absoluteString publicKeyURLTextField.text = Defaults[.gitRepositorySSHPublicKeyURL]?.absoluteString var doneBarButtonItem: UIBarButtonItem? @@ -43,7 +43,7 @@ class SSHKeySettingTableViewController: UITableViewController { Defaults[.gitRepositorySSHPublicKeyURL] = URL(string: publicKeyURLTextField.text!) Defaults[.gitRepositorySSHPrivateKeyURL] = URL(string: privateKeyURLTextField.text!) - Defaults[.gitRepositorySSHPrivateKeyPassphrase] = passphraseTextField.text! + Utils.addPasswrodToKeychain(name: "gitRepositorySSHPrivateKeyPassphrase", password: passphraseTextField.text!) do { try Data(contentsOf: Defaults[.gitRepositorySSHPublicKeyURL]!).write(to: Globals.sshPublicKeyURL, options: .atomic) diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index 7952572..4c72a09 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -113,7 +113,15 @@ class SettingsTableViewController: UITableViewController { if auth == "Password" { gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username, password: password!)) } else { - gitCredential = GitCredential(credential: GitCredential.Credential.ssh(userName: username, password: Defaults[.gitRepositorySSHPrivateKeyPassphrase]!, publicKeyFile: Globals.sshPublicKeyURL, privateKeyFile: Globals.sshPrivateKeyURL)) + gitCredential = GitCredential( + credential: GitCredential.Credential.ssh( + userName: username, + password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase")!, + publicKeyFile: Globals.sshPublicKeyURL, + privateKeyFile: Globals.sshPrivateKeyURL, + passwordNotSetCallback: self.requestSshKeyPassword + ) + ) } let dispatchQueue = DispatchQueue.global(qos: .userInitiated) dispatchQueue.async { @@ -179,7 +187,32 @@ class SettingsTableViewController: UITableViewController { touchIDSwitch.isEnabled = false } } - + + func requestSshKeyPassword() -> String { + let sem = DispatchSemaphore(value: 0) + var newPassword = "" + + DispatchQueue.main.async { + SVProgressHUD.dismiss() + let alert = UIAlertController(title: "Password", message: "Please fill in the password of your SSH key.", preferredStyle: UIAlertControllerStyle.alert) + + alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in + newPassword = alert.textFields!.first!.text! + sem.signal() + })) + + alert.addTextField(configurationHandler: {(textField: UITextField!) in + textField.text = PasswordStore.shared.gitRepositoryPassword + textField.isSecureTextEntry = true + }) + + self.present(alert, animated: true, completion: nil) + } + + let _ = sem.wait(timeout: DispatchTime.distantFuture) + return newPassword + } + func actOnPasswordStoreErasedNotification() { pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" touchIDSwitch.isOn = false diff --git a/pass/Helpers/DefaultsKeys.swift b/pass/Helpers/DefaultsKeys.swift index 791e9c1..ae3f6f6 100644 --- a/pass/Helpers/DefaultsKeys.swift +++ b/pass/Helpers/DefaultsKeys.swift @@ -26,7 +26,7 @@ extension DefaultsKeys { static let gitRepositoryPasswordAttempts = DefaultsKey("gitRepositoryPasswordAttempts") static let gitRepositorySSHPublicKeyURL = DefaultsKey("gitRepositorySSHPublicKeyURL") static let gitRepositorySSHPrivateKeyURL = DefaultsKey("gitRepositorySSHPrivateKeyURL") - static let gitRepositorySSHPrivateKeyPassphrase = DefaultsKey("gitRepositorySSHPrivateKeyPassphrase") + static let lastUpdatedTime = DefaultsKey("lasteUpdatedTime") static let isTouchIDOn = DefaultsKey("isTouchIDOn") diff --git a/pass/Models/PasswordStore.swift b/pass/Models/PasswordStore.swift index a3a14f5..2034f16 100644 --- a/pass/Models/PasswordStore.swift +++ b/pass/Models/PasswordStore.swift @@ -17,11 +17,11 @@ struct GitCredential { enum Credential { case http(userName: String, password: String) - case ssh(userName: String, password: String, publicKeyFile: URL, privateKeyFile: URL) + case ssh(userName: String, password: String, publicKeyFile: URL, privateKeyFile: URL, passwordNotSetCallback: (() -> String)? ) } var credential: Credential - + func credentialProvider() throws -> GTCredentialProvider { return GTCredentialProvider { (_, _, _) -> (GTCredential?) in var credential: GTCredential? = nil @@ -65,8 +65,28 @@ struct GitCredential { Defaults[.gitRepositoryPasswordAttempts] += 1 PasswordStore.shared.gitRepositoryPassword = newPassword credential = try? GTCredential(userName: userName, password: newPassword) - case let .ssh(userName, password, publicKeyFile, privateKeyFile): - credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: password) + case let .ssh(userName, password, publicKeyFile, privateKeyFile, passwordNotSetCallback): + + var newPassword:String? = password + + // Check if the private key is encrypted + let encrypted = try? String(contentsOf: privateKeyFile).contains("ENCRYPTED") + + // Request password if not already set + if encrypted! && password == "" { + newPassword = passwordNotSetCallback!() + } + + // Save password for the future + Utils.addPasswrodToKeychain(name: "gitRepositorySSHPrivateKeyPassphrase", password: newPassword!) + + // nil is expected in case of empty password + if newPassword == "" { + newPassword = nil + } + + + credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: newPassword) } return credential } @@ -119,7 +139,15 @@ class PasswordStore { if Defaults[.gitRepositoryAuthenticationMethod] == "Password" { gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername]!, password: Utils.getPasswordFromKeychain(name: "gitRepositoryPassword") ?? "")) } else if Defaults[.gitRepositoryAuthenticationMethod] == "SSH Key"{ - gitCredential = GitCredential(credential: GitCredential.Credential.ssh(userName: Defaults[.gitRepositoryUsername]!, password: Defaults[.gitRepositorySSHPrivateKeyPassphrase]!, publicKeyFile: Globals.sshPublicKeyURL, privateKeyFile: Globals.sshPrivateKeyURL)) + gitCredential = GitCredential( + credential: GitCredential.Credential.ssh( + userName: Defaults[.gitRepositoryUsername]!, + password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase")!, + publicKeyFile: Globals.sshPublicKeyURL, + privateKeyFile: Globals.sshPrivateKeyURL, + passwordNotSetCallback: nil + ) + ) } else { gitCredential = nil }