Format code with SwiftFormat automatically in every build

This commit is contained in:
Danny Moesch 2020-06-28 21:25:40 +02:00 committed by Mingshen Sun
parent f167ab7549
commit 7f9f0e43b2
100 changed files with 1124 additions and 1063 deletions

View file

@ -6,11 +6,10 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class AboutRepositoryTableViewController: BasicStaticTableViewController {
private static let VALUE_NOT_AVAILABLE = "ValueNotAvailable".localize()
private var needRefresh = false
@ -18,6 +17,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
let indicator = UIActivityIndicatorView(style: .gray)
return indicator
}()
private let passwordStore = PasswordStore.shared
override func viewDidLoad() {
@ -41,10 +41,9 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
}
private func setTableData() {
// clear current contents (if any)
self.tableData.removeAll(keepingCapacity: true)
self.tableView.reloadData()
tableData.removeAll(keepingCapacity: true)
tableView.reloadData()
indicator.startAnimating()
// reload the table
@ -67,8 +66,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LocalCommits".localize(), .detailText: localCommits],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LastSynced".localize(), .detailText: lastSynced],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits".localize(), .detailText: commits],
[.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"],
],
[.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"]],
]
strongSelf.indicator.stopAnimating()
strongSelf.tableView.reloadData()
@ -79,15 +77,15 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
private func numberOfPasswordsString() -> String {
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
return formatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords)) ?? ""
return formatter.string(from: NSNumber(value: passwordStore.numberOfPasswords)) ?? ""
}
private func sizeOfRepositoryString() -> String {
return ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
ByteCountFormatter.string(fromByteCount: Int64(passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
}
private func lastSyncedTimeString() -> String {
guard let date = self.passwordStore.lastSyncedTime else {
guard let date = passwordStore.lastSyncedTime else {
return "SyncAgain?".localize()
}
let formatter = DateFormatter()
@ -103,7 +101,8 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
return AboutRepositoryTableViewController.VALUE_NOT_AVAILABLE
}
@objc func setNeedRefresh() {
@objc
func setNeedRefresh() {
needRefresh = true
}
}

View file

@ -9,17 +9,16 @@
import UIKit
class AboutTableViewController: BasicStaticTableViewController {
override func viewDidLoad() {
tableData = [
// section 0
[[.title: "Website".localize(), .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
[.title: "Help".localize(), .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
[.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
[.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"]],
// section 1,
[[.title: "OpenSourceComponents".localize(), .action: "segue", .link: "showOpenSourceComponentsSegue"],
[.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"],],
[.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"]],
]
super.viewDidLoad()
}
@ -39,11 +38,10 @@ class AboutTableViewController: BasicStaticTableViewController {
return nil
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 1 {
return "Acknowledgements".localize().uppercased()
}
return nil
}
}

View file

@ -6,8 +6,8 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class AddPasswordTableViewController: PasswordEditorTableViewController {
var defaultDirPrefix = ""
@ -17,7 +17,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
tableData[0][0][PasswordEditorCellKey.content] = defaultDirPrefix
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
if identifier == "saveAddPasswordSegue" {
// check PGP key
guard PGPAgent.shared.isPrepared else {

View file

@ -6,16 +6,15 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SVProgressHUD
import passKit
import SVProgressHUD
import UIKit
class AdvancedSettingsTableViewController: UITableViewController {
@IBOutlet weak var encryptInASCIIArmoredTableViewCell: UITableViewCell!
@IBOutlet weak var gitSignatureTableViewCell: UITableViewCell!
@IBOutlet weak var eraseDataTableViewCell: UITableViewCell!
@IBOutlet weak var discardChangesTableViewCell: UITableViewCell!
@IBOutlet var encryptInASCIIArmoredTableViewCell: UITableViewCell!
@IBOutlet var gitSignatureTableViewCell: UITableViewCell!
@IBOutlet var eraseDataTableViewCell: UITableViewCell!
@IBOutlet var discardChangesTableViewCell: UITableViewCell!
let passwordStore = PasswordStore.shared
let encryptInASCIIArmoredSwitch: UISwitch = {
@ -37,10 +36,10 @@ class AdvancedSettingsTableViewController: UITableViewController {
private func setGitSignatureText() {
let gitSignatureName = passwordStore.gitSignatureForNow?.name ?? ""
let gitSignatureEmail = passwordStore.gitSignatureForNow?.email ?? ""
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
if Defaults.gitSignatureName == nil && Defaults.gitSignatureEmail == nil {
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body)
gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
if Defaults.gitSignatureName == nil, Defaults.gitSignatureEmail == nil {
gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body)
gitSignatureTableViewCell.detailTextLabel?.text = "NotSet".localize()
}
}
@ -49,7 +48,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
tableView.deselectRow(at: indexPath, animated: true)
if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell {
let alert = UIAlertController(title: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
SVProgressHUD.show(withStatus: "Erasing...".localize())
self.passwordStore.erase()
self.navigationController!.popViewController(animated: true)
@ -57,10 +56,10 @@ class AdvancedSettingsTableViewController: UITableViewController {
SVProgressHUD.dismiss(withDelay: 1)
}))
alert.addAction(UIAlertAction.dismiss())
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
SVProgressHUD.show(withStatus: "Resetting...".localize())
do {
let numberDiscarded = try self.passwordStore.reset()
@ -73,15 +72,17 @@ class AdvancedSettingsTableViewController: UITableViewController {
}))
alert.addAction(UIAlertAction.dismiss())
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
}
}
@objc func encryptInASCIIArmoredAction(_ sender: Any?) {
@objc
func encryptInASCIIArmoredAction(_: Any?) {
Defaults.encryptInArmored = encryptInASCIIArmoredSwitch.isOn
}
@IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) {
@IBAction
func saveGitConfigSetting(segue: UIStoryboardSegue) {
if let controller = segue.source as? GitConfigSettingsTableViewController {
if let gitSignatureName = controller.nameTextField.text,
let gitSignatureEmail = controller.emailTextField.text {
@ -91,5 +92,4 @@ class AdvancedSettingsTableViewController: UITableViewController {
setGitSignatureText()
}
}
}

View file

@ -6,11 +6,10 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SafariServices
import MessageUI
import passKit
import SafariServices
import UIKit
enum CellDataType {
case link, segue, empty, detail
@ -25,7 +24,7 @@ enum CellDataKey {
}
class BasicStaticTableViewController: UITableViewController, MFMailComposeViewControllerDelegate {
var tableData = [[Dictionary<CellDataKey, Any>]]()
var tableData = [[[CellDataKey: Any]]]()
var navigationItemTitle: String?
override func viewDidLoad() {
@ -35,12 +34,12 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return tableData.count
override func numberOfSections(in _: UITableView) -> Int {
tableData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData[section].count
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
tableData[section].count
}
override func didReceiveMemoryWarning() {
@ -48,8 +47,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
// Dispose of any resources that can be recreated.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellData = tableData[indexPath.section][indexPath.row]
let cellDataStyle = cellData[CellDataKey.style] as? CellDataStyle
var cell: UITableViewCell?
@ -76,7 +74,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
return cell ?? UITableViewCell()
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
override func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let cellData = tableData[indexPath.section][indexPath.row]
let selector = cellData[CellDataKey.detailDisclosureAction] as? Selector
perform(selector, with: cellData[CellDataKey.detailDisclosureData])
@ -108,7 +106,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
}
case "http", "https":
let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false)
self.present(svc, animated: true, completion: nil)
present(svc, animated: true, completion: nil)
default:
break
}
@ -123,10 +121,10 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
mailVC.setToRecipients(recipients)
mailVC.setSubject(subject)
mailVC.setMessageBody("", isHTML: false)
self.present(mailVC, animated: true, completion: nil)
present(mailVC, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) {
controller.dismiss(animated: true)
}
}

View file

@ -6,9 +6,9 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import ObjectiveGit
import passKit
import UIKit
class CommitLogsTableViewController: UITableViewController {
var commits: [GTCommit] = []
@ -18,12 +18,12 @@ class CommitLogsTableViewController: UITableViewController {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil)
commits = getCommitLogs()
self.tableView.estimatedRowHeight = 50
self.tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return commits.count
override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
commits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@ -42,7 +42,8 @@ class CommitLogsTableViewController: UITableViewController {
return cell
}
@objc func updateCommitLogs() {
@objc
func updateCommitLogs() {
commits = getCommitLogs()
tableView.reloadData()
}

View file

@ -6,11 +6,11 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class EditPasswordTableViewController: PasswordEditorTableViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
if identifier == "saveEditPasswordSegue" {
// check name
guard checkName() else {

View file

@ -6,8 +6,8 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class GeneralSettingsTableViewController: BasicStaticTableViewController {
let passwordStore = PasswordStore.shared
@ -67,37 +67,35 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
override func viewDidLoad() {
tableData = [
// section 0
[[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"],],
[[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"]],
// section 1
[
[.title: "RememberPgpKeyPassphrase".localize(), .action: "none",],
[.title: "RememberGitCredentialPassphrase".localize(), .action: "none",],
[.title: "RememberPgpKeyPassphrase".localize(), .action: "none"],
[.title: "RememberGitCredentialPassphrase".localize(), .action: "none"],
],
// section 2
[
[.title: "ShowFolders".localize(), .action: "none",],
[.title: "HidePasswordImages".localize(), .action: "none",],
[.title: "HideUnknownFields".localize(), .action: "none",],
[.title: "HideOtpFields".localize(), .action: "none",],
[.title: "ShowFolders".localize(), .action: "none"],
[.title: "HidePasswordImages".localize(), .action: "none"],
[.title: "HideUnknownFields".localize(), .action: "none"],
[.title: "HideOtpFields".localize(), .action: "none"],
],
]
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
let cell = super.tableView(tableView, cellForRowAt: indexPath)
switch cell.textLabel!.text! {
case "HideUnknownFields".localize():
cell.accessoryType = .none
let detailButton = UIButton(type: .detailDisclosure)
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideUnknownSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width+10, height: hideUnknownSwitch.bounds.height))
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width + 10, height: hideUnknownSwitch.bounds.height))
accessoryView.addSubview(detailButton)
accessoryView.addSubview(hideUnknownSwitch)
cell.accessoryView = accessoryView
@ -106,10 +104,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
case "HideOtpFields".localize():
cell.accessoryType = .none
let detailButton = UIButton(type: .detailDisclosure)
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideOTPSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width+10, height: hideOTPSwitch.bounds.height))
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width + 10, height: hideOTPSwitch.bounds.height))
accessoryView.addSubview(detailButton)
accessoryView.addSubview(hideOTPSwitch)
cell.accessoryView = accessoryView
@ -130,10 +128,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
case "HidePasswordImages".localize():
cell.accessoryType = .none
let detailButton = UIButton(type: .detailDisclosure)
hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height)
hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height)
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHidePasswordImagesSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width+10, height: hidePasswordImagesSwitch.bounds.height))
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width + 10, height: hidePasswordImagesSwitch.bounds.height))
accessoryView.addSubview(detailButton)
accessoryView.addSubview(hidePasswordImagesSwitch)
cell.accessoryView = accessoryView
@ -144,43 +142,50 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
return cell
}
@objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) {
@objc
func tapHideUnknownSwitchDetailButton(_: Any?) {
let alertMessage = "HideUnknownFieldsExplanation.".localize()
let alertTitle = "HideUnknownFields".localize()
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
}
@objc func tapHideOTPSwitchDetailButton(_ sender: Any?) {
@objc
func tapHideOTPSwitchDetailButton(_: Any?) {
let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ", ")
let alertMessage = "HideOtpFieldsExplanation.".localize(keywordsString)
let alertTitle = "HideOtpFields".localize()
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
}
@objc func tapHidePasswordImagesSwitchDetailButton(_ sender: Any?) {
@objc
func tapHidePasswordImagesSwitchDetailButton(_: Any?) {
let alertMessage = "HidePasswordImagesExplanation.".localize()
let alertTitle = "HidePasswordImages".localize()
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
}
@objc func hideUnknownSwitchAction(_ sender: Any?) {
@objc
func hideUnknownSwitchAction(_: Any?) {
Defaults.isHideUnknownOn = hideUnknownSwitch.isOn
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
}
@objc func hideOTPSwitchAction(_ sender: Any?) {
@objc
func hideOTPSwitchAction(_: Any?) {
Defaults.isHideOTPOn = hideOTPSwitch.isOn
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
}
@objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) {
@objc
func rememberPGPPassphraseSwitchAction(_: Any?) {
Defaults.isRememberPGPPassphraseOn = rememberPGPPassphraseSwitch.isOn
if rememberPGPPassphraseSwitch.isOn == false {
AppKeychain.shared.removeAllContent(withPrefix: Globals.pgpKeyPassphrase)
}
}
@objc func rememberGitCredentialPassphraseSwitchAction(_ sender: Any?) {
@objc
func rememberGitCredentialPassphraseSwitchAction(_: Any?) {
Defaults.isRememberGitCredentialPassphraseOn = rememberGitCredentialPassphraseSwitch.isOn
if rememberGitCredentialPassphraseSwitch.isOn == false {
passwordStore.gitSSHPrivateKeyPassphrase = nil
@ -188,14 +193,15 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
}
}
@objc func showFolderSwitchAction(_ sender: Any?) {
@objc
func showFolderSwitchAction(_: Any?) {
Defaults.isShowFolderOn = showFolderSwitch.isOn
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
}
@objc func hidePasswordImagesSwitchAction(_ sender: Any?) {
@objc
func hidePasswordImagesSwitchAction(_: Any?) {
Defaults.isHidePasswordImagesOn = hidePasswordImagesSwitch.isOn
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
}
}

View file

@ -6,14 +6,14 @@
// Copyright © 2017 Yishi Lin. All rights reserved.
//
import UIKit
import passKit
import UIKit
class GitConfigSettingsTableViewController: UITableViewController {
let passwordStore = PasswordStore.shared
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet var nameTextField: UITextField!
@IBOutlet var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
@ -26,7 +26,7 @@ class GitConfigSettingsTableViewController: UITableViewController {
emailTextField.text = Defaults.gitSignatureEmail
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
if identifier == "saveGitConfigSettingSegue" {
let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text!
let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text!
@ -38,4 +38,3 @@ class GitConfigSettingsTableViewController: UITableViewController {
return true
}
}

View file

@ -6,21 +6,20 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SVProgressHUD
import passKit
import SVProgressHUD
import UIKit
class GitRepositorySettingsTableViewController: UITableViewController {
// MARK: - View Outlet
@IBOutlet weak var gitURLTextField: UITextField!
@IBOutlet weak var usernameTextField: UITextField!
@IBOutlet weak var branchNameTextField: UITextField!
@IBOutlet weak var authSSHKeyCell: UITableViewCell!
@IBOutlet weak var authPasswordCell: UITableViewCell!
@IBOutlet weak var gitURLCell: UITableViewCell!
@IBOutlet weak var gitRepositoryURLTabelViewCell: UITableViewCell!
@IBOutlet var gitURLTextField: UITextField!
@IBOutlet var usernameTextField: UITextField!
@IBOutlet var branchNameTextField: UITextField!
@IBOutlet var authSSHKeyCell: UITableViewCell!
@IBOutlet var authPasswordCell: UITableViewCell!
@IBOutlet var gitURLCell: UITableViewCell!
@IBOutlet var gitRepositoryURLTabelViewCell: UITableViewCell!
// MARK: - Properties
@ -33,27 +32,29 @@ class GitRepositorySettingsTableViewController: UITableViewController {
updateAuthenticationMethodCheckView(for: newValue)
}
}
private var gitUrl: URL {
get { Defaults.gitURL }
set { Defaults.gitURL = newValue }
}
private var gitBranchName: String {
get { Defaults.gitBranchName }
set { Defaults.gitBranchName = newValue }
}
private var gitUsername: String {
get { Defaults.gitUsername }
set { Defaults.gitUsername = newValue }
}
private var gitCredential: GitCredential {
get {
switch Defaults.gitAuthenticationMethod {
case .password:
return GitCredential(credential: .http(userName: Defaults.gitUsername))
case .key:
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
}
switch Defaults.gitAuthenticationMethod {
case .password:
return GitCredential(credential: .http(userName: Defaults.gitUsername))
case .key:
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
}
}
@ -61,9 +62,9 @@ class GitRepositorySettingsTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
gitURLTextField.text = self.gitUrl.absoluteString
usernameTextField.text = self.gitUsername
branchNameTextField.text = self.gitBranchName
gitURLTextField.text = gitUrl.absoluteString
usernameTextField.text = gitUsername
branchNameTextField.text = gitBranchName
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
authSSHKeyCell.accessoryType = .detailButton
}
@ -94,7 +95,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if cell == authPasswordCell {
self.gitAuthenticationMethod = .password
gitAuthenticationMethod = .password
} else if cell == authSSHKeyCell {
if !AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey()) {
Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self)
@ -108,7 +109,8 @@ class GitRepositorySettingsTableViewController: UITableViewController {
// MARK: - Segue Handlers
@IBAction func save(_ sender: Any) {
@IBAction
func save(_: Any) {
guard let gitURLTextFieldText = gitURLTextField.text, let gitURL = URL(string: gitURLTextFieldText.trimmed) else {
Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self)
return
@ -137,9 +139,9 @@ class GitRepositorySettingsTableViewController: UITableViewController {
}
}
self.gitUrl = gitURL
self.gitBranchName = branchName.trimmed
self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
gitUrl = gitURL
gitBranchName = branchName.trimmed
gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
if passwordStore.repositoryExists() {
let overwriteAlert: UIAlertController = {
@ -150,7 +152,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
alert.addAction(UIAlertAction.cancel())
return alert
}()
self.present(overwriteAlert, animated: true)
present(overwriteAlert, animated: true)
} else {
cloneAndSegueIfSuccess()
}
@ -159,15 +161,15 @@ class GitRepositorySettingsTableViewController: UITableViewController {
private func cloneAndSegueIfSuccess() {
// Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone.
Defaults.isRememberGitCredentialPassphraseOn = true
DispatchQueue.global(qos: .userInitiated).async() {
DispatchQueue.global(qos: .userInitiated).async {
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 gitTransferProgress = git_transfer_progress.pointee
let progress = Float(gitTransferProgress.received_objects) / Float(gitTransferProgress.total_objects)
SVProgressHUD.showProgress(progress, status: "Cloning Remote Repository")
}
let checkoutProgressBlock: (String, UInt, UInt) -> Void = { (_, completedSteps, totalSteps) in
let checkoutProgressBlock: (String, UInt, UInt) -> Void = { _, completedSteps, totalSteps in
let progress = Float(completedSteps) / Float(totalSteps)
SVProgressHUD.showProgress(progress, status: "CheckingOutBranch".localize(self.gitBranchName))
}
@ -179,7 +181,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
transferProgressBlock: transferProgressBlock,
checkoutProgressBlock: checkoutProgressBlock)
SVProgressHUD.dismiss() {
SVProgressHUD.dismiss {
let savePassphraseAlert: UIAlertController = {
let alert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in
@ -188,7 +190,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
self.passwordStore.gitSSHPrivateKeyPassphrase = nil
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
})
alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) {_ in
alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
Defaults.isRememberGitCredentialPassphraseOn = true
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
})
@ -199,7 +201,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
}
}
} catch {
SVProgressHUD.dismiss() {
SVProgressHUD.dismiss {
let error = error as NSError
var message = error.localizedDescription
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
@ -213,7 +215,8 @@ class GitRepositorySettingsTableViewController: UITableViewController {
}
}
@IBAction func importSSHKey(segue: UIStoryboardSegue) {
@IBAction
func importSSHKey(segue: UIStoryboardSegue) {
guard let sourceController = segue.source as? KeyImporter, sourceController.isReadyToUse() else {
return
}
@ -278,7 +281,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
}
private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
}
private func updateAuthenticationMethodCheckView(for method: GitAuthenticationMethod) {
@ -297,21 +300,20 @@ class GitRepositorySettingsTableViewController: UITableViewController {
private func showGitURLFormatHelp() {
let message = """
https://example.com[:port]/project.git
ssh://[user@]server[:port]/project.git
[user@]server:project.git (no scheme)
"""
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)
}
}
extension GitRepositorySettingsTableViewController: KeyImporter {
static let keySource = KeySource.itunes
static let label = "ITunesFileSharing".localize()
func isReadyToUse() -> Bool {
return KeyFileManager.PrivateSsh.doesKeyFileExist()
KeyFileManager.PrivateSsh.doesKeyFileExist()
}
func importKeys() throws {

View file

@ -9,7 +9,6 @@
import passKit
protocol KeyImporter {
static var keySource: KeySource { get }
static var label: String { get }
@ -24,9 +23,8 @@ protocol KeyImporter {
}
extension KeyImporter {
static var isCurrentKeySource: Bool {
return Defaults.gitSSHKeySource == Self.keySource
Defaults.gitSSHKeySource == Self.keySource
}
static var menuLabel: String {

View file

@ -6,11 +6,10 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SafariServices
import UIKit
class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
private static let openSourceComponents = [
["FavIcon",
"https://github.com/bitserf/FavIcon",
@ -48,12 +47,13 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
.link: item[1],
.accessoryType: UITableViewCell.AccessoryType.detailDisclosureButton,
.detailDisclosureAction: #selector(actOnDetailDisclosureButton(_:)),
.detailDisclosureData: item[2]
.detailDisclosureData: item[2],
])
}
}
@objc func actOnDetailDisclosureButton(_ sender: Any?) {
@objc
func actOnDetailDisclosureButton(_ sender: Any?) {
if let link = sender as? String, let url = URL(string: link) {
let svc = SFSafariViewController(url: url, entersReaderIfAvailable: false)
present(svc, animated: true)

View file

@ -6,15 +6,14 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
@IBOutlet weak var armorPublicKeyTextView: UITextView!
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
@IBOutlet weak var scanPublicKeyCell: UITableViewCell!
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
@IBOutlet var armorPublicKeyTextView: UITextView!
@IBOutlet var armorPrivateKeyTextView: UITextView!
@IBOutlet var scanPublicKeyCell: UITableViewCell!
@IBOutlet var scanPrivateKeyCell: UITableViewCell!
var armorPublicKey: String?
var armorPrivateKey: String?
@ -23,45 +22,47 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
enum KeyType {
case publicKey, privateKey
}
var keyType = KeyType.publicKey
var segments = [String]()
var message = ""
func reset(keytype: KeyType) {
self.keyType = keytype
self.segments.removeAll()
keyType = keytype
segments.removeAll()
message = "LookingForStartingFrame.".localize()
}
func addSegment(segment: String) -> (accept: Bool, message: String) {
let keyTypeStr = self.keyType == .publicKey ? "Public" : "Private"
let theOtherKeyTypeStr = self.keyType == .publicKey ? "Private" : "Public"
let keyTypeStr = keyType == .publicKey ? "Public" : "Private"
let theOtherKeyTypeStr = keyType == .publicKey ? "Private" : "Public"
// Skip duplicated segments.
guard segment != self.segments.last else {
return (accept: false, message: self.message)
guard segment != segments.last else {
return (accept: false, message: message)
}
// Check whether we have found the first block.
guard !self.segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else {
guard !segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else {
// Check whether we are scanning the wrong key type.
if segment.contains("-----BEGIN PGP \(theOtherKeyTypeStr.uppercased()) KEY BLOCK-----") {
self.message = "Scan\(keyTypeStr)Key.".localize()
message = "Scan\(keyTypeStr)Key.".localize()
}
return (accept: false, message: self.message)
return (accept: false, message: message)
}
// Update the list of scanned segment and return.
self.segments.append(segment)
segments.append(segment)
if segment.contains("-----END PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") {
self.message = "Done".localize()
return (accept: true, message: self.message)
message = "Done".localize()
return (accept: true, message: message)
} else {
self.message = "ScannedQrCodes(%d)".localize(self.segments.count)
return (accept: false, message: self.message)
message = "ScannedQrCodes(%d)".localize(segments.count)
return (accept: false, message: message)
}
}
}
var scanned = ScannedPGPKey()
override func viewDidLoad() {
@ -76,13 +77,14 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
}
@IBAction func save(_ sender: Any) {
@IBAction
func save(_: Any) {
armorPublicKey = armorPublicKeyTextView.text
armorPrivateKey = armorPrivateKeyTextView.text
self.saveImportedKeys()
saveImportedKeys()
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
if text == UIPasteboard.general.string {
// user pastes something, do the copy here again and clear the pasteboard in 45s
SecurePasteboard.shared.copy(textToCopy: text)
@ -94,21 +96,23 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
let selectedCell = tableView.cellForRow(at: indexPath)
if selectedCell == scanPublicKeyCell {
scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey)
self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
} else if selectedCell == scanPrivateKeyCell {
scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey)
self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
}
tableView.deselectRow(at: indexPath, animated: true)
}
// MARK: - QRScannerControllerDelegate Methods
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
return scanned.addSegment(segment: line)
}
// MARK: - QRScannerControllerDelegate Methods
func handleScannedOutput(line: String) {
func handleScannedOutput(line _: String) {
let key = scanned.segments.joined(separator: "")
switch scanned.keyType {
case .publicKey:
@ -118,7 +122,7 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
if segue.identifier == "showPGPScannerSegue" {
if let navController = segue.destination as? UINavigationController {
if let viewController = navController.topViewController as? QRScannerController {
@ -132,7 +136,6 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
}
extension PGPKeyArmorImportTableViewController: PGPKeyImporter {
static let keySource = KeySource.armor
static let label = "AsciiArmorEncryptedKey".localize()

View file

@ -9,18 +9,18 @@
import passKit
class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet var pgpPublicKeyFile: UITableViewCell!
@IBOutlet var pgpPrivateKeyFile: UITableViewCell!
@IBOutlet weak var pgpPublicKeyFile: UITableViewCell!
@IBOutlet weak var pgpPrivateKeyFile: UITableViewCell!
private var publicKey: String? = nil
private var privateKey: String? = nil
private var publicKey: String?
private var privateKey: String?
private enum KeyType { case none, `private`, `public` }
private var currentlyPicking = KeyType.none
@IBAction func save(_ sender: Any) {
self.saveImportedKeys()
@IBAction
func save(_: Any) {
saveImportedKeys()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
@ -43,7 +43,6 @@ class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
}
extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) {
guard let url = url.first else {
return
@ -78,12 +77,11 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
}
extension PGPKeyFileImportTableViewController: PGPKeyImporter {
static let keySource = KeySource.file
static let label = "LoadFromFiles".localize()
func isReadyToUse() -> Bool {
return validate(key: publicKey) && validate(key: privateKey)
validate(key: publicKey) && validate(key: privateKey)
}
func importKeys() throws {

View file

@ -9,19 +9,15 @@
import passKit
protocol PGPKeyImporter: KeyImporter {
func doAfterImport()
func saveImportedKeys()
}
extension PGPKeyImporter {
static var isCurrentKeySource: Bool {
return Defaults.pgpKeySource == Self.keySource
Defaults.pgpKeySource == Self.keySource
}
func doAfterImport() {
}
func doAfterImport() {}
}

View file

@ -6,13 +6,12 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var pgpPublicKeyURLTextField: UITextField!
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
@IBOutlet var pgpPublicKeyURLTextField: UITextField!
@IBOutlet var pgpPrivateKeyURLTextField: UITextField!
var pgpPrivateKeyURL: URL?
var pgpPublicKeyURL: URL?
@ -22,31 +21,31 @@ class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
pgpPublicKeyURLTextField.text = Defaults.pgpPublicKeyURL?.absoluteString
pgpPrivateKeyURLTextField.text = Defaults.pgpPrivateKeyURL?.absoluteString
}
@IBAction func save(_ sender: Any) {
@IBAction
func save(_: Any) {
guard let publicKeyURLText = pgpPublicKeyURLTextField.text,
let publicKeyURL = URL(string: publicKeyURLText),
let privateKeyURLText = pgpPrivateKeyURLTextField.text,
let privateKeyURL = URL(string: privateKeyURLText) else {
Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
return
Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
return
}
if privateKeyURL.scheme?.lowercased() == "http" || publicKeyURL.scheme?.lowercased() == "http" {
Utils.alert(title: "HttpNotSecure".localize(), message: "ReallyUseHttp.".localize(), controller: self)
}
pgpPrivateKeyURL = privateKeyURL
pgpPublicKeyURL = publicKeyURL
self.saveImportedKeys()
saveImportedKeys()
}
}
extension PGPKeyUrlImportTableViewController: PGPKeyImporter {
static let keySource = KeySource.url
static let label = "DownloadFromUrl".localize()
func isReadyToUse() -> Bool {
return validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "")
validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "")
&& validate(pgpKeyUrl: pgpPrivateKeyURLTextField.text ?? "")
}

View file

@ -6,16 +6,16 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import FavIcon
import SVProgressHUD
import passKit
import SVProgressHUD
import UIKit
class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate {
var passwordEntity: PasswordEntity?
private var password: Password?
private var passwordImage: UIImage?
private var oneTimePasswordIndexPath : IndexPath?
private var oneTimePasswordIndexPath: IndexPath?
private var shouldPopCurrentView = false
private let passwordStore = PasswordStore.shared
private let keychain = AppKeychain.shared
@ -52,7 +52,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
tableView.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
tableView.contentInset = UIEdgeInsets.init(top: -36, left: 0, bottom: 44, right: 0);
tableView.contentInset = UIEdgeInsets(top: -36, left: 0, bottom: 44, right: 0)
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 52
@ -66,8 +66,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
let image = UIImage(data: imageData as Data)
passwordImage = image
}
self.decryptThenShowPassword()
self.setupOneTimePasswordAutoRefresh()
decryptThenShowPassword()
setupOneTimePasswordAutoRefresh()
// pop the current view because this password might be "discarded"
NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil)
@ -78,16 +78,17 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.shouldPopCurrentView {
if shouldPopCurrentView {
let alert = UIAlertController(title: "Notice".localize(), message: "PreviousChangesDiscarded.".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction.okAndPopView(controller: self))
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
}
}
@objc private func decryptThenShowPassword(keyID: String? = nil) {
@objc
private func decryptThenShowPassword(keyID: String? = nil) {
guard let passwordEntity = passwordEntity else {
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: {(UIAlertAction) -> Void in
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: { (_) -> Void in
self.navigationController!.popViewController(animated: true)
})
return
@ -98,7 +99,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self)
self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
self.showPassword()
} catch AppError.PgpPrivateKeyNotFound(let key) {
} catch let AppError.PgpPrivateKeyNotFound(key) {
DispatchQueue.main.async {
// alert: cancel or try again
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
@ -115,7 +116,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
// alert: cancel or try again
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) {_ in
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in
self.decryptThenShowPassword()
})
self.present(alert, animated: true, completion: nil)
@ -141,14 +142,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
private func setupOneTimePasswordAutoRefresh() {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
[weak self] timer in
[weak self] _ in
// bail out of the timer code if the object has been freed
guard let strongSelf = self,
let otpType = strongSelf.password?.otpType,
otpType != .none,
let indexPath = strongSelf.oneTimePasswordIndexPath,
let cell = strongSelf.tableView.cellForRow(at: indexPath) as? LabelTableViewCell else {
return
return
}
switch otpType {
case .totp:
@ -163,64 +164,67 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
}
}
@objc private func pressEdit(_ sender: Any?) {
@objc
private func pressEdit(_: Any?) {
performSegue(withIdentifier: "editPasswordSegue", sender: self)
}
@objc private func setShouldPopCurrentView() {
self.shouldPopCurrentView = true
@objc
private func setShouldPopCurrentView() {
shouldPopCurrentView = true
}
@IBAction private func cancelEditPassword(segue: UIStoryboardSegue) {
@IBAction
private func cancelEditPassword(segue _: UIStoryboardSegue) {}
}
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
if self.password!.changed != 0 {
self.saveEditPassword(password: self.password!)
@IBAction
private func saveEditPassword(segue _: UIStoryboardSegue) {
if password!.changed != 0 {
saveEditPassword(password: password!)
}
}
private func saveEditPassword(password: Password, keyID: String? = nil) {
SVProgressHUD.show(withStatus: "Saving".localize())
do {
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: password, keyID: keyID)
self.setTableData()
self.tableView.reloadData()
passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password, keyID: keyID)
setTableData()
tableView.reloadData()
SVProgressHUD.showSuccess(withStatus: "Success".localize())
SVProgressHUD.dismiss(withDelay: 1)
} catch AppError.PgpPublicKeyNotFound(let key) {
DispatchQueue.main.async {
// alert: cancel or select keys
SVProgressHUD.dismiss()
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
let selectKey = UIAlertAction.selectKey(controller: self) { action in
self.saveEditPassword(password: password, keyID: action.title)
}
alert.addAction(selectKey)
} catch let AppError.PgpPublicKeyNotFound(key) {
DispatchQueue.main.async {
// alert: cancel or select keys
SVProgressHUD.dismiss()
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
let selectKey = UIAlertAction.selectKey(controller: self) { action in
self.saveEditPassword(password: password, keyID: action.title)
}
alert.addAction(selectKey)
self.present(alert, animated: true, completion: nil)
}
return
} catch {
DispatchQueue.main.async {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
}
}
self.present(alert, animated: true, completion: nil)
}
return
} catch {
DispatchQueue.main.async {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
}
}
}
@IBAction private func deletePassword(segue: UIStoryboardSegue) {
@IBAction
private func deletePassword(segue _: UIStoryboardSegue) {
do {
try passwordStore.delete(passwordEntity: passwordEntity!)
} catch {
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
}
let _ = navigationController?.popViewController(animated: true)
_ = navigationController?.popViewController(animated: true)
}
private func setTableData() {
self.tableData = Array<TableSection>()
tableData = [TableSection]()
// name section
var section = TableSection(type: .name)
@ -239,7 +243,6 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
section.item.append(Constants.PASSWORD_KEYWORD => password.password)
tableData.append(section)
// addition section
// show one time password
@ -254,7 +257,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
// show additional information
let filteredAdditionKeys = password.getFilteredAdditions()
if filteredAdditionKeys.count > 0 {
if !filteredAdditionKeys.isEmpty {
section = TableSection(type: .addition, header: "Additions".localize())
section.item.append(contentsOf: filteredAdditionKeys)
tableData.append(section)
@ -264,10 +267,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
section = TableSection(type: .misc)
section.item.append(AdditionField(title: "ShowRaw".localize()))
tableData.append(section)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
if segue.identifier == "editPasswordSegue" {
if let controller = segue.destination as? UINavigationController {
if let editController = controller.viewControllers.first as? EditPasswordTableViewController {
@ -288,9 +290,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
if urlString.lowercased().hasPrefix("http://") {
// try to replace http url to https url
newUrlString = urlString.replacingOccurrences(of: "http://",
with: "https://",
options: .caseInsensitive,
range: urlString.range(of: "http://"))
with: "https://",
options: .caseInsensitive,
range: urlString.range(of: "http://"))
} else if urlString.lowercased().hasPrefix("https://") {
// do nothing here
} else {
@ -311,11 +313,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
}
}
@objc private func tapMenu(recognizer: UITapGestureRecognizer) {
@objc
private func tapMenu(recognizer: UITapGestureRecognizer) {
if recognizer.state == UIGestureRecognizer.State.ended {
let tapLocation = recognizer.location(in: self.tableView)
if let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation) {
if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
let tapLocation = recognizer.location(in: tableView)
if let tapIndexPath = tableView.indexPathForRow(at: tapLocation) {
if let tappedCell = tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
tappedCell.becomeFirstResponder()
let menuController = UIMenuController.shared
let revealItem = UIMenuItem(title: "Reveal".localize(), action: #selector(LabelTableViewCell.revealPassword(_:)))
@ -330,22 +333,22 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
func gestureRecognizer(_: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view!.isKind(of: UIButton.classForCoder()) {
return false
}
return true
}
@IBAction func back(segue:UIStoryboardSegue) {
}
@IBAction
func back(segue _: UIStoryboardSegue) {}
func getNextHOTP() {
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
DispatchQueue.main.async {
Utils.alert(title: "Error".localize(), message: "GetNextPasswordOfNonHotp.".localize(), controller: self, completion: nil)
}
return;
return
}
// copy HOTP to pasteboard (will update counter)
@ -356,7 +359,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
// commit the change of HOTP counter
if password!.changed != 0 {
do {
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password!)
SVProgressHUD.showSuccess(withStatus: "PasswordCopied".localize() | "CounterUpdated".localize())
SVProgressHUD.dismiss(withDelay: 1)
} catch {
@ -384,19 +387,19 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
return from
}
override func numberOfSections(in tableView: UITableView) -> Int {
return tableData.count
override func numberOfSections(in _: UITableView) -> Int {
tableData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData[section].item.count
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
tableData[section].item.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sectionIndex = indexPath.section
let rowIndex = indexPath.row
let tableDataItem = tableData[sectionIndex].item[rowIndex]
switch(tableData[sectionIndex].type) {
switch tableData[sectionIndex].type {
case .name:
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordDetailTitleTableViewCell", for: indexPath) as! PasswordDetailTitleTableViewCell
if !Defaults.isHidePasswordImagesOn {
@ -453,8 +456,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
detailTextLabel.text = "HiddenFields(%d)".localize(numberOfHiddenFields)
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return tableData[section].header
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
tableData[section].header
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
@ -464,7 +467,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
footerLabel.numberOfLines = 0
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
footerLabel.textColor = UIColor.gray
let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path)
let dateString = passwordStore.getLatestUpdateInfo(filename: password!.url.path)
footerLabel.text = "LastUpdated".localize(dateString)
view.addSubview(footerLabel)
return view
@ -472,15 +475,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
return nil
}
override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
override func tableView(_: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) {
if action == #selector(copy(_:)) {
SecurePasteboard.shared.copy(textToCopy: tableData[indexPath.section].item[indexPath.row].content)
}
}
override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
override func tableView(_: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) -> Bool {
let section = tableData[indexPath.section]
switch(section.type) {
switch section.type {
case .main, .addition:
return action == #selector(UIResponderStandardEditActions.copy(_:))
default:
@ -488,8 +491,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
}
}
override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
return true
override func tableView(_: UITableView, shouldShowMenuForRowAt _: IndexPath) -> Bool {
true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

View file

@ -6,10 +6,10 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SafariServices
import OneTimePassword
import passKit
import SafariServices
import UIKit
enum PasswordEditorCellType: Equatable {
case nameCell
@ -30,18 +30,16 @@ enum PasswordEditorCellKey {
}
protocol PasswordSettingSliderTableViewCellDelegate {
func generateAndCopyPassword()
}
class PasswordEditorTableViewController: UITableViewController {
var tableData = [[Dictionary<PasswordEditorCellKey, Any>]]()
var tableData = [[[PasswordEditorCellKey: Any]]]()
var password: Password?
private var navigationItemTitle: String?
private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(),""].map {$0.uppercased()}
private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(), ""].map { $0.uppercased() }
private var sectionFooterTitles = ["", "", "UseKeyValueFormat.".localize(), ""]
private let nameSection = 0
private let passwordSection = 1
@ -86,7 +84,7 @@ class PasswordEditorTableViewController: UITableViewController {
passwordFlavorCell?.textLabel?.text = "PasswordGeneratorFlavor".localize()
passwordFlavorCell?.selectionStyle = .none
let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map { $0.localized })
let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map(\.localized))
passwordFlavorSelector.selectedSegmentIndex = PasswordGeneratorFlavor.allCases.firstIndex(of: passwordGenerator.flavor)!
passwordFlavorSelector.addTarget(self, action: #selector(flavorChanged), for: .valueChanged)
passwordFlavorCell?.accessoryView = passwordFlavorSelector
@ -126,11 +124,11 @@ class PasswordEditorTableViewController: UITableViewController {
],
[
[.type: PasswordEditorCellType.scanQRCodeCell],
]
],
]
if self.password != nil {
tableData[additionsSection+1].append([.type: PasswordEditorCellType.deletePasswordCell])
if password != nil {
tableData[additionsSection + 1].append([.type: PasswordEditorCellType.deletePasswordCell])
}
updateTableData(withRespectTo: passwordGenerator.flavor)
}
@ -206,11 +204,11 @@ class PasswordEditorTableViewController: UITableViewController {
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
override func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat {
44
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
override func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch tableData[indexPath.section][indexPath.row][PasswordEditorCellKey.type] as! PasswordEditorCellType {
case .passwordLengthCell, .passwordGroupsCell:
return 42
@ -221,11 +219,11 @@ class PasswordEditorTableViewController: UITableViewController {
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return tableData.count
override func numberOfSections(in _: UITableView) -> Int {
tableData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == passwordSection, hidePasswordSettings {
// hide the password section, only the password should be shown
return 1
@ -234,27 +232,27 @@ class PasswordEditorTableViewController: UITableViewController {
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionHeaderTitles[section]
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
sectionHeaderTitles[section]
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return sectionFooterTitles[section]
override func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
sectionFooterTitles[section]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
tableView.deselectRow(at: indexPath, animated: true)
if selectedCell == deletePasswordCell {
let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
self.performSegue(withIdentifier: "deletePasswordSegue", sender: self)
}))
alert.addAction(UIAlertAction.cancel())
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
} else if selectedCell == scanQRCodeCell {
self.performSegue(withIdentifier: "showQRScannerSegue", sender: self)
performSegue(withIdentifier: "showQRScannerSegue", sender: self)
}
}
@ -276,11 +274,12 @@ class PasswordEditorTableViewController: UITableViewController {
}
}
private func isPasswordDelimiterCellData(data: Dictionary<PasswordEditorCellKey, Any>) -> Bool {
return (data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell)
private func isPasswordDelimiterCellData(data: [PasswordEditorCellKey: Any]) -> Bool {
(data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell)
}
@objc func flavorChanged(_ sender: UISegmentedControl) {
@objc
func flavorChanged(_ sender: UISegmentedControl) {
let flavor = PasswordGeneratorFlavor.allCases[sender.selectedSegmentIndex]
guard passwordGenerator.flavor != flavor else {
return
@ -327,7 +326,7 @@ class PasswordEditorTableViewController: UITableViewController {
additionsCell?.setContent(content: additionsString)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
if segue.identifier == "showQRScannerSegue" {
if let navController = segue.destination as? UINavigationController {
if let viewController = navController.topViewController as? QRScannerController {
@ -362,8 +361,8 @@ class PasswordEditorTableViewController: UITableViewController {
// the name field should be a valid url
guard let path = name.stringByAddingPercentEncodingForRFC3986(),
var passwordURL = URL(string: path) else {
Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil)
return false
Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil)
return false
}
// check whether we can parse the filename (be consistent with PasswordStore::addPasswordEntities)
@ -382,20 +381,20 @@ class PasswordEditorTableViewController: UITableViewController {
}
// MARK: - FillPasswordTableViewCellDelegate
extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
// generate password, copy to pasteboard, and set the cell
// check whether the current password looks like an OTP field
func generateAndCopyPassword() {
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: {_ in
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: { _ in
self.generateAndCopyPasswordNoOtpCheck()
}))
alert.addAction(UIAlertAction.cancel())
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
} else {
self.generateAndCopyPasswordNoOtpCheck()
generateAndCopyPasswordNoOtpCheck()
}
}
@ -407,11 +406,12 @@ extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
}
// MARK: - PasswordSettingSliderTableViewCellDelegate
extension PasswordEditorTableViewController: PasswordSettingSliderTableViewCellDelegate {}
// MARK: - QRScannerControllerDelegate
extension PasswordEditorTableViewController: QRScannerControllerDelegate {
extension PasswordEditorTableViewController: QRScannerControllerDelegate {
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
if let url = URL(string: line), let _ = Token(url: url) {
return (accept: true, message: "ValidTokenUrl".localize())
@ -426,31 +426,31 @@ extension PasswordEditorTableViewController: QRScannerControllerDelegate {
}
// MARK: - SFSafariViewControllerDelegate
extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_: SFSafariViewController) {
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter { !$0.isEmpty }
if copiedLinesSplit?.count ?? 0 > 0 {
let generatedPassword = copiedLinesSplit![0]
let alert = UIAlertController(title: "WannaUseIt?".localize(), message: "", preferredStyle: UIAlertController.Style.alert)
let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\n")
message.append(Utils.attributedPassword(plainPassword: generatedPassword))
alert.setValue(message, forKey: "attributedMessage")
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: {[unowned self] (action) -> Void in
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { [unowned self] (_) -> Void in
// update tableData so to make sure reloadData() works correctly
self.tableData[self.passwordSection][0][PasswordEditorCellKey.content] = generatedPassword
// update cell manually, no need to call reloadData()
self.fillPasswordCell?.setContent(content: generatedPassword)
}))
alert.addAction(UIAlertAction.cancel())
self.present(alert, animated: true, completion: nil)
present(alert, animated: true, completion: nil)
}
}
}
// MARK: - UITextFieldDelegate
extension PasswordEditorTableViewController: UITextFieldDelegate {
extension PasswordEditorTableViewController: UITextFieldDelegate {
// update tableData so to make sure reloadData() works correctly
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == nameCell?.contentTextField {
@ -471,8 +471,8 @@ extension PasswordEditorTableViewController: UITextFieldDelegate {
}
// MARK: - UITextViewDelegate
extension PasswordEditorTableViewController: UITextViewDelegate {
extension PasswordEditorTableViewController: UITextViewDelegate {
// update tableData so to make sure reloadData() works correctly
func textViewDidEndEditing(_ textView: UITextView) {
if textView == additionsCell?.contentTextView {

View file

@ -6,16 +6,16 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SVProgressHUD
import passKit
import SVProgressHUD
import UIKit
fileprivate let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold
private let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold
class PasswordsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITabBarControllerDelegate, UISearchBarDelegate {
private var passwordsTableEntries: [PasswordTableEntry] = []
private var passwordsTableAllEntries: [PasswordTableEntry] = []
private var parentPasswordEntity: PasswordEntity? = nil
private var parentPasswordEntity: PasswordEntity?
private let passwordStore = PasswordStore.shared
private let keychain = AppKeychain.shared
@ -30,14 +30,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
private var gitCredential: GitCredential {
get {
switch Defaults.gitAuthenticationMethod {
case .password:
return GitCredential(credential: .http(userName: Defaults.gitUsername))
case .key:
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
}
switch Defaults.gitAuthenticationMethod {
case .password:
return GitCredential(credential: .http(userName: Defaults.gitUsername))
case .key:
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
}
}
@ -49,11 +47,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
uiSearchController.searchBar.sizeToFit()
return uiSearchController
}()
private lazy var syncControl: UIRefreshControl = {
let syncControl = UIRefreshControl()
syncControl.addTarget(self, action: #selector(handleRefresh(_:)), for: UIControl.Event.valueChanged)
return syncControl
}()
private lazy var searchBarView: UIView? = {
guard #available(iOS 11, *) else {
let uiView = UIView(frame: CGRect(x: 0, y: 64, width: self.view.bounds.width, height: 44))
@ -62,6 +62,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
return nil
}()
private lazy var backUIBarButtonItem: UIBarButtonItem = {
let backUIButton = UIButton(type: .system)
if #available(iOS 13.0, *) {
@ -116,28 +117,29 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
return transition
}()
@IBOutlet weak var tableView: UITableView!
@IBOutlet var tableView: UITableView!
private func initPasswordsTableEntries(parent: PasswordEntity?) {
let passwordAllEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
let passwordAllEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false)
passwordsTableAllEntries = passwordAllEntities.compactMap {
PasswordTableEntry($0)
}
let passwordEntities = Defaults.isShowFolderOn ?
self.passwordStore.fetchPasswordEntityCoreData(parent: parent) :
passwordStore.fetchPasswordEntityCoreData(parent: parent) :
passwordAllEntities
passwordsTableEntries = passwordEntities.compactMap {
PasswordTableEntry($0)
}
parentPasswordEntity = parent
}
@IBAction func cancelAddPassword(segue: UIStoryboardSegue) {
@IBAction
func cancelAddPassword(segue _: UIStoryboardSegue) {}
}
@IBAction func saveAddPassword(segue: UIStoryboardSegue) {
@IBAction
func saveAddPassword(segue: UIStoryboardSegue) {
if let controller = segue.source as? AddPasswordTableViewController {
addPassword(password: controller.password!)
}
@ -149,13 +151,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
SVProgressHUD.show(withStatus: "Saving".localize())
DispatchQueue.global(qos: .userInitiated).async {
do {
let _ = try self.passwordStore.add(password: password, keyID: keyID)
_ = try self.passwordStore.add(password: password, keyID: keyID)
DispatchQueue.main.async {
// will trigger reloadTableView() by a notification
SVProgressHUD.showSuccess(withStatus: "Done".localize())
SVProgressHUD.dismiss(withDelay: 1)
}
} catch AppError.PgpPublicKeyNotFound(let key) {
} catch let AppError.PgpPublicKeyNotFound(key) {
DispatchQueue.main.async {
// alert: cancel or select keys
SVProgressHUD.dismiss()
@ -190,15 +192,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
do {
try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: {(git_transfer_progress, stop) in
try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: { git_transfer_progress, _ in
DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize())
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize())
}
})
if self.passwordStore.numberOfLocalCommits > 0 {
try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: {(current, total, bytes, stop) in
try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: { current, total, _, _ in
DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(current)/Float(total), status: "PushingToRemoteRepository".localize())
SVProgressHUD.showProgress(Float(current) / Float(total), status: "PushingToRemoteRepository".localize())
}
})
}
@ -232,7 +234,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
super.viewDidAppear(animated)
if Defaults.isShowFolderOn {
searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map { $0.localizedName }
searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map(\.localizedName)
} else {
searchController.searchBar.scopeButtonTitles = nil
}
@ -251,7 +253,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
navigationItem.hidesSearchBarWhenScrolling = false
} else {
// Fallback on earlier versions
tableView.contentInset = UIEdgeInsets.init(top: 44, left: 0, bottom: 0, right: 0)
tableView.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: 0, right: 0)
view.addSubview(searchBarView!)
}
navigationItem.title = "PasswordStore".localize()
@ -272,16 +274,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: UIApplication.willEnterForegroundNotification, object: nil)
// listen to the swipe back guesture
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
swipeRight.direction = UISwipeGestureRecognizer.Direction.right
self.view.addGestureRecognizer(swipeRight)
view.addGestureRecognizer(swipeRight)
}
@objc func didTapNavigationBar(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: self.navigationController?.navigationBar)
let hitView = self.navigationController?.navigationBar.hitTest(location, with: nil)
@objc
func didTapNavigationBar(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: navigationController?.navigationBar)
let hitView = navigationController?.navigationBar.hitTest(location, with: nil)
guard !(hitView is UIControl) else { return }
guard (passwordStore.numberOfLocalCommits != 0) else { return }
guard passwordStore.numberOfLocalCommits != 0 else { return }
let ac = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let allAction = UIAlertAction(title: "All Passwords", style: .default) { _ in
@ -289,7 +292,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
let unsyncedAction = UIAlertAction(title: "Unsynced Passwords", style: .default) { _ in
let filteredPasswordsTableEntries = self.passwordsTableEntries.filter { entry in
return !entry.synced
!entry.synced
}
self.reloadTableView(data: filteredPasswordsTableEntries, label: .unsynced)
}
@ -299,7 +302,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
ac.addAction(unsyncedAction)
ac.addAction(cancelAction)
self.present(ac, animated: true, completion: nil)
present(ac, animated: true, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
@ -310,7 +313,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
// Add gesture recognizer to the navigation bar when the view is about to appear
self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
// This allows controlls in the navigation bar to continue receiving touches
tapNavigationBarGestureRecognizer.cancelsTouchesInView = false
@ -318,9 +321,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
tableView.refreshControl = passwordStore.repositoryExists() ? syncControl : nil
}
override func viewWillDisappear(_ animated: Bool) {
override func viewWillDisappear(_: Bool) {
// Remove gesture recognizer from navigation bar when view is about to disappear
self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
}
override func viewWillLayoutSubviews() {
@ -332,12 +335,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
func numberOfSections(in _: UITableView) -> Int {
sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].entries.count
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
sections[section].entries.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@ -372,7 +375,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
private func getPasswordEntry(by indexPath: IndexPath) -> PasswordTableEntry {
return sections[indexPath.section].entries[indexPath.row]
sections[indexPath.section].entries[indexPath.row]
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
@ -390,16 +393,18 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
}
@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
@objc
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
// swipe right -> swipe back
if swipeGesture.direction == .right && parentPasswordEntity != nil {
self.backAction(nil)
if swipeGesture.direction == .right, parentPasswordEntity != nil {
backAction(nil)
}
}
}
@objc func backAction(_ sender: Any?) {
@objc
func backAction(_: Any?) {
guard Defaults.isShowFolderOn else { return }
var anim: CATransition? = transitionFromLeft
if parentPasswordEntity == nil {
@ -408,13 +413,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
reloadTableView(parent: parentPasswordEntity?.parent, anim: anim)
}
@objc func addPasswordAction(_ sender: Any?) {
@objc
func addPasswordAction(_: Any?) {
if shouldPerformSegue(withIdentifier: "addPasswordSegue", sender: self) {
performSegue(withIdentifier: "addPasswordSegue", sender: self)
}
}
@objc func longPressAction(_ gesture: UILongPressGestureRecognizer) {
@objc
func longPressAction(_ gesture: UILongPressGestureRecognizer) {
if gesture.state == UIGestureRecognizer.State.began {
let touchPoint = gesture.location(in: tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
@ -424,31 +431,31 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
private func hideSectionHeader() -> Bool {
if passwordsTableEntries.count < hideSectionHeaderThreshold || self.searchController.isActive {
if passwordsTableEntries.count < hideSectionHeaderThreshold || searchController.isActive {
return true
}
return false
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
if hideSectionHeader() {
return nil
}
return sections[section].title
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
func sectionIndexTitles(for _: UITableView) -> [String]? {
if hideSectionHeader() {
return nil
}
return sections.map { $0.title }
return sections.map(\.title)
}
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return index
func tableView(_: UITableView, sectionForSectionIndexTitle _: String, at index: Int) -> Int {
index
}
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
decryptThenCopyPassword(from: indexPath)
}
@ -460,7 +467,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
SVProgressHUD.dismiss()
self.decryptPassword(passwordEntity: passwordEntity)
decryptPassword(passwordEntity: passwordEntity)
}
private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) {
@ -476,7 +483,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize())
SVProgressHUD.dismiss(withDelay: 0.6)
}
} catch AppError.PgpPrivateKeyNotFound(let key) {
} catch let AppError.PgpPrivateKeyNotFound(key) {
DispatchQueue.main.async {
// alert: cancel or try again
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
@ -488,7 +495,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
self.present(alert, animated: true)
}
} catch {
} catch {
DispatchQueue.main.async {
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self)
}
@ -496,14 +503,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
}
private func generateSections(item: [PasswordTableEntry]) {
let collation = UILocalizedIndexedCollation.current()
let sectionTitles = collation.sectionIndexTitles
var newSections = [(title: String, entries: [PasswordTableEntry])]()
// initialize all sections
for i in 0..<sectionTitles.count {
for i in 0 ..< sectionTitles.count {
newSections.append((title: sectionTitles[i], entries: [PasswordTableEntry]()))
}
@ -514,21 +520,21 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
// sort each list and set sectionTitles
for i in 0..<sectionTitles.count {
for i in 0 ..< sectionTitles.count {
let entriesToSort = newSections[i].entries
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
newSections[i].entries = sortedEntries as! [PasswordTableEntry]
}
// only keep non-empty sections
sections = newSections.filter {$0.entries.count > 0}
sections = newSections.filter { !$0.entries.isEmpty }
}
@objc func actOnSearchNotification() {
@objc
func actOnSearchNotification() {
searchController.searchBar.becomeFirstResponder()
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "showPasswordDetail" {
guard PGPAgent.shared.isPrepared else {
@ -540,7 +546,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
return false
}
} else if identifier == "addPasswordSegue" {
guard PGPAgent.shared.isPrepared && self.passwordStore.storeRepository != nil else {
guard PGPAgent.shared.isPrepared && passwordStore.storeRepository != nil else {
Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil)
return false
}
@ -551,7 +557,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPasswordDetail" {
if let viewController = segue.destination as? PasswordDetailTableViewController {
let selectedIndexPath = self.tableView.indexPath(for: sender as! UITableViewCell)!
let selectedIndexPath = tableView.indexPath(for: sender as! UITableViewCell)!
let passwordEntity = getPasswordEntry(by: selectedIndexPath).passwordEntity
viewController.passwordEntity = passwordEntity
}
@ -568,8 +574,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
func filterContentForSearchText(searchText: String, scope: SearchBarScope = .all) {
var entries: [PasswordTableEntry] = scope == .all ? passwordsTableAllEntries : passwordsTableEntries
if searchController.isActive && searchController.searchBar.text != "" {
entries = entries.filter {$0.match(searchText)}
if searchController.isActive, searchController.searchBar.text != "" {
entries = entries.filter { $0.match(searchText) }
}
reloadTableView(data: entries)
}
@ -587,7 +593,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
if #available(iOS 11, *) {
navigationController?.navigationBar.prefersLargeTitles = false
}
self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
} else {
navigationItem.leftBarButtonItem = nil
switch label {
@ -599,17 +605,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
if #available(iOS 11, *) {
navigationController?.navigationBar.prefersLargeTitles = true
}
self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
}
navigationItem.rightBarButtonItem = addPasswordUIBarButtonItem
// set the password table
generateSections(item: data)
if anim != nil {
self.tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey")
tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey")
}
tableView.reloadData()
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
// set the sync control title
let atribbutedTitle = "LastSynced".localize() + ": \(lastSyncedTimeString())"
@ -617,7 +623,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
private func lastSyncedTimeString() -> String {
guard let date = self.passwordStore.lastSyncedTime else {
guard let date = passwordStore.lastSyncedTime else {
return "SyncAgain?".localize()
}
let formatter = DateFormatter()
@ -631,7 +637,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
reloadTableView(data: passwordsTableEntries, label: label, anim: anim)
}
@objc func actOnReloadTableViewRelatedNotification() {
@objc
func actOnReloadTableViewRelatedNotification() {
DispatchQueue.main.async { [weak weakSelf = self] in
guard let strongSelf = weakSelf else { return }
// Reset selectedScopeButtonIndex to make sure the correct reloadTableView
@ -641,36 +648,37 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
}
@objc func handleRefresh(_ syncControl: UIRefreshControl) {
@objc
func handleRefresh(_: UIRefreshControl) {
syncPasswords()
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewController == self.navigationController {
func tabBarController(_: UITabBarController, didSelect viewController: UIViewController) {
if viewController == navigationController {
let currentTime = Date().timeIntervalSince1970
let duration = currentTime - self.tapTabBarTime
self.tapTabBarTime = currentTime
let duration = currentTime - tapTabBarTime
tapTabBarTime = currentTime
if duration < 0.35 {
let topIndexPath = IndexPath(row: 0, section: 0)
if tableView.numberOfSections > 0 {
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
}
self.tapTabBarTime = 0
if tableView.numberOfSections > 0 {
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
}
tapTabBarTime = 0
return
}
backAction(self)
}
}
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
func searchBar(_: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
// update the default search scope
Defaults.searchDefault = SearchBarScope(rawValue: selectedScope)
updateSearchResults(for: searchController)
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
func searchBarShouldBeginEditing(_: UISearchBar) -> Bool {
// set the default search scope to "all"
if Defaults.isShowFolderOn && Defaults.searchDefault == .all {
if Defaults.isShowFolderOn, Defaults.searchDefault == .all {
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.all.rawValue
} else {
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue
@ -678,7 +686,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
return true
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
func searchBarShouldEndEditing(_: UISearchBar) -> Bool {
// set the default search scope to "current"
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue
updateSearchResults(for: searchController)
@ -686,13 +694,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
}
private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
}
}
extension PasswordsViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let scope = SearchBarScope(rawValue: searchController.searchBar.selectedScopeButtonIndex) ?? .all
filterContentForSearchText(searchText: searchController.searchBar.text!, scope: scope)
@ -700,8 +706,7 @@ extension PasswordsViewController: UISearchResultsUpdating {
}
extension PasswordsViewController: CAAnimationDelegate {
func animationDidStart(_ anim: CAAnimation) {
func animationDidStart(_: CAAnimation) {
view.window?.backgroundColor = Colors.systemBackground
view.layer.backgroundColor = Colors.systemBackground.cgColor
}

View file

@ -6,11 +6,11 @@
// Copyright © 2017 Yishi Lin. All rights reserved.
//
import UIKit
import AVFoundation
import OneTimePassword
import SVProgressHUD
import passKit
import SVProgressHUD
import UIKit
protocol QRScannerControllerDelegate {
func checkScannedOutput(line: String) -> (accept: Bool, message: String)
@ -18,8 +18,7 @@ protocol QRScannerControllerDelegate {
}
class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
@IBOutlet weak var scannerOutput: UILabel!
@IBOutlet var scannerOutput: UILabel!
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
@ -93,15 +92,12 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
// Dispose of any resources that can be recreated.
}
// MARK: - AVCaptureMetadataOutputObjectsDelegate Methods
func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
func metadataOutput(_: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from _: AVCaptureConnection) {
if let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
supportedCodeTypes.contains(metadataObj.type),
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) {
// draw a bounds on the found QR code
qrCodeFrameView?.frame = barCodeObject.bounds

View file

@ -6,12 +6,11 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class RawPasswordViewController: UIViewController {
@IBOutlet weak var rawPasswordTextView: UITextView!
@IBOutlet var rawPasswordTextView: UITextView!
var password: Password?
override func viewDidLoad() {

View file

@ -6,13 +6,12 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import passKit
import UIKit
class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
@IBOutlet var armorPrivateKeyTextView: UITextView!
@IBOutlet var scanPrivateKeyCell: UITableViewCell!
var gitSSHPrivateKeyPassphrase: String?
var armorPrivateKey: String?
@ -22,32 +21,33 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
var message = ""
func reset() {
self.segments.removeAll()
segments.removeAll()
message = "LookingForStartingFrame.".localize()
}
func addSegment(segment: String) -> (accept: Bool, message: String) {
// Skip duplicated segments.
guard segment != self.segments.last else {
return (accept: false, message: self.message)
guard segment != segments.last else {
return (accept: false, message: message)
}
// Check whether we have found the first block.
guard !self.segments.isEmpty || segment.contains("-----BEGIN") else {
return (accept: false, message: self.message)
guard !segments.isEmpty || segment.contains("-----BEGIN") else {
return (accept: false, message: message)
}
// Update the list of scanned segment and return.
self.segments.append(segment)
segments.append(segment)
if segment.range(of: "-----END.*KEY-----", options: .regularExpression, range: nil, locale: nil) != nil {
self.message = "Done".localize()
return (accept: true, message: self.message)
message = "Done".localize()
return (accept: true, message: message)
} else {
self.message = "ScannedQrCodes(%d)".localize(self.segments.count)
return (accept: false, message: self.message)
message = "ScannedQrCodes(%d)".localize(segments.count)
return (accept: false, message: message)
}
}
}
var scanned = ScannedSSHKey()
override func viewDidLoad() {
@ -59,12 +59,13 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
}
@IBAction func doneButtonTapped(_ sender: Any) {
@IBAction
func doneButtonTapped(_: Any) {
armorPrivateKey = armorPrivateKeyTextView.text
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
if text == UIPasteboard.general.string {
// user pastes something, do the copy here again and clear the pasteboard in 45s
SecurePasteboard.shared.copy(textToCopy: text)
@ -76,23 +77,24 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
let selectedCell = tableView.cellForRow(at: indexPath)
if selectedCell == scanPrivateKeyCell {
scanned.reset()
self.performSegue(withIdentifier: "showSSHScannerSegue", sender: self)
performSegue(withIdentifier: "showSSHScannerSegue", sender: self)
}
tableView.deselectRow(at: indexPath, animated: true)
}
// MARK: - QRScannerControllerDelegate Methods
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
return scanned.addSegment(segment: line)
}
// MARK: - QRScannerControllerDelegate Methods
func handleScannedOutput(line: String) {
func handleScannedOutput(line _: String) {
armorPrivateKeyTextView.text = scanned.segments.joined(separator: "")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
if segue.identifier == "showSSHScannerSegue" {
if let navController = segue.destination as? UINavigationController {
if let viewController = navController.topViewController as? QRScannerController {
@ -104,13 +106,11 @@ 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()

View file

@ -10,12 +10,12 @@ import passKit
import SVProgressHUD
class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet var sshPrivateKeyFile: UITableViewCell!
@IBOutlet weak var sshPrivateKeyFile: UITableViewCell!
private var privateKey: String?
private var privateKey: String? = nil
@IBAction func doneButtonTapped(_ sender: Any) {
@IBAction
func doneButtonTapped(_: Any) {
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
@ -35,7 +35,6 @@ class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController {
}
extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) {
guard let url = url.first else {
return
@ -61,7 +60,6 @@ extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
}
extension SSHKeyFileImportTableViewController: KeyImporter {
static let keySource = KeySource.file
static let label = "LoadFromFiles".localize()

View file

@ -6,12 +6,11 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import SVProgressHUD
import passKit
import SVProgressHUD
class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var privateKeyURLTextField: UITextField!
@IBOutlet var privateKeyURLTextField: UITextField!
var sshPrivateKeyURL: URL?
@ -20,11 +19,12 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
privateKeyURLTextField.text = Defaults.gitSSHPrivateKeyURL?.absoluteString
}
@IBAction func doneButtonTapped(_ sender: UIButton) {
@IBAction
func doneButtonTapped(_: UIButton) {
guard let text = privateKeyURLTextField.text,
let privateKeyURL = URL(string: text) else {
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
return
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
return
}
if privateKeyURL.scheme?.lowercased() == "http" {
@ -41,7 +41,6 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
}
extension SSHKeyUrlImportTableViewController: KeyImporter {
static let keySource = KeySource.url
static let label = "DownloadFromUrl".localize()

View file

@ -10,15 +10,16 @@ import UIKit
class SettingsSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
self.delegate = self
self.preferredDisplayMode = .allVisible
delegate = self
preferredDisplayMode = .allVisible
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
_: UISplitViewController,
collapseSecondary _: UIViewController,
onto _: UIViewController
) -> Bool {
// Return true to prevent UIKit from applying its default behavior
return true
true
}
}

View file

@ -6,26 +6,27 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
import SVProgressHUD
import CoreData
import passKit
import SVProgressHUD
import UIKit
class SettingsTableViewController: UITableViewController, UITabBarControllerDelegate {
@IBOutlet weak var pgpKeyTableViewCell: UITableViewCell!
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
@IBOutlet var pgpKeyTableViewCell: UITableViewCell!
@IBOutlet var passcodeTableViewCell: UITableViewCell!
@IBOutlet var passwordRepositoryTableViewCell: UITableViewCell!
var setPasscodeLockAlert: UIAlertController?
let passwordStore = PasswordStore.shared
let keychain = AppKeychain.shared
var passcodeLock = PasscodeLock.shared
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
func tabBarController(_: UITabBarController, didSelect _: UIViewController) {
navigationController?.popViewController(animated: true)
}
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
@IBAction
func savePGPKey(segue: UIStoryboardSegue) {
guard let sourceController = segue.source as? PGPKeyImporter, sourceController.isReadyToUse() else {
return
}
@ -58,19 +59,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
}
}
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
@IBAction
func saveGitServerSetting(segue _: UIStoryboardSegue) {
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
setPGPKeyTableViewCellDetailText()
setPasscodeLockCell()
}
override func viewWillAppear(_ animated: Bool) {
override func viewWillAppear(_: Bool) {
super.viewWillAppear(true)
tabBarController!.delegate = self
setPasswordRepositoryTableViewCellDetailText()
@ -78,9 +80,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
private func setPasscodeLockCell() {
if passcodeLock.hasPasscode {
self.passcodeTableViewCell.detailTextLabel?.text = "On".localize()
passcodeTableViewCell.detailTextLabel?.text = "On".localize()
} else {
self.passcodeTableViewCell.detailTextLabel?.text = "Off".localize()
passcodeTableViewCell.detailTextLabel?.text = "Off".localize()
}
}
@ -107,7 +109,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
passwordRepositoryTableViewCell.detailTextLabel?.text = host
}
@objc func actOnPasswordStoreErasedNotification() {
@objc
func actOnPasswordStoreErasedNotification() {
setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText()
setPasscodeLockCell()
@ -180,9 +183,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let passcodeRemoveViewController = PasscodeLockViewController()
let removePasscodeAction = UIAlertAction(title: "RemovePasscode".localize(), style: .destructive) { [weak self] _ in
passcodeRemoveViewController.successCallback = {
passcodeRemoveViewController.successCallback = {
self?.passcodeLock.delete()
self?.setPasscodeLockCell()
}
@ -198,10 +200,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
optionMenu.addAction(UIAlertAction.cancel())
optionMenu.popoverPresentationController?.sourceView = passcodeTableViewCell
optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds
self.present(optionMenu, animated: true, completion: nil)
present(optionMenu, animated: true, completion: nil)
}
@objc func alertTextFieldDidChange(_ sender: UITextField) {
@objc
func alertTextFieldDidChange(_ sender: UITextField) {
// check whether we should enable the Save button in setPasscodeLockAlert
if let setPasscodeLockAlert = self.setPasscodeLockAlert,
let setPasscodeLockAlertTextFields0 = setPasscodeLockAlert.textFields?[0],
@ -218,25 +221,25 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
func setPasscodeLock() {
// prepare the alert for setting the passcode
setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert)
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in
textField.placeholder = "Passcode".localize()
textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
})
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in
textField.placeholder = "PasswordConfirmation".localize()
textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
})
// save action
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (action:UIAlertAction) -> Void in
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (_: UIAlertAction) -> Void in
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
self.passcodeLock.save(passcode: passcode)
// refresh the passcode lock cell ("On")
self.setPasscodeLockCell()
}
saveAction.isEnabled = false // disable the Save button by default
saveAction.isEnabled = false // disable the Save button by default
// cancel action
let cancelAction = UIAlertAction.cancel()
@ -244,17 +247,16 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
// present
setPasscodeLockAlert?.addAction(saveAction)
setPasscodeLockAlert?.addAction(cancelAction)
self.present(setPasscodeLockAlert!, animated: true, completion: nil)
present(setPasscodeLockAlert!, animated: true, completion: nil)
}
}
extension SettingsTableViewController: PGPKeyImporter {
static let keySource = KeySource.itunes
static let label = "ITunesFileSharing".localize()
func isReadyToUse() -> Bool {
return KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist()
KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist()
}
func importKeys() throws {

View file

@ -18,7 +18,7 @@ class SpecialThanksTableViewController: BasicStaticTableViewController {
"https://icons8.com"],
["FlatIcon",
"https://www.flaticon.com"],
]
]
override func viewDidLoad() {
tableData.append([])