Cleanup GitServerSettingTableViewController

This commit is contained in:
Mingshen Sun 2019-11-30 17:37:09 -08:00
parent 9b304433fb
commit 902930ddfc
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
5 changed files with 156 additions and 131 deletions

View file

@ -65,7 +65,7 @@ class GitSSHKeyArmorSettingTableViewController: AutoCellHeightUITableViewControl
} catch { } catch {
Utils.alert(title: "CannotSave".localize(), message: "CannotSaveSshKey".localize(), controller: self, completion: nil) Utils.alert(title: "CannotSave".localize(), message: "CannotSaveSshKey".localize(), controller: self, completion: nil)
} }
SharedDefaults[.gitSSHKeySource] = "armor" SharedDefaults[.gitSSHKeySource] = .armor
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
} }

View file

@ -12,6 +12,7 @@ import passKit
class GitServerSettingTableViewController: UITableViewController { class GitServerSettingTableViewController: UITableViewController {
// MARK: - View Outlet
@IBOutlet weak var gitURLTextField: UITextField! @IBOutlet weak var gitURLTextField: UITextField!
@IBOutlet weak var usernameTextField: UITextField! @IBOutlet weak var usernameTextField: UITextField!
@ -21,9 +22,10 @@ class GitServerSettingTableViewController: UITableViewController {
@IBOutlet weak var gitURLCell: UITableViewCell! @IBOutlet weak var gitURLCell: UITableViewCell!
@IBOutlet weak var gitRepositoryURLTabelViewCell: UITableViewCell! @IBOutlet weak var gitRepositoryURLTabelViewCell: UITableViewCell!
private let passwordStore = PasswordStore.shared // MARK: - Properties
private var sshLabel: UILabel? = nil
private var sshLabel: UILabel? = nil
private let passwordStore = PasswordStore.shared
private var gitAuthenticationMethod: GitAuthenticationMethod { private var gitAuthenticationMethod: GitAuthenticationMethod {
get { SharedDefaults[.gitAuthenticationMethod] } get { SharedDefaults[.gitAuthenticationMethod] }
set { set {
@ -55,25 +57,9 @@ class GitServerSettingTableViewController: UITableViewController {
} }
} }
private func updateAuthenticationMethodCheckView(for method: GitAuthenticationMethod) {
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
let sshKeyCheckView = authSSHKeyCell.viewWithTag(1001)!
switch method { // MARK: - View Controller Lifecycle
case .password:
passwordCheckView.isHidden = false
sshKeyCheckView.isHidden = true
case .key:
passwordCheckView.isHidden = true
sshKeyCheckView.isHidden = false
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Grey out ssh option if ssh_key is not present
sshLabel?.isEnabled = AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey())
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
gitURLTextField.text = self.gitUrl.absoluteString gitURLTextField.text = self.gitUrl.absoluteString
@ -84,6 +70,19 @@ class GitServerSettingTableViewController: UITableViewController {
authSSHKeyCell.accessoryType = .detailButton authSSHKeyCell.accessoryType = .detailButton
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Grey out ssh option if ssh_key is not present.
sshLabel?.isEnabled = AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey())
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.endEditing(true)
}
// MARK: - UITableViewController Override
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) let cell = tableView.cellForRow(at: indexPath)
if cell == authSSHKeyCell { if cell == authSSHKeyCell {
@ -93,27 +92,80 @@ class GitServerSettingTableViewController: UITableViewController {
} }
} }
private func showGitURLFormatHelp() { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Utils.alert(title: "Git URL Format", message: "https://example.com[:port]/project.git\nssh://[user@]server[:port]/project.git\n[user@]server:project.git (no scheme)", controller: self) let cell = tableView.cellForRow(at: indexPath)
if cell == authPasswordCell {
self.gitAuthenticationMethod = .password
} else if cell == authSSHKeyCell {
if !AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey()) {
Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self)
gitAuthenticationMethod = .password
} else {
gitAuthenticationMethod = .key
}
}
tableView.deselectRow(at: indexPath, animated: true)
} }
override func viewDidAppear(_ animated: Bool) { // MARK: - Segue Handlers
super.viewDidAppear(animated)
@IBAction func save(_ sender: Any) {
guard let gitURLTextFieldText = gitURLTextField.text, let gitURL = URL(string: gitURLTextFieldText.trimmed) else {
Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self)
return
} }
override func viewWillDisappear(_ animated: Bool) { guard let branchName = branchNameTextField.text, !branchName.trimmed.isEmpty else {
super.viewWillDisappear(animated) Utils.alert(title: "CannotSave".localize(), message: "SpecifyBranchName.".localize(), controller: self)
view.endEditing(true) return
} }
if let scheme = gitURL.scheme {
switch scheme {
case "ssh", "http", "https":
if gitURL.user == nil && usernameTextField.text == nil {
Utils.alert(title: "CannotSave".localize(), message: "CannotFindUsername.".localize(), controller: self)
return
}
if let urlUsername = gitURL.user, let textFieldUsername = usernameTextField.text, urlUsername != textFieldUsername.trimmed {
Utils.alert(title: "CannotSave".localize(), message: "CheckEnteredUsername.".localize(), controller: self)
return
}
case "file": break
default:
Utils.alert(title: "CannotSave".localize(), message: "Protocol is not supported", controller: self)
return
}
}
self.gitUrl = gitURL
self.gitBranchName = branchName.trimmed
self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
if passwordStore.repositoryExisted() {
let overwriteAlert: UIAlertController = {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in
self.cloneAndSegueIfSuccess()
})
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil))
return alert
}()
self.present(overwriteAlert, animated: true, completion: nil)
} else {
cloneAndSegueIfSuccess()
}
}
private func cloneAndSegueIfSuccess() { private func cloneAndSegueIfSuccess() {
// Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone. // Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone.
SharedDefaults[.isRememberGitCredentialPassphraseOn] = true SharedDefaults[.isRememberGitCredentialPassphraseOn] = true
DispatchQueue.global(qos: .userInitiated).async() { DispatchQueue.global(qos: .userInitiated).async() {
do { do {
let transferProgressBlock: (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { (git_transfer_progress, _) in let transferProgressBlock: (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { (git_transfer_progress, _) in
let progress = Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects) let gitTransferProgress = git_transfer_progress.pointee
let progress = Float(gitTransferProgress.received_objects) / Float(gitTransferProgress.total_objects)
SVProgressHUD.showProgress(progress, status: "Cloning Remote Repository") SVProgressHUD.showProgress(progress, status: "Cloning Remote Repository")
} }
@ -153,122 +205,65 @@ class GitServerSettingTableViewController: UITableViewController {
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError { if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
message = "\(message)\n\("UnderlyingError".localize(underlyingError.localizedDescription))" message = "\(message)\n\("UnderlyingError".localize(underlyingError.localizedDescription))"
} }
Utils.alert(title: "Error".localize(), message: message, controller: self, completion: nil) Utils.alert(title: "Error".localize(), message: message, controller: self)
} }
} }
} }
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if cell == authPasswordCell {
self.gitAuthenticationMethod = .password
} else if cell == authSSHKeyCell {
if !AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey()) {
Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self, completion: nil)
gitAuthenticationMethod = .password
} else {
gitAuthenticationMethod = .key
}
}
tableView.deselectRow(at: indexPath, animated: true)
}
@IBAction func save(_ sender: Any) { // MARK: - Helper Functions
guard let gitURLTextFieldText = gitURLTextField.text, let gitURL = URL(string: gitURLTextFieldText.trimmed) else {
Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self, completion: nil)
return
}
guard let branchName = branchNameTextField.text, !branchName.trimmed.isEmpty else { private func showSSHKeyActionSheet() {
Utils.alert(title: "CannotSave".localize(), message: "SpecifyBranchName.".localize(), controller: self, completion: nil)
return
}
if let scheme = gitURL.scheme {
switch scheme {
case "ssh", "http", "https":
if gitURL.user == nil && usernameTextField.text == nil {
Utils.alert(title: "CannotSave".localize(), message: "CannotFindUsername.".localize(), controller: self, completion: nil)
return
}
if let urlUsername = gitURL.user, let textFieldUsername = usernameTextField.text, urlUsername != textFieldUsername.trimmed {
Utils.alert(title: "CannotSave".localize(), message: "CheckEnteredUsername.".localize(), controller: self, completion: nil)
return
}
case "file": break
default:
Utils.alert(title: "CannotSave".localize(), message: "Protocol is not supported", controller: self, completion: nil)
return
}
}
self.gitUrl = gitURL
self.gitBranchName = branchName.trimmed
self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
if passwordStore.repositoryExisted() {
let overwriteAlert: UIAlertController = {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in
self.cloneAndSegueIfSuccess()
})
alert.addAction(UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil))
return alert
}()
self.present(overwriteAlert, animated: true, completion: nil)
} else {
cloneAndSegueIfSuccess()
}
}
func showSSHKeyActionSheet() {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
var urlActionTitle = "DownloadFromUrl".localize() var urlActionTitle = "DownloadFromUrl".localize()
var armorActionTitle = "AsciiArmorEncryptedKey".localize() var armorActionTitle = "AsciiArmorEncryptedKey".localize()
var fileActionTitle = "ITunesFileSharing".localize() var fileActionTitle = "ITunesFileSharing".localize()
if SharedDefaults[.gitSSHKeySource] == "url" { switch SharedDefaults[.gitSSHKeySource] {
urlActionTitle = "\(urlActionTitle)" case .url: urlActionTitle = "\(urlActionTitle)"
} else if SharedDefaults[.gitSSHKeySource] == "armor" { case .armor: armorActionTitle = "\(armorActionTitle)"
armorActionTitle = "\(armorActionTitle)" case .file: fileActionTitle = "\(fileActionTitle)"
} else if SharedDefaults[.gitSSHKeySource] == "file" { case .none: break
fileActionTitle = "\(fileActionTitle)"
} }
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
} }
optionMenu.addAction(urlAction)
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
} }
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
optionMenu.addAction(urlAction)
optionMenu.addAction(armorAction) optionMenu.addAction(armorAction)
let fileAction: UIAlertAction = {
if KeyFileManager.PrivateSsh.doesKeyFileExist() { if KeyFileManager.PrivateSsh.doesKeyFileExist() {
// might keys updated via iTunes, or downloaded/pasted inside the app
fileActionTitle.append(" (\("Import".localize()))") fileActionTitle.append(" (\("Import".localize()))")
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in let action = UIAlertAction(title: fileActionTitle, style: .default) { _ in
do { do {
try self.passwordStore.gitSSHKeyImportFromFileSharing() try self.passwordStore.gitSSHKeyImportFromFileSharing()
SharedDefaults[.gitSSHKeySource] = "file" SharedDefaults[.gitSSHKeySource] = .file
SVProgressHUD.showSuccess(withStatus: "Imported".localize()) SVProgressHUD.showSuccess(withStatus: "Imported".localize())
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
self.sshLabel?.isEnabled = true self.sshLabel?.isEnabled = true
} catch { } catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self)
} }
} }
optionMenu.addAction(fileAction) return action
} else { } else {
fileActionTitle.append(" (\("Tips".localize()))") fileActionTitle.append(" (\("Tips".localize()))")
let fileAction = UIAlertAction(title: fileActionTitle, 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)
} }
optionMenu.addAction(fileAction) return action
} }
}()
optionMenu.addAction(fileAction)
if SharedDefaults[.gitSSHKeySource] != nil { if SharedDefaults[.gitSSHKeySource] != nil {
let deleteAction = UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in let deleteAction = UIAlertAction(title: "RemoveSShKeys".localize(), style: .destructive) { _ in
self.passwordStore.removeGitSSHKeys() self.passwordStore.removeGitSSHKeys()
@ -278,9 +273,13 @@ class GitServerSettingTableViewController: UITableViewController {
} }
optionMenu.addAction(deleteAction) optionMenu.addAction(deleteAction)
} }
let cancelAction = UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: nil)
optionMenu.addAction(cancelAction) optionMenu.addAction(cancelAction)
optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell
optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds
self.present(optionMenu, animated: true, completion: nil) self.present(optionMenu, animated: true, completion: nil)
} }
@ -317,4 +316,28 @@ class GitServerSettingTableViewController: UITableViewController {
let _ = sem.wait(timeout: .distantFuture) let _ = sem.wait(timeout: .distantFuture)
return password return password
} }
private func updateAuthenticationMethodCheckView(for method: GitAuthenticationMethod) {
let passwordCheckView = authPasswordCell.viewWithTag(1001)
let sshKeyCheckView = authSSHKeyCell.viewWithTag(1001)
switch method {
case .password:
passwordCheckView?.isHidden = false
sshKeyCheckView?.isHidden = true
case .key:
passwordCheckView?.isHidden = true
sshKeyCheckView?.isHidden = false
}
}
private func showGitURLFormatHelp() {
let message = """
https://example.com[:port]/project.git
ssh://[user@]server[:port]/project.git
[user@]server:project.git (no scheme)
"""
Utils.alert(title: "Git URL Format", message: message, controller: self)
}
} }

