Refactor logic of requesting git/ssh password callback

This commit is contained in:
Bob Sun 2017-04-24 10:53:26 -07:00
parent a12847e887
commit b35d79031d
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
2 changed files with 49 additions and 75 deletions

View file

@ -112,7 +112,7 @@ class SettingsTableViewController: UITableViewController {
SVProgressHUD.show(withStatus: "Prepare Repository") SVProgressHUD.show(withStatus: "Prepare Repository")
var gitCredential: GitCredential var gitCredential: GitCredential
if auth == "Password" { if auth == "Password" {
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username, password: password!)) gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username, password: password!, requestGitPassword: requestGitPassword))
} else { } else {
gitCredential = GitCredential( gitCredential = GitCredential(
credential: GitCredential.Credential.ssh( credential: GitCredential.Credential.ssh(
@ -120,7 +120,7 @@ class SettingsTableViewController: UITableViewController {
password: Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") ?? "", password: Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") ?? "",
publicKeyFile: Globals.gitSSHPublicKeyURL, publicKeyFile: Globals.gitSSHPublicKeyURL,
privateKeyFile: Globals.gitSSHPrivateKeyURL, privateKeyFile: Globals.gitSSHPrivateKeyURL,
passwordNotSetCallback: self.requestSshKeyPassword requestSSHKeyPassword: self.requestGitPassword
) )
) )
} }
@ -204,31 +204,32 @@ class SettingsTableViewController: UITableViewController {
} }
} }
func requestSshKeyPassword() -> String { private func requestGitPassword(message: String) -> String? {
let sem = DispatchSemaphore(value: 0) let sem = DispatchSemaphore(value: 0)
var newPassword = "" var password: String?
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.dismiss() SVProgressHUD.dismiss()
let alert = UIAlertController(title: "Password", message: "Please fill in the password of your SSH key.", preferredStyle: UIAlertControllerStyle.alert) let alert = UIAlertController(title: "Password", message: message, 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 alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = self.passwordStore.gitPassword textField.text = self.passwordStore.gitPassword
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
}) })
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
password = alert.textFields!.first!.text
sem.signal()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
password = nil
sem.signal()
})
self.present(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
} }
let _ = sem.wait(timeout: DispatchTime.distantFuture) let _ = sem.wait(timeout: .distantFuture)
return newPassword return password
} }
func actOnPasswordStoreErasedNotification() { func actOnPasswordStoreErasedNotification() {
setPGPKeyTableViewCellDetailText() setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText() setPasswordRepositoryTableViewCellDetailText()

View file

@ -14,76 +14,48 @@ import ObjectiveGit
import SVProgressHUD import SVProgressHUD
struct GitCredential { struct GitCredential {
var credential: Credential
enum Credential { enum Credential {
case http(userName: String, password: String) case http(userName: String, password: String, requestGitPassword: ((_ message: String) -> String?)?)
case ssh(userName: String, password: String, publicKeyFile: URL, privateKeyFile: URL, passwordNotSetCallback: (() -> String)? ) case ssh(userName: String, password: String, publicKeyFile: URL, privateKeyFile: URL, requestSSHKeyPassword: ((_ message: String) -> String?)? )
}
init(credential: Credential) {
self.credential = credential
Defaults[.gitPasswordAttempts] = 0
} }
var credential: Credential
func credentialProvider() throws -> GTCredentialProvider { func credentialProvider() throws -> GTCredentialProvider {
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
var credential: GTCredential? = nil var credential: GTCredential? = nil
switch self.credential { switch self.credential {
case let .http(userName, password): case let .http(userName, password, requestGitPassword):
print(Defaults[.gitPasswordAttempts]) var newPassword = password
var newPassword: String = password
if Defaults[.gitPasswordAttempts] != 0 { if Defaults[.gitPasswordAttempts] != 0 {
let sem = DispatchSemaphore(value: 0) if let requestGitPasswordCallback = requestGitPassword,
DispatchQueue.main.async { let requestedPassword = requestGitPasswordCallback("Please fill in the password of your Git account.") {
SVProgressHUD.dismiss() newPassword = requestedPassword
if var topController = UIApplication.shared.keyWindow?.rootViewController { } else {
while let presentedViewController = topController.presentedViewController { return nil
topController = presentedViewController
}
let alert = UIAlertController(title: "Password", message: "Please fill in the password of your Git account.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
newPassword = alert.textFields!.first!.text!
PasswordStore.shared.gitPassword = newPassword
sem.signal()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
Defaults[.gitPasswordAttempts] = -1
sem.signal()
})
alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = PasswordStore.shared.gitPassword
textField.isSecureTextEntry = true
})
topController.present(alert, animated: true, completion: nil)
}
} }
let _ = sem.wait(timeout: DispatchTime.distantFuture)
}
if Defaults[.gitPasswordAttempts] == -1 {
Defaults[.gitPasswordAttempts] = 0
return nil
} }
Defaults[.gitPasswordAttempts] += 1 Defaults[.gitPasswordAttempts] += 1
PasswordStore.shared.gitPassword = newPassword
credential = try? GTCredential(userName: userName, password: newPassword) credential = try? GTCredential(userName: userName, password: newPassword)
case let .ssh(userName, password, publicKeyFile, privateKeyFile, passwordNotSetCallback): case let .ssh(userName, password, publicKeyFile, privateKeyFile, requestSSHKeyPassword):
var newPassword = password
var newPassword:String? = password if Defaults[.gitPasswordAttempts] != 0 {
if let requestSSHKeyPasswordCallback = requestSSHKeyPassword,
// Check if the private key is encrypted let requestedPassword = requestSSHKeyPasswordCallback("Please fill in the password of your SSH key.") {
let encrypted = try? String(contentsOf: privateKeyFile).contains("ENCRYPTED") newPassword = requestedPassword
} else {
// Request password if not already set return nil
if encrypted == nil && password == "" {
newPassword = passwordNotSetCallback!() }
} }
Defaults[.gitPasswordAttempts] += 1
// Save password for the future
Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", 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) credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: newPassword)
} }
return credential return credential
@ -184,7 +156,8 @@ class PasswordStore {
public func initGitCredential() { public func initGitCredential() {
if Defaults[.gitAuthenticationMethod] == "Password" { if Defaults[.gitAuthenticationMethod] == "Password" {
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitUsername] ?? "", password: Utils.getPasswordFromKeychain(name: "gitPassword") ?? "")) let httpCredential = GitCredential.Credential.http(userName: Defaults[.gitUsername] ?? "", password: Utils.getPasswordFromKeychain(name: "gitPassword") ?? "", requestGitPassword: nil)
gitCredential = GitCredential(credential: httpCredential)
} else if Defaults[.gitAuthenticationMethod] == "SSH Key"{ } else if Defaults[.gitAuthenticationMethod] == "SSH Key"{
gitCredential = GitCredential( gitCredential = GitCredential(
credential: GitCredential.Credential.ssh( credential: GitCredential.Credential.ssh(
@ -192,7 +165,7 @@ class PasswordStore {
password: gitSSHPrivateKeyPassphrase ?? "", password: gitSSHPrivateKeyPassphrase ?? "",
publicKeyFile: Globals.gitSSHPublicKeyURL, publicKeyFile: Globals.gitSSHPublicKeyURL,
privateKeyFile: Globals.gitSSHPrivateKeyURL, privateKeyFile: Globals.gitSSHPrivateKeyURL,
passwordNotSetCallback: nil requestSSHKeyPassword: nil
) )
) )
} else { } else {