View file

@ -28,13 +28,13 @@ class SSHKeySettingTableViewController: AutoCellHeightUITableViewController {
do { do {
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: SshKey.PRIVATE.getFileSharingPath()), options: .atomic) try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: SshKey.PRIVATE.getFileSharingPath()), options: .atomic)
try self.passwordStore.gitSSHKeyImportFromFileSharing() try self.passwordStore.gitSSHKeyImportFromFileSharing()
SharedDefaults[.gitSSHKeySource] = "file" SharedDefaults[.gitSSHKeySource] = .file
SVProgressHUD.showSuccess(withStatus: "Imported".localize()) SVProgressHUD.showSuccess(withStatus: "Imported".localize())
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} catch { } catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
} }
SharedDefaults[.gitSSHKeySource] = "url" SharedDefaults[.gitSSHKeySource] = .url
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
} }

View file

@ -11,6 +11,14 @@ import SwiftyUserDefaults
public var SharedDefaults = UserDefaults(suiteName: Globals.groupIdentifier)! public var SharedDefaults = UserDefaults(suiteName: Globals.groupIdentifier)!
public enum GitAuthenticationMethod: String, DefaultsSerializable {
case password, key
}
public enum GitSSHKeySource: String, DefaultsSerializable {
case file, armor, url
}
public extension DefaultsKeys { public extension DefaultsKeys {
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource") static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL") static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")
@ -27,7 +35,7 @@ public extension DefaultsKeys {
static let gitUsername = DefaultsKey<String>("gitUsername", defaultValue: "git") static let gitUsername = DefaultsKey<String>("gitUsername", defaultValue: "git")
static let gitBranchName = DefaultsKey<String>("gitBranchName", defaultValue: "master") static let gitBranchName = DefaultsKey<String>("gitBranchName", defaultValue: "master")
static let gitSSHPrivateKeyURL = DefaultsKey<URL?>("gitSSHPrivateKeyURL") static let gitSSHPrivateKeyURL = DefaultsKey<URL?>("gitSSHPrivateKeyURL")
static let gitSSHKeySource = DefaultsKey<String?>("gitSSHKeySource") static let gitSSHKeySource = DefaultsKey<GitSSHKeySource?>("gitSSHKeySource")
static let gitSignatureName = DefaultsKey<String?>("gitSignatureName") static let gitSignatureName = DefaultsKey<String?>("gitSignatureName")
static let gitSignatureEmail = DefaultsKey<String?>("gitSignatureEmail") static let gitSignatureEmail = DefaultsKey<String?>("gitSignatureEmail")

View file

@ -7,14 +7,8 @@
// //
import Foundation import Foundation
import UIKit
import SwiftyUserDefaults
import ObjectiveGit import ObjectiveGit
public enum GitAuthenticationMethod: String, DefaultsSerializable {
case password, key
}
public struct GitCredential { public struct GitCredential {
private var credential: Credential private var credential: Credential
private let passwordStore = PasswordStore.shared private let passwordStore = PasswordStore.shared