From ed387069a41b3f8cd2344d623d9076533a612aa4 Mon Sep 17 00:00:00 2001 From: Mingshen Sun Date: Sun, 9 Dec 2018 16:59:07 -0800 Subject: [PATCH] lint: delete trailing whitespaces --- README.md | 2 +- _config.yml | 3 +- pass/AppDelegate.swift | 24 +-- .../AboutRepositoryTableViewController.swift | 18 +- .../AboutTableViewController.swift | 8 +- .../AddPasswordTableViewController.swift | 6 +- .../AdvancedSettingsTableViewController.swift | 10 +- .../BasicStaticTableViewController.swift | 24 +-- .../CommitLogsTableViewController.swift | 10 +- .../EditPasswordTableViewController.swift | 4 +- .../GeneralSettingsTableViewController.swift | 40 ++--- .../GitConfigSettingTableViewController.swift | 8 +- ...SHKeyArmorSettingTableViewController.swift | 38 ++-- .../GitServerSettingTableViewController.swift | 36 ++-- ...nSourceComponentsTableViewController.swift | 4 +- ...GPKeyArmorSettingTableViewController.swift | 32 ++-- .../PGPKeySettingTableViewController.swift | 10 +- .../PasswordDetailTableViewController.swift | 94 +++++----- .../PasswordEditorTableViewController.swift | 80 ++++----- .../Controllers/PasswordsViewController.swift | 108 ++++++------ pass/Controllers/QRScannerController.swift | 52 +++--- .../RawPasswordViewController.swift | 2 +- .../SSHKeySettingTableViewController.swift | 10 +- .../SettingsSplitViewController.swift | 2 +- .../SettingsTableViewController.swift | 56 +++--- .../SpecialThanksTableViewController.swift | 2 +- pass/Helpers/SecurePasteboard.swift | 12 +- pass/Views/ContentTableViewCell.swift | 4 +- pass/Views/FillPasswordTableViewCell.swift | 16 +- pass/Views/LabelTableViewCell.swift | 28 +-- .../PasswordDetailTitleTableViewCell.swift | 2 +- pass/Views/SliderTableViewCell.swift | 14 +- pass/Views/TextFieldTableViewCell.swift | 6 +- pass/Views/TextViewTableViewCell.swift | 4 +- pass/Views/TitleTextFieldTableViewCell.swift | 6 +- .../CredentialProviderViewController.swift | 42 ++--- .../PasscodeExtensionDisplay.swift | 6 +- passExtension/ExtensionViewController.swift | 48 ++--- .../OnePasswordExtensionConstants.swift | 2 +- passExtension/PasscodeExtensionDisplay.swift | 6 +- passExtension/passProcessor.js | 4 +- .../Controllers/PasscodeLockPresenter.swift | 8 +- .../PasscodeLockViewController.swift | 42 ++--- passKit/Helpers/DefaultsKeys.swift | 10 +- passKit/Helpers/FileManagerExtension.swift | 34 ++-- passKit/Helpers/Globals.swift | 16 +- passKit/Helpers/NotificationNames.swift | 2 +- passKit/Helpers/UIViewExtension.swift | 8 +- passKit/Helpers/Utils.swift | 8 +- passKit/Models/GitCredential.swift | 10 +- passKit/Models/PasscodeLock.swift | 10 +- passKit/Models/Password.swift | 18 +- passKit/Models/PasswordEntity.swift | 8 +- passKit/Models/PasswordStore.swift | 164 +++++++++--------- passKit/Parser/AdditionField.swift | 2 +- passKit/Parser/OtpType.swift | 2 +- passKitTests/Models/PasswordTest.swift | 2 +- passKitTests/passKitTests.swift | 10 +- passTests/passTests.swift | 10 +- 59 files changed, 624 insertions(+), 623 deletions(-) diff --git a/README.md b/README.md index f800716..d9e6922 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + # Pass [![GitHub release](https://img.shields.io/github/release/mssun/passforios.svg)](https://github.com/mssun/passforios/releases) diff --git a/_config.yml b/_config.yml index 2f7efbe..f6129eb 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1,2 @@ -theme: jekyll-theme-minimal \ No newline at end of file +theme: jekyll-theme-minimal + diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift index ce0d190..c12fd6e 100644 --- a/pass/AppDelegate.swift +++ b/pass/AppDelegate.swift @@ -23,7 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let presenter = PasscodeLockPresenter(mainWindow: self.window) return presenter }() - + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100)) @@ -35,18 +35,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } return true } - + func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if let _ = window?.rootViewController as? PasscodeLockViewController { window?.frame = UIScreen.main.bounds } return .all } - + @objc func postSearchNotification() { NotificationCenter.default.post(name: .passwordSearch, object: nil) } - + func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { if shortcutItem.type == Globals.bundleIdentifier + ".search" { let tabBarController = self.window!.rootViewController as! UITabBarController @@ -60,7 +60,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - + // Display a blur effect view let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light) let blurEffectView = UIVisualEffectView(effect: blurEffect) @@ -68,7 +68,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { blurEffectView.tag = ViewTag.blur.rawValue blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.window?.addSubview(blurEffectView) - + // Display the Pass icon in the middle of the screen let iconsDictionary = Bundle.main.infoDictionary?["CFBundleIcons"] as? NSDictionary let primaryIconsDictionary = iconsDictionary?["CFBundlePrimaryIcon"] as? NSDictionary @@ -85,7 +85,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - + } func applicationWillEnterForeground(_ application: UIApplication) { @@ -95,7 +95,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - + self.window?.viewWithTag(ViewTag.appicon.rawValue)?.removeFromSuperview() self.window?.viewWithTag(ViewTag.blur.rawValue)?.removeFromSuperview() } @@ -107,7 +107,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } // MARK: - Core Data stack - + lazy var persistentContainer: NSPersistentContainer = { /* The persistent container for the application. This implementation @@ -126,7 +126,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - + /* Typical reasons for an error here include: * The parent directory does not exist, cannot be created, or disallows writing. @@ -140,9 +140,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { }) return container }() - + // MARK: - Core Data Saving support - + func saveContext () { let context = persistentContainer.viewContext if context.hasChanges { diff --git a/pass/Controllers/AboutRepositoryTableViewController.swift b/pass/Controllers/AboutRepositoryTableViewController.swift index 69b7ae4..04736f5 100644 --- a/pass/Controllers/AboutRepositoryTableViewController.swift +++ b/pass/Controllers/AboutRepositoryTableViewController.swift @@ -10,7 +10,7 @@ import UIKit import passKit class AboutRepositoryTableViewController: BasicStaticTableViewController { - + private var needRefresh = false private var indicator: UIActivityIndicatorView = { let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) @@ -23,13 +23,13 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { indicator.center = CGPoint(x: view.bounds.midX, y: view.bounds.height * 0.382) tableView.addSubview(indicator) - + setTableData() - + // all password store updates (including erase, discard) will trigger the refresh NotificationCenter.default.addObserver(self, selector: #selector(setNeedRefresh), name: .passwordStoreUpdated, object: nil) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if needRefresh { @@ -37,14 +37,14 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { needRefresh = false } } - + private func setTableData() { - + // clear current contents (if any) self.tableData.removeAll(keepingCapacity: true) self.tableView.reloadData() indicator.startAnimating() - + // reload the table DispatchQueue.global(qos: .userInitiated).async { let passwords = self.numberOfPasswordsString() @@ -52,7 +52,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { let localCommits = self.numberOfLocalCommitsString() let lastSynced = self.lastSyncedTimeString() let commits = self.numberOfPasswordsString() - + DispatchQueue.main.async { [weak self] in guard let strongSelf = self else { return @@ -97,7 +97,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { formatter.timeStyle = .short return formatter.string(from: date) } - + @objc func setNeedRefresh() { needRefresh = true } diff --git a/pass/Controllers/AboutTableViewController.swift b/pass/Controllers/AboutTableViewController.swift index 5bc6989..91348c9 100644 --- a/pass/Controllers/AboutTableViewController.swift +++ b/pass/Controllers/AboutTableViewController.swift @@ -9,21 +9,21 @@ import UIKit class AboutTableViewController: BasicStaticTableViewController { - + override func viewDidLoad() { tableData = [ // section 0 [[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"], [.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"], [.title: "Contact Developer", .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],], - + // section 1, [[.title: "Open Source Components", .action: "segue", .link: "showOpenSourceComponentsSegue"], [.title: "Special Thanks", .action: "segue", .link: "showSpecialThanksSegue"],], ] super.viewDidLoad() } - + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { if section == tableData.count - 1 { let view = UIView() @@ -38,7 +38,7 @@ class AboutTableViewController: BasicStaticTableViewController { } return nil } - + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { if section == 1 { return "Acknowledgements".uppercased() diff --git a/pass/Controllers/AddPasswordTableViewController.swift b/pass/Controllers/AddPasswordTableViewController.swift index 924e5bd..afaa904 100644 --- a/pass/Controllers/AddPasswordTableViewController.swift +++ b/pass/Controllers/AddPasswordTableViewController.swift @@ -27,7 +27,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { tableData[0][0][PasswordEditorCellKey.content] = defaultDirPrefix super.viewDidLoad() } - + override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "saveAddPasswordSegue" { // check PGP key @@ -37,7 +37,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) return false } - + // check name guard checkName() == true else { return false @@ -45,7 +45,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { } return true } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if segue.identifier == "saveAddPasswordSegue" { diff --git a/pass/Controllers/AdvancedSettingsTableViewController.swift b/pass/Controllers/AdvancedSettingsTableViewController.swift index b150e96..4982034 100644 --- a/pass/Controllers/AdvancedSettingsTableViewController.swift +++ b/pass/Controllers/AdvancedSettingsTableViewController.swift @@ -17,7 +17,7 @@ class AdvancedSettingsTableViewController: UITableViewController { @IBOutlet weak var eraseDataTableViewCell: UITableViewCell! @IBOutlet weak var discardChangesTableViewCell: UITableViewCell! let passwordStore = PasswordStore.shared - + let encryptInASCIIArmoredSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -33,7 +33,7 @@ class AdvancedSettingsTableViewController: UITableViewController { encryptInASCIIArmoredTableViewCell.selectionStyle = .none setGitSignatureText() } - + private func setGitSignatureText() { let gitSignatureName = passwordStore.gitSignatureForNow.name! let gitSignatureEmail = passwordStore.gitSignatureForNow.email! @@ -77,17 +77,17 @@ class AdvancedSettingsTableViewController: UITableViewController { } catch { Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil) } - + })) alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil)) self.present(alert, animated: true, completion: nil) } } - + @objc func encryptInASCIIArmoredAction(_ sender: Any?) { SharedDefaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn } - + @IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) { if let controller = segue.source as? GitConfigSettingTableViewController { if let gitSignatureName = controller.nameTextField.text, diff --git a/pass/Controllers/BasicStaticTableViewController.swift b/pass/Controllers/BasicStaticTableViewController.swift index 86512fc..cf24efc 100644 --- a/pass/Controllers/BasicStaticTableViewController.swift +++ b/pass/Controllers/BasicStaticTableViewController.swift @@ -27,18 +27,18 @@ enum CellDataKey { class BasicStaticTableViewController: UITableViewController, MFMailComposeViewControllerDelegate { var tableData = [[Dictionary]]() var navigationItemTitle: String? - + override func viewDidLoad() { super.viewDidLoad() if navigationItemTitle != nil { navigationItem.title = navigationItemTitle } } - + override func numberOfSections(in tableView: UITableView) -> Int { return tableData.count } - + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return tableData[section].count } @@ -47,13 +47,13 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let cellData = tableData[indexPath.section][indexPath.row] let cellDataStyle = cellData[CellDataKey.style] as? CellDataStyle var cell: UITableViewCell? - + switch cellDataStyle ?? .defaultStyle { case .value1: cell = UITableViewCell(style: .value1, reuseIdentifier: "value1 cell") @@ -61,7 +61,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo default: cell = UITableViewCell(style: .default, reuseIdentifier: "default cell") } - + if let detailText = cellData[CellDataKey.detailText] as? String { cell?.detailTextLabel?.text = detailText } @@ -71,17 +71,17 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo cell?.accessoryType = .disclosureIndicator cell?.selectionStyle = .default } - + cell?.textLabel?.text = cellData[CellDataKey.title] as? String return cell ?? UITableViewCell() } - + override func tableView(_ 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]) } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let cellData = tableData[indexPath.section][indexPath.row] @@ -116,7 +116,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo break } } - + func sendEmail(toRecipients recipients: [String], subject: String) { let mailVC = MFMailComposeViewController() mailVC.mailComposeDelegate = self @@ -125,7 +125,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo mailVC.setMessageBody("", isHTML: false) self.present(mailVC, animated: true, completion: nil) } - + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { controller.dismiss(animated: true) } diff --git a/pass/Controllers/CommitLogsTableViewController.swift b/pass/Controllers/CommitLogsTableViewController.swift index 1bcbc7b..110282a 100644 --- a/pass/Controllers/CommitLogsTableViewController.swift +++ b/pass/Controllers/CommitLogsTableViewController.swift @@ -13,7 +13,7 @@ import passKit class CommitLogsTableViewController: UITableViewController { var commits: [GTCommit] = [] let passwordStore = PasswordStore.shared - + override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil) @@ -25,14 +25,14 @@ class CommitLogsTableViewController: UITableViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return commits.count } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "commitLogCell", for: indexPath) let formatter = DateFormatter() formatter.dateStyle = DateFormatter.Style.medium formatter.timeStyle = .medium let dateString = formatter.string(from: commits[indexPath.row].commitDate) - + let author = cell.contentView.viewWithTag(200) as? UILabel let dateLabel = cell.contentView.viewWithTag(201) as? UILabel let messageLabel = cell.contentView.viewWithTag(202) as? UILabel @@ -41,12 +41,12 @@ class CommitLogsTableViewController: UITableViewController { messageLabel?.text = commits[indexPath.row].message?.trimmed return cell } - + @objc func updateCommitLogs() { commits = getCommitLogs() tableView.reloadData() } - + private func getCommitLogs() -> [GTCommit] { do { return try passwordStore.getRecentCommits(count: 20) diff --git a/pass/Controllers/EditPasswordTableViewController.swift b/pass/Controllers/EditPasswordTableViewController.swift index 35ef7e9..ab58251 100644 --- a/pass/Controllers/EditPasswordTableViewController.swift +++ b/pass/Controllers/EditPasswordTableViewController.swift @@ -24,7 +24,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController { tableData[1].append([.type: PasswordEditorCellType.memorablePasswordGeneratorCell]) super.viewDidLoad() } - + override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "saveEditPasswordSegue" { // check name @@ -34,7 +34,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController { } return true } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if segue.identifier == "saveEditPasswordSegue" { diff --git a/pass/Controllers/GeneralSettingsTableViewController.swift b/pass/Controllers/GeneralSettingsTableViewController.swift index c978a1c..697e0cd 100644 --- a/pass/Controllers/GeneralSettingsTableViewController.swift +++ b/pass/Controllers/GeneralSettingsTableViewController.swift @@ -19,7 +19,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { uiSwitch.addTarget(self, action: #selector(hideUnknownSwitchAction(_:)), for: UIControlEvents.valueChanged) return uiSwitch }() - + let hideOTPSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -27,7 +27,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { uiSwitch.addTarget(self, action: #selector(hideOTPSwitchAction(_:)), for: UIControlEvents.valueChanged) return uiSwitch }() - + let rememberPGPPassphraseSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -36,7 +36,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { uiSwitch.isOn = SharedDefaults[.isRememberPGPPassphraseOn] return uiSwitch }() - + let rememberGitCredentialPassphraseSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -45,7 +45,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { uiSwitch.isOn = SharedDefaults[.isRememberGitCredentialPassphraseOn] return uiSwitch }() - + let showFolderSwitch: UISwitch = { let uiSwitch = UISwitch() uiSwitch.onTintColor = Globals.blue @@ -59,12 +59,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { tableData = [ // section 0 [[.title: "About Repository", .action: "segue", .link: "showAboutRepositorySegue"],], - + // section 1 [ [.title: "Password Generator Flavor", .action: "none", .style: CellDataStyle.value1], ], - + // section 2 [ [.title: "Remember PGP Key Passphrase", .action: "none",], @@ -78,9 +78,9 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { ] super.viewDidLoad() - + } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = super.tableView(tableView, cellForRowAt: indexPath) switch cell.textLabel!.text! { @@ -127,7 +127,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { } return cell } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { super.tableView(tableView, didSelectRowAt: indexPath) let cell = tableView.cellForRow(at: indexPath)! @@ -136,7 +136,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { showPasswordGeneratorFlavorActionSheet(sourceCell: cell) } } - + func showPasswordGeneratorFlavorActionSheet(sourceCell: UITableViewCell) { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) var randomFlavorActionTitle = "" @@ -152,12 +152,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { SharedDefaults[.passwordGeneratorFlavor] = "Random" sourceCell.detailTextLabel?.text = "Random" } - + let appleFlavorAction = UIAlertAction(title: appleFlavorActionTitle, style: .default) { _ in SharedDefaults[.passwordGeneratorFlavor] = "Apple" sourceCell.detailTextLabel?.text = "Apple" } - + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) optionMenu.addAction(randomFlavorAction) optionMenu.addAction(appleFlavorAction) @@ -166,37 +166,37 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { optionMenu.popoverPresentationController?.sourceRect = sourceCell.bounds self.present(optionMenu, animated: true, completion: nil) } - + @objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) { let alertMessage = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields." let alertTitle = "Hide Unknown Fields" Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } - + @objc func tapHideOTPSwitchDetailButton(_ sender: Any?) { let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ",") let alertMessage = "Turn on this switch to hide the fields related to one time passwords (i.e., \(keywordsString))." let alertTitle = "Hide One Time Password Fields" Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } - + @objc func hideUnknownSwitchAction(_ sender: Any?) { SharedDefaults[.isHideUnknownOn] = hideUnknownSwitch.isOn NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil) } - + @objc func hideOTPSwitchAction(_ sender: Any?) { SharedDefaults[.isHideOTPOn] = hideOTPSwitch.isOn NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil) } - + @objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) { SharedDefaults[.isRememberPGPPassphraseOn] = rememberPGPPassphraseSwitch.isOn if rememberPGPPassphraseSwitch.isOn == false { passwordStore.pgpKeyPassphrase = nil } } - + @objc func rememberGitCredentialPassphraseSwitchAction(_ sender: Any?) { SharedDefaults[.isRememberGitCredentialPassphraseOn] = rememberGitCredentialPassphraseSwitch.isOn if rememberGitCredentialPassphraseSwitch.isOn == false { @@ -204,10 +204,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { passwordStore.gitPassword = nil } } - + @objc func showFolderSwitchAction(_ sender: Any?) { SharedDefaults[.isShowFolderOn] = showFolderSwitch.isOn NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil) } - + } diff --git a/pass/Controllers/GitConfigSettingTableViewController.swift b/pass/Controllers/GitConfigSettingTableViewController.swift index f0d0d5a..a0e79d0 100644 --- a/pass/Controllers/GitConfigSettingTableViewController.swift +++ b/pass/Controllers/GitConfigSettingTableViewController.swift @@ -12,21 +12,21 @@ import passKit class GitConfigSettingTableViewController: UITableViewController { let passwordStore = PasswordStore.shared - + @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var emailTextField: UITextField! - + override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableViewAutomaticDimension - + let signature = passwordStore.gitSignatureForNow nameTextField.placeholder = signature.name emailTextField.placeholder = signature.email nameTextField.text = SharedDefaults[.gitSignatureName] emailTextField.text = SharedDefaults[.gitSignatureEmail] } - + override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "saveGitConfigSettingSegue" { let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text! diff --git a/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift b/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift index fb82f5f..803e9c5 100644 --- a/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift +++ b/pass/Controllers/GitSSHKeyArmorSettingTableViewController.swift @@ -12,10 +12,10 @@ import passKit class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate { @IBOutlet weak var armorPrivateKeyTextView: UITextView! @IBOutlet weak var scanPrivateKeyCell: UITableViewCell! - + var gitSSHPrivateKeyPassphrase: String? let passwordStore = PasswordStore.shared - + class ScannedSSHKey { static let maxNumberOfGif = 100 var numberOfSegments = 0 @@ -24,7 +24,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie var message = "" var hasStarted = false var isDone = false - + func reset() { numberOfSegments = 0 previousSegment = "" @@ -33,14 +33,14 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie hasStarted = false isDone = false } - + func addSegment(segment: String) { // skip duplicated segments guard segment != previousSegment else { return } previousSegment = segment - + // check whether we have found the first block if hasStarted == false { hasStarted = segment.contains("-----BEGIN") @@ -48,38 +48,38 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie guard hasStarted == true else { return } - + // check the number of segments numberOfSegments = numberOfSegments + 1 guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else { key = "Too many QR codes" return } - + // update full text and check whether we are done key.append(segment) if let index1 = key.range(of: "-----END")?.lowerBound, let _ = key.suffix(from: index1).range(of: "KEY-----")?.lowerBound { isDone = true } - + // update message message = "\(numberOfSegments) scanned QR codes." } } var scanned = ScannedSSHKey() - + override func viewDidLoad() { super.viewDidLoad() armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor] armorPrivateKeyTextView.delegate = self - + scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes" scanPrivateKeyCell?.textLabel?.textColor = Globals.blue scanPrivateKeyCell?.selectionStyle = .default scanPrivateKeyCell?.accessoryType = .disclosureIndicator } - + @IBAction func doneButtonTapped(_ sender: Any) { SharedDefaults[.gitSSHPrivateKeyArmor] = armorPrivateKeyTextView.text do { @@ -90,7 +90,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie SharedDefaults[.gitSSHKeySource] = "armor" self.navigationController!.popViewController(animated: true) } - + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if text == UIPasteboard.general.string { // user pastes something, do the copy here again and clear the pasteboard in 45s @@ -98,7 +98,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie } return true } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPrivateKeyCell { @@ -107,8 +107,8 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie } tableView.deselectRow(at: indexPath, animated: true) } - - + + // MARK: - QRScannerControllerDelegate Methods func checkScannedOutput(line: String) -> (accept: Bool, message: String) { scanned.addSegment(segment: line) @@ -118,12 +118,12 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie return (accept: false, message: scanned.message) } } - + // MARK: - QRScannerControllerDelegate Methods func handleScannedOutput(line: String) { armorPrivateKeyTextView.text = scanned.key } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showSSHScannerSegue" { if let navController = segue.destination as? UINavigationController { @@ -135,9 +135,9 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie } } } - + @IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) { - + } } diff --git a/pass/Controllers/GitServerSettingTableViewController.swift b/pass/Controllers/GitServerSettingTableViewController.swift index 3ccaf46..7c322b4 100644 --- a/pass/Controllers/GitServerSettingTableViewController.swift +++ b/pass/Controllers/GitServerSettingTableViewController.swift @@ -37,7 +37,7 @@ class GitServerSettingTableViewController: UITableViewController { sshKeyCheckView.isHidden = true } } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Grey out ssh option if ssh_key is not present @@ -55,30 +55,30 @@ class GitServerSettingTableViewController: UITableViewController { checkAuthenticationMethod(method: authenticationMethod) authSSHKeyCell.accessoryType = .detailButton } - + override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) if cell == authSSHKeyCell { showSSHKeyActionSheet() } } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) view.endEditing(true) } - + private func cloneAndSegueIfSuccess() { // try to clone let gitRepostiroyURL = gitURLTextField.text!.trimmed let username = usernameTextField.text! let auth = authenticationMethod - + SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) SVProgressHUD.show(withStatus: "Prepare Repository") @@ -160,15 +160,15 @@ class GitServerSettingTableViewController: UITableViewController { checkAuthenticationMethod(method: authenticationMethod) tableView.deselectRow(at: indexPath, animated: true) } - + @IBAction func save(_ sender: Any) { - + // some sanity checks guard let gitURL = URL(string: gitURLTextField.text!) else { Utils.alert(title: "Cannot Save", message: "Please set the Git repository URL.", controller: self, completion: nil) return } - + switch gitURL.scheme { case let val where val == "https": break @@ -188,7 +188,7 @@ class GitServerSettingTableViewController: UITableViewController { Utils.alert(title: "Cannot Save", message: "Please specify the scheme of the Git repository URL (https or ssh).", controller: self, completion: nil) return } - + if passwordStore.repositoryExisted() { let alert = UIAlertController(title: "Overwrite?", message: "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "Overwrite", style: UIAlertActionStyle.destructive, handler: { _ in @@ -202,13 +202,13 @@ class GitServerSettingTableViewController: UITableViewController { cloneAndSegueIfSuccess() } } - + func showSSHKeyActionSheet() { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) var urlActionTitle = "Download from URL" var armorActionTitle = "ASCII-Armor Encrypted Key" var fileActionTitle = "iTunes File Sharing" - + if SharedDefaults[.gitSSHKeySource] == "url" { urlActionTitle = "✓ \(urlActionTitle)" } else if SharedDefaults[.gitSSHKeySource] == "armor" { @@ -225,7 +225,7 @@ class GitServerSettingTableViewController: UITableViewController { let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) optionMenu.addAction(urlAction) optionMenu.addAction(armorAction) - + if passwordStore.gitSSHKeyExists(inFileSharing: true) { // might keys updated via iTunes, or downloaded/pasted inside the app fileActionTitle.append(" (Import)") @@ -249,7 +249,7 @@ class GitServerSettingTableViewController: UITableViewController { } optionMenu.addAction(fileAction) } - + if SharedDefaults[.gitSSHKeySource] != nil { let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in self.passwordStore.removeGitSSHKeys() @@ -266,7 +266,7 @@ class GitServerSettingTableViewController: UITableViewController { optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds self.present(optionMenu, animated: true, completion: nil) } - + private func requestGitPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? { let sem = DispatchSemaphore(value: 0) var password: String? @@ -277,7 +277,7 @@ class GitServerSettingTableViewController: UITableViewController { case .ssh: message = "Please fill in the passphrase of your SSH key." } - + DispatchQueue.main.async { SVProgressHUD.dismiss() let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert) @@ -295,7 +295,7 @@ class GitServerSettingTableViewController: UITableViewController { }) self.present(alert, animated: true, completion: nil) } - + let _ = sem.wait(timeout: .distantFuture) return password } diff --git a/pass/Controllers/OpenSourceComponentsTableViewController.swift b/pass/Controllers/OpenSourceComponentsTableViewController.swift index d60af7d..0134926 100644 --- a/pass/Controllers/OpenSourceComponentsTableViewController.swift +++ b/pass/Controllers/OpenSourceComponentsTableViewController.swift @@ -33,7 +33,7 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController { "https://github.com/SVProgressHUD/SVProgressHUD", "https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE.txt"], ] - + override func viewDidLoad() { tableData.append([]) for item in openSourceComponents { @@ -43,7 +43,7 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController { } super.viewDidLoad() } - + @objc func actOnDetailDisclosureButton(_ sender: Any?) { if let link = sender as? String { let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false) diff --git a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift index 923e85f..22bcf32 100644 --- a/pass/Controllers/PGPKeyArmorSettingTableViewController.swift +++ b/pass/Controllers/PGPKeyArmorSettingTableViewController.swift @@ -14,10 +14,10 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe @IBOutlet weak var armorPrivateKeyTextView: UITextView! @IBOutlet weak var scanPublicKeyCell: UITableViewCell! @IBOutlet weak var scanPrivateKeyCell: UITableViewCell! - + var pgpPassphrase: String? let passwordStore = PasswordStore.shared - + class ScannedPGPKey { static let maxNumberOfGif = 100 enum KeyType { @@ -30,7 +30,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe var message = "" var hasStarted = false var isDone = false - + func reset(keytype: KeyType) { self.keyType = keytype numberOfSegments = 0 @@ -40,14 +40,14 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe hasStarted = false isDone = false } - + func addSegment(segment: String) { // skip duplicated segments guard segment != previousSegment else { return } previousSegment = segment - + // check whether we have found the first block if hasStarted == false { let findPublic = segment.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----") @@ -68,32 +68,32 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe guard hasStarted == true else { return } - + // check the number of segments numberOfSegments = numberOfSegments + 1 guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else { key = "Too many QR codes" return } - + // update full text and check whether we are done key.append(segment) if key.contains("-----END PGP PUBLIC KEY BLOCK-----") || key.contains("-----END PGP PRIVATE KEY BLOCK-----") { isDone = true } - + // update message message = "\(numberOfSegments) scanned QR codes." } } var scanned = ScannedPGPKey() - + override func viewDidLoad() { super.viewDidLoad() armorPublicKeyTextView.text = SharedDefaults[.pgpPublicKeyArmor] armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor] pgpPassphrase = passwordStore.pgpKeyPassphrase - + scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes" scanPublicKeyCell?.textLabel?.textColor = Globals.blue scanPublicKeyCell?.selectionStyle = .default @@ -104,7 +104,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe scanPrivateKeyCell?.selectionStyle = .default scanPrivateKeyCell?.accessoryType = .disclosureIndicator } - + @IBAction func save(_ sender: Any) { guard armorPublicKeyTextView.text.isEmpty == false else { Utils.alert(title: "Cannot Save", message: "Please set public key first.", controller: self, completion: nil) @@ -138,7 +138,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe }) self.present(savePassphraseAlert, animated: true, completion: nil) } - + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if text == UIPasteboard.general.string { // user pastes something, do the copy here again and clear the pasteboard in 45s @@ -146,7 +146,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe } return true } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPublicKeyCell { @@ -158,7 +158,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe } tableView.deselectRow(at: indexPath, animated: true) } - + // MARK: - QRScannerControllerDelegate Methods func checkScannedOutput(line: String) -> (accept: Bool, message: String) { scanned.addSegment(segment: line) @@ -168,7 +168,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe return (accept: false, message: scanned.message) } } - + // MARK: - QRScannerControllerDelegate Methods func handleScannedOutput(line: String) { switch scanned.keyType { @@ -178,7 +178,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe armorPrivateKeyTextView.text = scanned.key } } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showPGPScannerSegue" { if let navController = segue.destination as? UINavigationController { diff --git a/pass/Controllers/PGPKeySettingTableViewController.swift b/pass/Controllers/PGPKeySettingTableViewController.swift index dd43e30..2b01510 100644 --- a/pass/Controllers/PGPKeySettingTableViewController.swift +++ b/pass/Controllers/PGPKeySettingTableViewController.swift @@ -15,7 +15,7 @@ class PGPKeySettingTableViewController: UITableViewController { @IBOutlet weak var pgpPrivateKeyURLTextField: UITextField! var pgpPassphrase: String? let passwordStore = PasswordStore.shared - + override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableViewAutomaticDimension @@ -23,7 +23,7 @@ class PGPKeySettingTableViewController: UITableViewController { pgpPrivateKeyURLTextField.text = SharedDefaults[.pgpPrivateKeyURL]?.absoluteString pgpPassphrase = passwordStore.pgpKeyPassphrase } - + private func validatePGPKeyURL(input: String?) -> Bool { guard let path = input, let url = URL(string: path) else { Utils.alert(title: "Cannot Save PGP Key", message: "Please set PGP Key URL first.", controller: self, completion: nil) @@ -35,7 +35,7 @@ class PGPKeySettingTableViewController: UITableViewController { } return true } - + @IBAction func save(_ sender: Any) { guard validatePGPKeyURL(input: pgpPublicKeyURLTextField.text) == true, validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else { @@ -65,6 +65,6 @@ class PGPKeySettingTableViewController: UITableViewController { }) self.present(savePassphraseAlert, animated: true, completion: nil) } - - + + } diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift index 390b9f7..fcb5977 100644 --- a/pass/Controllers/PasswordDetailTableViewController.swift +++ b/pass/Controllers/PasswordDetailTableViewController.swift @@ -18,7 +18,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni private var oneTimePasswordIndexPath : IndexPath? private var shouldPopCurrentView = false private let passwordStore = PasswordStore.shared - + private lazy var editUIBarButtonItem: UIBarButtonItem = { let uiBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(pressEdit(_:))) return uiBarButtonItem @@ -31,18 +31,18 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni title = "" content = "" } - + init(title: String) { self.title = title self.content = "" } - + init(title: String, content: String) { self.title = title self.content = content } } - + private struct TableSection { var type: PasswordDetailTableViewControllerSectionType var header: String? @@ -52,56 +52,56 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni header = nil item = [TableCell]() } - + init(type: PasswordDetailTableViewControllerSectionType, header: String) { self.init(type: type) self.header = header } } - + private var tableData = Array() - + private enum PasswordDetailTableViewControllerSectionType { case name, main, addition, misc } - + override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "LabelTableViewCell", bundle: nil), forCellReuseIdentifier: "labelCell") tableView.register(UINib(nibName: "PasswordDetailTitleTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordDetailTitleTableViewCell") - + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(PasswordDetailTableViewController.tapMenu(recognizer:))) tapGesture.cancelsTouchesInView = false tableView.addGestureRecognizer(tapGesture) tapGesture.delegate = self - + tableView.contentInset = UIEdgeInsetsMake(-36, 0, 44, 0); tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 52 - + editUIBarButtonItem.isEnabled = false navigationItem.rightBarButtonItem = editUIBarButtonItem if #available(iOS 11.0, *) { navigationItem.largeTitleDisplayMode = .never } - + if let imageData = passwordEntity?.getImage() { let image = UIImage(data: imageData as Data) passwordImage = image } self.decryptThenShowPassword() self.setupOneTimePasswordAutoRefresh() - + // pop the current view because this password might be "discarded" NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil) - + // reset the data table if some password (maybe another one) has been updated NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordStoreUpdated, object: nil) - + // reset the data table if the disaply settings have been changed NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordDetailDisplaySettingChanged, object: nil) } - + override func viewDidAppear(_ animated: Bool) { super.viewWillAppear(animated) if self.shouldPopCurrentView { @@ -112,7 +112,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni self.present(alert, animated: true, completion: nil) } } - + private func requestPGPKeyPassphrase() -> String { let sem = DispatchSemaphore(value: 0) var passphrase = "" @@ -134,7 +134,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } return passphrase } - + @objc private func decryptThenShowPassword() { guard let passwordEntity = passwordEntity else { Utils.alert(title: "Cannot Show Password", message: "The password does not exist.", controller: self, handler: {(UIAlertAction) -> Void in @@ -166,7 +166,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni self.showPassword() } } - + private func showPassword() { DispatchQueue.main.async { [weak self] in self?.setTableData() @@ -179,7 +179,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } } - + private func setupOneTimePasswordAutoRefresh() { Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in @@ -204,19 +204,19 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } } - + @objc private func pressEdit(_ sender: Any?) { performSegue(withIdentifier: "editPasswordSegue", sender: self) } - + @objc private func setShouldPopCurrentView() { self.shouldPopCurrentView = true } - + @IBAction private func cancelEditPassword(segue: UIStoryboardSegue) { - + } - + @IBAction private func saveEditPassword(segue: UIStoryboardSegue) { if self.password!.changed != 0 { SVProgressHUD.show(withStatus: "Saving") @@ -231,7 +231,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni SVProgressHUD.dismiss(withDelay: 1) } } - + @IBAction private func deletePassword(segue: UIStoryboardSegue) { do { try passwordStore.delete(passwordEntity: passwordEntity!) @@ -243,7 +243,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni private func setTableData() { self.tableData = Array() - + // name section var section = TableSection(type: .name) section.item.append(TableCell()) @@ -261,9 +261,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni section.item.append(TableCell(title: "password", content: password.password)) tableData.append(section) - + // addition section - + // show one time password if password.otpType != .none { if let (title, otp) = self.password?.getOtpStrings() { @@ -273,7 +273,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1) } } - + // show additional information let filteredAdditionKeys = password.getFilteredAdditions() if filteredAdditionKeys.count > 0 { @@ -283,14 +283,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni }) tableData.append(section) } - + // misc section section = TableSection(type: .misc) section.item.append(TableCell(title: "Show Raw")) tableData.append(section) - + } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "editPasswordSegue" { if let controller = segue.destination as? UINavigationController { @@ -306,7 +306,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } } - + private func updatePasswordImage(urlString: String) { var newUrlString = urlString if urlString.lowercased().hasPrefix("http://") { @@ -321,7 +321,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // if a url does not start with http or https, try to add https newUrlString = "https://\(urlString)" } - + try? FavIcon.downloadPreferred(newUrlString) { [weak self] result in if case let .success(image) = result { let indexPath = IndexPath(row: 0, section: 0) @@ -334,7 +334,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } } - + @objc private func tapMenu(recognizer: UITapGestureRecognizer) { if recognizer.state == UIGestureRecognizerState.ended { let tapLocation = recognizer.location(in: self.tableView) @@ -353,17 +353,17 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } } - + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if touch.view!.isKind(of: UIButton.classForCoder()) { return false } return true } - + @IBAction func back(segue:UIStoryboardSegue) { } - + func getNextHOTP() { guard password != nil, passwordEntity != nil, password?.otpType == .hotp else { DispatchQueue.main.async { @@ -371,12 +371,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } return; } - + // copy HOTP to pasteboard (will update counter) if let plainPassword = password!.getNextHotp() { SecurePasteboard.shared.copy(textToCopy: plainPassword) } - + // commit the change of HOTP counter if password!.changed != 0 { do { @@ -465,11 +465,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni detailTextLabel.textColor = .gray detailTextLabel.text = "\(numberOfHiddenFields) hidden field\(numberOfHiddenFields > 1 ? "s" : "")" } - + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return tableData[section].header } - + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { if section == tableData.count - 1 { let view = UIView() @@ -484,13 +484,13 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } return nil } - + override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: 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 { let section = tableData[indexPath.section] switch(section.type) { @@ -500,11 +500,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni return false } } - + override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { return true } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let section = tableData[indexPath.section] if section.type == .misc { diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift index a7aa3b9..1c35821 100644 --- a/pass/Controllers/PasswordEditorTableViewController.swift +++ b/pass/Controllers/PasswordEditorTableViewController.swift @@ -20,21 +20,21 @@ enum PasswordEditorCellKey { } class PasswordEditorTableViewController: UITableViewController, FillPasswordTableViewCellDelegate, PasswordSettingSliderTableViewCellDelegate, QRScannerControllerDelegate, UITextFieldDelegate, UITextViewDelegate, SFSafariViewControllerDelegate { - + var tableData = [ [Dictionary] ]() var password: Password? - + private var navigationItemTitle: String? - + private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()} private var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""] private let nameSection = 0 private let passwordSection = 1 private let additionsSection = 2 private var hidePasswordSettings = true - + var nameCell: TextFieldTableViewCell? var fillPasswordCell: FillPasswordTableViewCell? private var passwordLengthCell: SliderTableViewCell? @@ -42,39 +42,39 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl private var deletePasswordCell: UITableViewCell? private var scanQRCodeCell: UITableViewCell? private var memorablePasswordGeneratorCell: UITableViewCell? - + override func loadView() { super.loadView() - + deletePasswordCell = UITableViewCell(style: .default, reuseIdentifier: "default") deletePasswordCell!.textLabel?.text = "Delete Password" deletePasswordCell!.textLabel?.textColor = Globals.red deletePasswordCell?.selectionStyle = .default - + scanQRCodeCell = UITableViewCell(style: .default, reuseIdentifier: "default") scanQRCodeCell?.textLabel?.text = "Add One-Time Password" scanQRCodeCell?.textLabel?.textColor = Globals.blue scanQRCodeCell?.selectionStyle = .default scanQRCodeCell?.accessoryType = .disclosureIndicator - + memorablePasswordGeneratorCell = UITableViewCell(style: .default, reuseIdentifier: "default") memorablePasswordGeneratorCell?.textLabel?.text = "Get a Memorable One: xkpasswd" memorablePasswordGeneratorCell?.textLabel?.textColor = Globals.blue memorablePasswordGeneratorCell?.selectionStyle = .default memorablePasswordGeneratorCell?.accessoryType = .disclosureIndicator } - + override func viewDidLoad() { super.viewDidLoad() if navigationItemTitle != nil { navigationItem.title = navigationItemTitle } - + tableView.register(UINib(nibName: "TextFieldTableViewCell", bundle: nil), forCellReuseIdentifier: "textFieldCell") tableView.register(UINib(nibName: "TextViewTableViewCell", bundle: nil), forCellReuseIdentifier: "textViewCell") tableView.register(UINib(nibName: "FillPasswordTableViewCell", bundle: nil), forCellReuseIdentifier: "fillPasswordCell") tableView.register(UINib(nibName: "SliderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordLengthCell") - + tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 48 self.tableView.sectionFooterHeight = UITableViewAutomaticDimension; @@ -83,10 +83,10 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl override func viewDidLayoutSubviews() { additionsCell?.contentTextView.setContentOffset(.zero, animated: false) } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cellData = tableData[indexPath.section][indexPath.row] - + switch cellData[PasswordEditorCellKey.type] as! PasswordEditorCellType { case .nameCell: nameCell = tableView.dequeueReusableCell(withIdentifier: "textFieldCell", for: indexPath) as? TextFieldTableViewCell @@ -132,7 +132,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl return scanQRCodeCell! } } - + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 44 } @@ -153,11 +153,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sectionHeaderTitles[section] } - + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { return sectionFooterTitles[section] } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == deletePasswordCell { @@ -175,12 +175,12 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl let vc = SFSafariViewController(url: url, entersReaderIfAvailable: false) vc.delegate = self present(vc, animated: true) - + } } tableView.deselectRow(at: indexPath, animated: true) } - + // generate password, copy to pasteboard, and set the cell // check whether the current password looks like an OTP field func generateAndCopyPassword() { @@ -195,23 +195,23 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl self.generateAndCopyPasswordNoOtpCheck() } } - + // generate the password, don't care whether the original line is otp func generateAndCopyPasswordNoOtpCheck() { // show password settings (e.g., the length slider) showPasswordSettings() - + let length = passwordLengthCell?.roundedValue ?? 0 let plainPassword = PasswordGeneratorFlavour.from(SharedDefaults[.passwordGeneratorFlavor]).generatePassword(length: length) SecurePasteboard.shared.copy(textToCopy: plainPassword) - + // update tableData so to make sure reloadData() works correctly tableData[passwordSection][0][PasswordEditorCellKey.content] = plainPassword - + // update cell manually, no need to call reloadData() fillPasswordCell?.setContent(content: plainPassword) } - + // show password settings (e.g., the length slider) func showPasswordSettings() { if hidePasswordSettings == true { @@ -219,13 +219,13 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl tableView.reloadSections([passwordSection], with: .fade) } } - + // show/hide password settings (e.g., the length slider) func showHidePasswordSettings() { hidePasswordSettings = !hidePasswordSettings tableView.reloadSections([passwordSection], with: .fade) } - + func insertScannedOTPFields(_ otpauth: String) { // update tableData var additionsString = "" @@ -235,11 +235,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl additionsString = otpauth } tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsString - + // reload the additions cell additionsCell?.setContent(content: additionsString) } - + // MARK: - QRScannerControllerDelegate Methods func checkScannedOutput(line: String) -> (accept: Bool, message: String) { if let url = URL(string: line), let _ = Token(url: url) { @@ -248,12 +248,12 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl return (accept: false, message: "Invalid token URL") } } - + // MARK: - QRScannerControllerDelegate Methods func handleScannedOutput(line: String) { insertScannedOTPFields(line) } - + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showQRScannerSegue" { if let navController = segue.destination as? UINavigationController { @@ -265,7 +265,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl } } } - + // update tableData so to make sure reloadData() works correctly func textFieldDidEndEditing(_ textField: UITextField) { if textField == nameCell?.contentTextField { @@ -277,48 +277,48 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl } } } - + // update tableData so to make sure reloadData() works correctly func textViewDidEndEditing(_ textView: UITextView) { if textView == additionsCell?.contentTextView { tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsCell?.getContent() } } - + func textFieldDidBeginEditing(_ textField: UITextField) { if textField == fillPasswordCell?.contentTextField { // show password generation settings automatically showPasswordSettings() } } - + func getNameURL() -> (String, URL) { let encodedName = (nameCell?.getContent()?.stringByAddingPercentEncodingForRFC3986())! let name = URL(string: encodedName)!.lastPathComponent let url = URL(string: encodedName)!.appendingPathExtension("gpg") return (name, url) } - + func checkName() -> Bool { // the name field should not be empty guard let name = nameCell?.getContent(), name.isEmpty == false else { Utils.alert(title: "Cannot Save", message: "Please fill in the name.", controller: self, completion: nil) return false } - + // the name should not start with / guard name.hasPrefix("/") == false else { Utils.alert(title: "Cannot Save", message: "Please remove the prefix \"/\" from your password name.", controller: self, completion: nil) return false } - + // the name field should be a valid url guard let path = name.stringByAddingPercentEncodingForRFC3986(), var passwordURL = URL(string: path) else { Utils.alert(title: "Cannot Save", message: "Password name is invalid.", controller: self, completion: nil) return false } - + // check whether we can parse the filename (be consistent with PasswordStore::addPasswordEntities) var previousPathLength = Int.max while passwordURL.path != "." { @@ -329,10 +329,10 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl } previousPathLength = passwordURL.path.count } - + return true } - + func safariViewControllerDidFinish(_ controller: SFSafariViewController) { let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty }) if copiedLinesSplit?.count ?? 0 > 0 { @@ -353,5 +353,5 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl self.present(alert, animated: true, completion: nil) } } - + } diff --git a/pass/Controllers/PasswordsViewController.swift b/pass/Controllers/PasswordsViewController.swift index 27c5430..dccefbf 100644 --- a/pass/Controllers/PasswordsViewController.swift +++ b/pass/Controllers/PasswordsViewController.swift @@ -27,13 +27,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV private var filteredPasswordsTableEntries: [PasswordsTableEntry] = [] private var parentPasswordEntity: PasswordEntity? = nil private let passwordStore = PasswordStore.shared - + private var tapTabBarTime: TimeInterval = 0 private var sections = [(title: String, entries: [PasswordsTableEntry])]() - + private var searchActive : Bool = false - + private lazy var searchController: UISearchController = { let uiSearchController = UISearchController(searchResultsController: nil) uiSearchController.searchResultsUpdater = self @@ -59,7 +59,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV let backUIBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(self.backAction(_:))) return backUIBarButtonItem }() - + private lazy var transitionFromRight: CATransition = { let transition = CATransition() transition.type = kCATransitionPush @@ -69,7 +69,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV transition.subtype = kCATransitionFromRight return transition }() - + private lazy var transitionFromLeft: CATransition = { let transition = CATransition() transition.type = kCATransitionPush @@ -81,7 +81,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV }() @IBOutlet weak var tableView: UITableView! - + private func initPasswordsTableEntries(parent: PasswordEntity?) { passwordsTableEntries.removeAll() passwordsTableAllEntries.removeAll() @@ -102,9 +102,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } parentPasswordEntity = parent } - + @IBAction func cancelAddPassword(segue: UIStoryboardSegue) { - + } @IBAction func saveAddPassword(segue: UIStoryboardSegue) { if let controller = segue.source as? AddPasswordTableViewController { @@ -127,7 +127,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + private func syncPasswords() { guard passwordStore.repositoryExisted() else { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) { @@ -190,17 +190,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + if SharedDefaults[.isShowFolderOn] { searchController.searchBar.scopeButtonTitles = ["Current", "All"] } else { searchController.searchBar.scopeButtonTitles = nil } } - + override func viewDidLoad() { super.viewDidLoad() searchController.searchBar.delegate = self @@ -220,22 +220,22 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV tableView.refreshControl = syncControl SVProgressHUD.setDefaultMaskType(.black) tableView.register(UINib(nibName: "PasswordWithFolderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordWithFolderTableViewCell") - + // initialize the password table reloadTableView(parent: nil) - + // reset the data table if some password (maybe another one) has been updated NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordStoreUpdated, object: nil) // reset the data table if the disaply settings have been changed NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordDisplaySettingChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil) - + // listen to the swipe back guesture let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture)) swipeRight.direction = UISwipeGestureRecognizerDirection.right self.view.addGestureRecognizer(swipeRight) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) tabBarController!.delegate = self @@ -243,7 +243,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV tableView.deselectRow(at: path, animated: false) } } - + override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() guard #available(iOS 11, *) else { @@ -252,21 +252,21 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV return } } - + func numberOfSections(in tableView: UITableView) -> Int { return sections.count } - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return sections[section].entries.count } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:))) longPressGestureRecognizer.minimumPressDuration = 0.6 if SharedDefaults[.isShowFolderOn] && searchController.searchBar.selectedScopeButtonIndex == 0{ let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) - + let entry = getPasswordEntry(by: indexPath) if entry.passwordEntity!.synced { cell.textLabel?.text = entry.title @@ -299,11 +299,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } - + private func getPasswordEntry(by indexPath: IndexPath) -> PasswordsTableEntry { return sections[indexPath.section].entries[indexPath.row] } - + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let entry = getPasswordEntry(by: indexPath) if !entry.isDir { @@ -318,7 +318,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV reloadTableView(parent: entry.passwordEntity, anim: transitionFromRight) } } - + @objc func respondToSwipeGesture(gesture: UIGestureRecognizer) { if let swipeGesture = gesture as? UISwipeGestureRecognizer { // swipe right -> swipe back @@ -327,7 +327,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + @objc func backAction(_ sender: Any?) { guard SharedDefaults[.isShowFolderOn] else { return } var anim: CATransition? = transitionFromLeft @@ -336,7 +336,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } reloadTableView(parent: parentPasswordEntity?.parent, anim: anim) } - + @objc func longPressAction(_ gesture: UILongPressGestureRecognizer) { if gesture.state == UIGestureRecognizerState.began { let touchPoint = gesture.location(in: tableView) @@ -345,7 +345,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sections[section].title } @@ -357,11 +357,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { return index } - + func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { decryptThenCopyPassword(from: indexPath) } - + private func requestPGPKeyPassphrase() -> String { let sem = DispatchSemaphore(value: 0) var passphrase = "" @@ -389,7 +389,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } return passphrase } - + private func decryptThenCopyPassword(from indexPath: IndexPath) { guard self.passwordStore.privateKey != nil else { Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) @@ -418,39 +418,39 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + private func generateSections(item: [PasswordsTableEntry]) { let collation = UILocalizedIndexedCollation.current() let sectionTitles = collation.sectionIndexTitles var newSections = [(title: String, entries: [PasswordsTableEntry])]() - + // initialize all sections for i in 0.. 0} } - + @objc func actOnSearchNotification() { searchController.searchBar.becomeFirstResponder() } - + override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "showPasswordDetail" { guard self.passwordStore.privateKey != nil else { @@ -487,7 +487,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } } - + func filterContentForSearchText(searchText: String, scope: String = "All") { switch scope { case "All": @@ -512,10 +512,10 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV default: break } - - + + } - + private func reloadTableView(data: [PasswordsTableEntry], anim: CAAnimation? = nil) { // set navigation item let numberOfLocalCommits = self.passwordStore.numberOfLocalCommits @@ -529,7 +529,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } else { navigationItem.leftBarButtonItem = nil } - + // set the password table generateSections(item: data) if anim != nil { @@ -537,7 +537,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } tableView.reloadData() self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey") - + // set the sync control title let atribbutedTitle = "Last Synced: \(lastSyncedTimeString())" syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle) @@ -552,12 +552,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV formatter.timeStyle = .short return formatter.string(from: date) } - + private func reloadTableView(parent: PasswordEntity?, anim: CAAnimation? = nil) { initPasswordsTableEntries(parent: parent) reloadTableView(data: passwordsTableEntries, anim: anim) } - + @objc func actOnReloadTableViewRelatedNotification() { DispatchQueue.main.async { [weak weakSelf = self] in guard let strongSelf = weakSelf else { return } @@ -565,11 +565,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV strongSelf.reloadTableView(data: strongSelf.passwordsTableEntries) } } - + @objc func handleRefresh(_ syncControl: UIRefreshControl) { syncPasswords() } - + func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { if viewController == self.navigationController { let currentTime = Date().timeIntervalSince1970 @@ -586,14 +586,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV backAction(self) } } - + func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { // update the default search scope SharedDefaults[.isSearchDefaultAll] = searchController.searchBar.scopeButtonTitles![selectedScope] == "All" updateSearchResults(for: searchController) } - - + + func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { // set the default search scope to "all" if SharedDefaults[.isShowFolderOn] && SharedDefaults[.isSearchDefaultAll] { @@ -603,14 +603,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } return true } - + func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool { // set the default search scope to "current" searchController.searchBar.selectedScopeButtonIndex = 0 updateSearchResults(for: searchController) return true } - + private func requestGitPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? { let sem = DispatchSemaphore(value: 0) var password: String? @@ -621,7 +621,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV case .ssh: message = "Please fill in the password of your SSH key." } - + DispatchQueue.main.async { SVProgressHUD.dismiss() let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert) @@ -639,7 +639,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV }) self.present(alert, animated: true, completion: nil) } - + let _ = sem.wait(timeout: .distantFuture) return password } diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift index 0b7d6fe..d69988e 100644 --- a/pass/Controllers/QRScannerController.swift +++ b/pass/Controllers/QRScannerController.swift @@ -17,90 +17,90 @@ protocol QRScannerControllerDelegate { } class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { - + @IBOutlet weak var scannerOutput: UILabel! - + var captureSession: AVCaptureSession? var videoPreviewLayer: AVCaptureVideoPreviewLayer? var qrCodeFrameView: UIView? - + let supportedCodeTypes = [AVMetadataObject.ObjectType.qr] - + var delegate: QRScannerControllerDelegate? - + override func viewDidLoad() { super.viewDidLoad() - + if AVCaptureDevice.authorizationStatus(for: .video) == .denied { presentCameraSettings() } - + // Get an instance of the AVCaptureDevice class to initialize a device object and provide the video as the media type parameter. let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) do { // Get an instance of the AVCaptureDeviceInput class using the previous device object. let input = try AVCaptureDeviceInput(device: captureDevice!) - + // Initialize the captureSession object. captureSession = AVCaptureSession() // Set the input device on the capture session. captureSession?.addInput(input) - + // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. let captureMetadataOutput = AVCaptureMetadataOutput() captureSession?.addOutput(captureMetadataOutput) - + // Set delegate and use the default dispatch queue to execute the call back captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) captureMetadataOutput.metadataObjectTypes = supportedCodeTypes - + // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer. videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!) videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill videoPreviewLayer?.frame = view.layer.bounds view.layer.addSublayer(videoPreviewLayer!) - + // Start video capture. captureSession?.startRunning() - + // Move the message label to the front scannerOutput.layer.cornerRadius = 10 scannerOutput.text = "No QR code detected" view.bringSubview(toFront: scannerOutput) - + // Initialize QR Code Frame to highlight the QR code qrCodeFrameView = UIView() - + if let qrCodeFrameView = qrCodeFrameView { qrCodeFrameView.layer.borderColor = UIColor.green.cgColor qrCodeFrameView.layer.borderWidth = 2 view.addSubview(qrCodeFrameView) view.bringSubview(toFront: qrCodeFrameView) } - + } catch { scannerOutput.text = error.localizedDescription } } - + override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - + + // MARK: - AVCaptureMetadataOutputObjectsDelegate Methods - + func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: 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 - + // check whether it is a valid result if let scanned = metadataObj.stringValue { if let (accept, message) = delegate?.checkScannedOutput(line: scanned) { @@ -121,13 +121,13 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg } else { scannerOutput.text = "No string value" } - + } else { qrCodeFrameView?.frame = CGRect.zero scannerOutput.text = "No QR code detected" } } - + func presentCameraSettings() { let alertController = UIAlertController(title: "Error", message: "Camera access denied.\nWARNING: Toggle the camera permission resets the app! Save your changes.", @@ -140,7 +140,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg }) } }) - + present(alertController, animated: true) } } diff --git a/pass/Controllers/RawPasswordViewController.swift b/pass/Controllers/RawPasswordViewController.swift index 171e95e..4f258e0 100644 --- a/pass/Controllers/RawPasswordViewController.swift +++ b/pass/Controllers/RawPasswordViewController.swift @@ -13,7 +13,7 @@ class RawPasswordViewController: UIViewController { @IBOutlet weak var rawPasswordTextView: UITextView! var password: Password? - + override func viewDidLoad() { super.viewDidLoad() navigationItem.title = password?.name diff --git a/pass/Controllers/SSHKeySettingTableViewController.swift b/pass/Controllers/SSHKeySettingTableViewController.swift index 698b873..95fe132 100644 --- a/pass/Controllers/SSHKeySettingTableViewController.swift +++ b/pass/Controllers/SSHKeySettingTableViewController.swift @@ -14,21 +14,21 @@ class SSHKeySettingTableViewController: UITableViewController { @IBOutlet weak var privateKeyURLTextField: UITextField! let passwordStore = PasswordStore.shared - + override func viewDidLoad() { super.viewDidLoad() privateKeyURLTextField.text = SharedDefaults[.gitSSHPrivateKeyURL]?.absoluteString } - - + + @IBAction func doneButtonTapped(_ sender: UIButton) { guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else { Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil) return } - + SharedDefaults[.gitSSHPrivateKeyURL] = privateKeyURL - + do { try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic) } catch { diff --git a/pass/Controllers/SettingsSplitViewController.swift b/pass/Controllers/SettingsSplitViewController.swift index baf70ae..1ac4e54 100644 --- a/pass/Controllers/SettingsSplitViewController.swift +++ b/pass/Controllers/SettingsSplitViewController.swift @@ -13,7 +13,7 @@ class SettingsSplitViewController: UISplitViewController, UISplitViewControllerD self.delegate = self self.preferredDisplayMode = .allVisible } - + func splitViewController( _ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index 12657b5..7e0b26e 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -16,14 +16,14 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele @IBOutlet weak var passcodeTableViewCell: UITableViewCell! @IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell! var setPasscodeLockAlert: UIAlertController? - + let passwordStore = PasswordStore.shared var passcodeLock = PasscodeLock.shared - + func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { navigationController?.popViewController(animated: true) } - + @IBAction func savePGPKey(segue: UIStoryboardSegue) { if let controller = segue.source as? PGPKeySettingTableViewController { SharedDefaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!.trimmed) @@ -32,7 +32,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase } SharedDefaults[.pgpKeySource] = "url" - + SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) SVProgressHUD.show(withStatus: "Fetching PGP Key") @@ -53,7 +53,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } } } - + } else if let controller = segue.source as? PGPKeyArmorSettingTableViewController { SharedDefaults[.pgpKeySource] = "armor" if SharedDefaults[.isRememberPGPPassphraseOn] { @@ -62,7 +62,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SharedDefaults[.pgpPublicKeyArmor] = controller.armorPublicKeyTextView.text! SharedDefaults[.pgpPrivateKeyArmor] = controller.armorPrivateKeyTextView.text! - + SVProgressHUD.setDefaultMaskType(.black) SVProgressHUD.setDefaultStyle(.light) SVProgressHUD.show(withStatus: "Fetching PGP Key") @@ -84,7 +84,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } } } - + private func saveImportedPGPKey() { // load keys SharedDefaults[.pgpKeySource] = "file" @@ -108,11 +108,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } } } - + @IBAction func saveGitServerSetting(segue: UIStoryboardSegue) { self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host } - + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return super.tableView(tableView, numberOfRowsInSection: section) } @@ -125,12 +125,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele setPasswordRepositoryTableViewCellDetailText() setPasscodeLockCell() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(true) tabBarController!.delegate = self } - + private func setPasscodeLockCell() { if passcodeLock.hasPasscode { self.passcodeTableViewCell.detailTextLabel?.text = "On" @@ -138,7 +138,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele self.passcodeTableViewCell.detailTextLabel?.text = "Off" } } - + private func setPGPKeyTableViewCellDetailText() { if let pgpKeyID = self.passwordStore.pgpKeyID { pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID @@ -146,7 +146,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele pgpKeyTableViewCell.detailTextLabel?.text = "Not Set" } } - + private func setPasswordRepositoryTableViewCellDetailText() { if SharedDefaults[.gitURL] == nil { passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set" @@ -154,13 +154,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host } } - + @objc func actOnPasswordStoreErasedNotification() { setPGPKeyTableViewCellDetailText() setPasswordRepositoryTableViewCellDetailText() setPasscodeLockCell() } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if tableView.cellForRow(at: indexPath) == passcodeTableViewCell { if SharedDefaults[.passcodeKey] != nil{ @@ -173,13 +173,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } tableView.deselectRow(at: indexPath, animated: true) } - + func showPGPKeyActionSheet() { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) var urlActionTitle = "Download from URL" var armorActionTitle = "ASCII-Armor Encrypted Key" var fileActionTitle = "iTunes File Sharing" - + if SharedDefaults[.pgpKeySource] == "url" { urlActionTitle = "✓ \(urlActionTitle)" } else if SharedDefaults[.pgpKeySource] == "armor" { @@ -235,8 +235,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } optionMenu.addAction(fileAction) } - - + + if SharedDefaults[.pgpKeySource] != nil { let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in self.passwordStore.removePGPKeys() @@ -249,12 +249,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele optionMenu.popoverPresentationController?.sourceRect = pgpKeyTableViewCell.bounds self.present(optionMenu, animated: true, completion: nil) } - + func showPasscodeActionSheet() { let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let passcodeRemoveViewController = PasscodeLockViewController() - - + + let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in passcodeRemoveViewController.successCallback = { self?.passcodeLock.delete() @@ -262,11 +262,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } self?.present(passcodeRemoveViewController, animated: true, completion: nil) } - + let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in self?.setPasscodeLock() } - + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) optionMenu.addAction(removePasscodeAction) optionMenu.addAction(changePasscodeAction) @@ -289,7 +289,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } } } - + func setPasscodeLock() { // prepare the alert for setting the passcode setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert) @@ -303,7 +303,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele textField.isSecureTextEntry = true textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged) }) - + // save action let saveAction = UIAlertAction(title: "Save", style: .default) { (action:UIAlertAction) -> Void in let passcode: String = self.setPasscodeLockAlert!.textFields![0].text! @@ -312,10 +312,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele self.setPasscodeLockCell() } saveAction.isEnabled = false // disable the Save button by default - + // cancel action let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) - + // present setPasscodeLockAlert?.addAction(saveAction) setPasscodeLockAlert?.addAction(cancelAction) diff --git a/pass/Controllers/SpecialThanksTableViewController.swift b/pass/Controllers/SpecialThanksTableViewController.swift index 8d58cee..abd68da 100644 --- a/pass/Controllers/SpecialThanksTableViewController.swift +++ b/pass/Controllers/SpecialThanksTableViewController.swift @@ -19,7 +19,7 @@ class SpecialThanksTableViewController: BasicStaticTableViewController { ["FlatIcon", "https://www.flaticon.com"], ] - + override func viewDidLoad() { tableData.append([]) for item in openSourceComponents { diff --git a/pass/Helpers/SecurePasteboard.swift b/pass/Helpers/SecurePasteboard.swift index df4f1f8..8dbbe49 100644 --- a/pass/Helpers/SecurePasteboard.swift +++ b/pass/Helpers/SecurePasteboard.swift @@ -12,33 +12,33 @@ import UIKit class SecurePasteboard { public static let shared = SecurePasteboard() private var backgroundTaskID = UIBackgroundTaskInvalid - + func copy(textToCopy: String?, expirationTime: Double = 45) { // copy to the pasteboard UIPasteboard.general.string = textToCopy ?? "" - + // clean the pasteboard after expirationTime guard expirationTime > 0 else { return } - + // exit the existing background task, if any if backgroundTaskID != UIBackgroundTaskInvalid { UIApplication.shared.endBackgroundTask(UIBackgroundTaskInvalid) self.backgroundTaskID = UIBackgroundTaskInvalid } - + backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in UIPasteboard.general.string = "" UIApplication.shared.endBackgroundTask(UIBackgroundTaskInvalid) self?.backgroundTaskID = UIBackgroundTaskInvalid }) - + DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + expirationTime) { [weak self] in UIPasteboard.general.string = "" UIApplication.shared.endBackgroundTask(UIBackgroundTaskInvalid) self?.backgroundTaskID = UIBackgroundTaskInvalid } } - + } diff --git a/pass/Views/ContentTableViewCell.swift b/pass/Views/ContentTableViewCell.swift index d68dea4..34b462b 100644 --- a/pass/Views/ContentTableViewCell.swift +++ b/pass/Views/ContentTableViewCell.swift @@ -18,11 +18,11 @@ class ContentTableViewCell: UITableViewCell { override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } - + func getContent() -> String? { return nil } - + func setContent(content: String?) { } } diff --git a/pass/Views/FillPasswordTableViewCell.swift b/pass/Views/FillPasswordTableViewCell.swift index 0042ba1..9e1727b 100644 --- a/pass/Views/FillPasswordTableViewCell.swift +++ b/pass/Views/FillPasswordTableViewCell.swift @@ -18,15 +18,15 @@ class FillPasswordTableViewCell: ContentTableViewCell { @IBOutlet weak var contentTextField: UITextField! var delegate: FillPasswordTableViewCellDelegate? - + @IBOutlet weak var settingButton: UIButton! @IBOutlet weak var generateButton: UIButton! - + override func awakeFromNib() { super.awakeFromNib() // Initialization code contentTextField.font = Globals.passwordFont - + // Force aspect ratio of button images settingButton.imageView?.contentMode = .scaleAspectFit generateButton.imageView?.contentMode = .scaleAspectFit @@ -37,24 +37,24 @@ class FillPasswordTableViewCell: ContentTableViewCell { // Configure the view for the selected state } - + @IBAction func generatePassword(_ sender: UIButton) { self.delegate?.generateAndCopyPassword() } - + @IBAction func showHidePasswordSettings() { self.delegate?.showHidePasswordSettings() } - + // re-color @IBAction func textFieldDidChange(_ sender: UITextField) { contentTextField.attributedText = Utils.attributedPassword(plainPassword: sender.text ?? "") } - + override func getContent() -> String? { return contentTextField.attributedText?.string } - + override func setContent(content: String?) { contentTextField.attributedText = Utils.attributedPassword(plainPassword: content ?? "") } diff --git a/pass/Views/LabelTableViewCell.swift b/pass/Views/LabelTableViewCell.swift index daa701b..7f22ae3 100644 --- a/pass/Views/LabelTableViewCell.swift +++ b/pass/Views/LabelTableViewCell.swift @@ -19,19 +19,19 @@ class LabelTableViewCell: UITableViewCell { @IBOutlet weak var contentLabel: UILabel! @IBOutlet weak var titleLabel: UILabel! - + private enum CellType { case password, URL, HOTP, other } private var type = CellType.other private var isReveal = false - + weak var delegatePasswordTableView : PasswordDetailTableViewController? - + private var passwordDisplayButton: UIButton? private var buttons: UIView? - + var cellData: LabelTableViewCellData? { didSet { guard let title = cellData?.title, let content = cellData?.content else { @@ -72,7 +72,7 @@ class LabelTableViewCell: UITableViewCell { updateButtons() } } - + override var canBecomeFirstResponder: Bool { get { return true @@ -103,7 +103,7 @@ class LabelTableViewCell: UITableViewCell { override func copy(_ sender: Any?) { SecurePasteboard.shared.copy(textToCopy: cellData?.content) } - + @objc func revealPassword(_ sender: Any?) { let plainPassword = cellData?.content ?? "" if type == .password { @@ -114,7 +114,7 @@ class LabelTableViewCell: UITableViewCell { isReveal = true passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Invisible"), for: .normal) } - + @objc func concealPassword(_ sender: Any?) { if type == .password { if cellData?.content.isEmpty == false { @@ -128,7 +128,7 @@ class LabelTableViewCell: UITableViewCell { isReveal = false passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Visible"), for: .normal) } - + @objc func reversePasswordDisplay(_ sender: Any?) { if isReveal { // conceal @@ -143,21 +143,21 @@ class LabelTableViewCell: UITableViewCell { // if isURLCell, passwordTableView should not be nil delegatePasswordTableView!.openLink(to: cellData?.content) } - + @objc func getNextHOTP(_ sender: Any?) { // if isHOTPCell, passwordTableView should not be nil delegatePasswordTableView!.getNextHOTP() } - + private func updateButtons() { // total width and height of a button let height = min(self.bounds.height, 36.0) let width = max(height * 0.8, Globals.tableCellButtonSize) - + // margins (between button boundary and icon) let marginY = max((height - Globals.tableCellButtonSize) / 2, 0.0) let marginX = max((width - Globals.tableCellButtonSize) / 2, 0.0) - + switch type { case .password: if let content = cellData?.content, content != "" { @@ -178,7 +178,7 @@ class LabelTableViewCell: UITableViewCell { nextButton.imageView?.contentMode = .scaleAspectFit nextButton.contentEdgeInsets = UIEdgeInsetsMake(marginY, marginX, marginY, marginX) nextButton.addTarget(self, action: #selector(getNextHOTP), for: UIControlEvents.touchUpInside) - + // password button passwordDisplayButton = UIButton(type: .system) passwordDisplayButton!.frame = CGRect(x: width, y: 0, width: width, height: height) @@ -187,7 +187,7 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit passwordDisplayButton!.contentEdgeInsets = UIEdgeInsetsMake(marginY, marginX, marginY, marginX) passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControlEvents.touchUpInside) - + buttons = UIView() buttons!.frame = CGRect(x: 0, y: 0, width: width * 2, height: height) buttons!.addSubview(nextButton) diff --git a/pass/Views/PasswordDetailTitleTableViewCell.swift b/pass/Views/PasswordDetailTitleTableViewCell.swift index 68fce90..6d76ad6 100644 --- a/pass/Views/PasswordDetailTitleTableViewCell.swift +++ b/pass/Views/PasswordDetailTitleTableViewCell.swift @@ -22,5 +22,5 @@ class PasswordDetailTitleTableViewCell: UITableViewCell { // Configure the view for the selected state } - + } diff --git a/pass/Views/SliderTableViewCell.swift b/pass/Views/SliderTableViewCell.swift index cbcdebb..e782951 100644 --- a/pass/Views/SliderTableViewCell.swift +++ b/pass/Views/SliderTableViewCell.swift @@ -18,15 +18,15 @@ class SliderTableViewCell: ContentTableViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var valueLabel: UILabel! @IBOutlet weak var slider: UISlider! - + var delegate: UITableViewController? - + var roundedValue: Int { get { return Int(valueLabel.text!)! } } - + override func awakeFromNib() { super.awakeFromNib() // Initialization code @@ -37,7 +37,7 @@ class SliderTableViewCell: ContentTableViewCell { // Configure the view for the selected state } - + @IBAction func handleSliderValueChange(_ sender: UISlider) { let oldRoundedValue = self.roundedValue let newRoundedValue = Int(sender.value) @@ -51,14 +51,14 @@ class SliderTableViewCell: ContentTableViewCell { delegate.generateAndCopyPassword() } } - + func reset(title: String, minimumValue: Int, maximumValue: Int, defaultValue: Int) { titleLabel.text = title slider.minimumValue = Float(minimumValue) slider.maximumValue = Float(maximumValue) slider.value = Float(defaultValue) valueLabel.text = String(defaultValue) - + // "not editable" if minimumValue == maximumValue { titleLabel.textColor = UIColor.gray @@ -66,5 +66,5 @@ class SliderTableViewCell: ContentTableViewCell { slider.isUserInteractionEnabled = false } } - + } diff --git a/pass/Views/TextFieldTableViewCell.swift b/pass/Views/TextFieldTableViewCell.swift index 1522d36..68d4eb4 100644 --- a/pass/Views/TextFieldTableViewCell.swift +++ b/pass/Views/TextFieldTableViewCell.swift @@ -11,15 +11,15 @@ import UIKit class TextFieldTableViewCell: ContentTableViewCell { @IBOutlet weak var contentTextField: UITextField! - + override func awakeFromNib() { super.awakeFromNib() } - + override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } - + override func getContent() -> String? { return contentTextField.text } diff --git a/pass/Views/TextViewTableViewCell.swift b/pass/Views/TextViewTableViewCell.swift index ba6e701..4b00187 100644 --- a/pass/Views/TextViewTableViewCell.swift +++ b/pass/Views/TextViewTableViewCell.swift @@ -19,11 +19,11 @@ class TextViewTableViewCell: ContentTableViewCell { override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } - + override func getContent() -> String? { return contentTextView.text } - + override func setContent(content: String?) { contentTextView.text = content } diff --git a/pass/Views/TitleTextFieldTableViewCell.swift b/pass/Views/TitleTextFieldTableViewCell.swift index a24f5ce..c96703c 100644 --- a/pass/Views/TitleTextFieldTableViewCell.swift +++ b/pass/Views/TitleTextFieldTableViewCell.swift @@ -12,7 +12,7 @@ class TitleTextFieldTableViewCell: UITableViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var contentTextField: UITextField! - + override func awakeFromNib() { super.awakeFromNib() // Initialization code @@ -20,7 +20,7 @@ class TitleTextFieldTableViewCell: UITableViewCell { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tap(_:))) titleLabel.addGestureRecognizer(tapGestureRecognizer) } - + @objc func tap(_ sender: Any?) { contentTextField.becomeFirstResponder() } @@ -28,5 +28,5 @@ class TitleTextFieldTableViewCell: UITableViewCell { override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } - + } diff --git a/passAutoFillExtension/CredentialProviderViewController.swift b/passAutoFillExtension/CredentialProviderViewController.swift index 5688f4d..3e87a4c 100644 --- a/passAutoFillExtension/CredentialProviderViewController.swift +++ b/passAutoFillExtension/CredentialProviderViewController.swift @@ -25,18 +25,18 @@ fileprivate class PasswordsTableEntry : NSObject { class CredentialProviderViewController: ASCredentialProviderViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate { @IBOutlet weak var searchBar: UISearchBar! @IBOutlet weak var tableView: UITableView! - + private let passwordStore = PasswordStore.shared - + private var searchActive = false private var passwordsTableEntries: [PasswordsTableEntry] = [] private var filteredPasswordsTableEntries: [PasswordsTableEntry] = [] - + private lazy var passcodelock: PasscodeExtensionDisplay = { let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext) return passcodelock }() - + /* Prepare your UI to list available credentials for the user to choose from. The items in 'serviceIdentifiers' describe the service the user is logging in to, so your extension can @@ -50,14 +50,14 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa searchBarSearchButtonClicked(searchBar) return } - + // get the domain var identifier = serviceIdentifiers[0].identifier if !identifier.hasPrefix("http://") && !identifier.hasPrefix("https://") { identifier = "http://" + identifier } let url = URL(string: identifier)?.host ?? "" - + // "click" search searchBar.text = url searchBar.becomeFirstResponder() @@ -102,20 +102,20 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa super.viewWillAppear(animated) passcodelock.presentPasscodeLockIfNeeded(self) } - + override func viewDidLoad() { super.viewDidLoad() - + // prepare searchBar.delegate = self tableView.delegate = self tableView.dataSource = self tableView.register(UINib(nibName: "PasswordWithFolderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordWithFolderTableViewCell") - + // initialize table entries initPasswordsTableEntries() } - + private func initPasswordsTableEntries() { passwordsTableEntries.removeAll() filteredPasswordsTableEntries.removeAll() @@ -125,7 +125,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa PasswordsTableEntry($0) } } - + // define cell contents, and set long press action func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) @@ -140,16 +140,16 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa cell.detailTextLabel?.text = entry.categoryText return cell } - + // select row -> extension returns (with username and password) func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let entry = getPasswordEntry(by: indexPath) - + guard self.passwordStore.privateKey != nil else { Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) return } - + let passwordEntity = entry.passwordEntity! UIImpactFeedbackGenerator(style: .medium).impactOccurred() DispatchQueue.global(qos: .userInteractive).async { @@ -171,18 +171,18 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } } } - + func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if searchActive { return filteredPasswordsTableEntries.count } return passwordsTableEntries.count; } - + private func requestPGPKeyPassphrase() -> String { let sem = DispatchSemaphore(value: 0) var passphrase = "" @@ -204,13 +204,13 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } return passphrase } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" searchActive = false self.tableView.reloadData() } - + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { if let searchText = searchBar.text, searchText.isEmpty == false { filteredPasswordsTableEntries = passwordsTableEntries.filter { entry in @@ -229,11 +229,11 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } self.tableView.reloadData() } - + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { searchBarSearchButtonClicked(searchBar) } - + private func getPasswordEntry(by indexPath: IndexPath) -> PasswordsTableEntry { if searchActive { return filteredPasswordsTableEntries[indexPath.row] diff --git a/passAutoFillExtension/PasscodeExtensionDisplay.swift b/passAutoFillExtension/PasscodeExtensionDisplay.swift index 8130a7b..6863378 100644 --- a/passAutoFillExtension/PasscodeExtensionDisplay.swift +++ b/passAutoFillExtension/PasscodeExtensionDisplay.swift @@ -31,7 +31,7 @@ class PasscodeExtensionDisplay { private var isPasscodePresented = false private let passcodeLockVC: PasscodeLockViewControllerForExtension private let extensionContext: ASCredentialProviderExtensionContext? - + public init(extensionContext: ASCredentialProviderExtensionContext?) { self.extensionContext = extensionContext passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) @@ -40,7 +40,7 @@ class PasscodeExtensionDisplay { } passcodeLockVC.setCancellable(true) } - + // present the passcode lock view if passcode is set and the view controller is not presented public func presentPasscodeLockIfNeeded(_ extensionVC: UIViewController) { guard PasscodeLock.shared.hasPasscode && !isPasscodePresented == true else { @@ -49,7 +49,7 @@ class PasscodeExtensionDisplay { isPasscodePresented = true extensionVC.present(passcodeLockVC, animated: true, completion: nil) } - + public func dismiss(animated: Bool = true) { isPasscodePresented = false } diff --git a/passExtension/ExtensionViewController.swift b/passExtension/ExtensionViewController.swift index 0d74b0e..2e5593c 100644 --- a/passExtension/ExtensionViewController.swift +++ b/passExtension/ExtensionViewController.swift @@ -26,24 +26,24 @@ fileprivate class PasswordsTableEntry : NSObject { class ExtensionViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationBarDelegate { @IBOutlet weak var searchBar: UISearchBar! @IBOutlet weak var tableView: UITableView! - + private let passwordStore = PasswordStore.shared - + private var searchActive = false private var passwordsTableEntries: [PasswordsTableEntry] = [] private var filteredPasswordsTableEntries: [PasswordsTableEntry] = [] - + enum Action { case findLogin, fillBrowser, unknown } - + private var extensionAction = Action.unknown - + private lazy var passcodelock: PasscodeExtensionDisplay = { let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext) return passcodelock }() - + private func initPasswordsTableEntries() { passwordsTableEntries.removeAll() filteredPasswordsTableEntries.removeAll() @@ -53,12 +53,12 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV PasswordsTableEntry($0) } } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) passcodelock.presentPasscodeLockIfNeeded(self) } - + override func viewDidLoad() { super.viewDidLoad() // prepare @@ -66,15 +66,15 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV tableView.delegate = self tableView.dataSource = self tableView.register(UINib(nibName: "PasswordWithFolderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordWithFolderTableViewCell") - + // initialize table entries initPasswordsTableEntries() - + // get the provider guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else { return } - + for extensionItem in extensionItems { if let itemProviders = extensionItem.attachments as? [NSItemProvider] { for provider in itemProviders { @@ -133,7 +133,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } } } - + // define cell contents, and set long press action func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) @@ -148,16 +148,16 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV cell.detailTextLabel?.text = entry.categoryText return cell } - + // select row -> extension returns (with username and password) func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let entry = getPasswordEntry(by: indexPath) - + guard self.passwordStore.privateKey != nil else { Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil) return } - + let passwordEntity = entry.passwordEntity! UIImpactFeedbackGenerator(style: .medium).impactOccurred() DispatchQueue.global(qos: .userInteractive).async { @@ -197,19 +197,19 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } } } - - + + func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if searchActive{ return filteredPasswordsTableEntries.count } return passwordsTableEntries.count; } - + private func requestPGPKeyPassphrase() -> String { let sem = DispatchSemaphore(value: 0) var passphrase = "" @@ -231,17 +231,17 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } return passphrase } - + @IBAction func cancelExtension(_ sender: Any) { extensionContext!.completeRequest(returningItems: [], completionHandler: nil) } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" searchActive = false self.tableView.reloadData() } - + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { if let searchText = searchBar.text, searchText.isEmpty == false { filteredPasswordsTableEntries = passwordsTableEntries.filter { entry in @@ -260,11 +260,11 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } self.tableView.reloadData() } - + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { searchBarSearchButtonClicked(searchBar) } - + private func getPasswordEntry(by indexPath: IndexPath) -> PasswordsTableEntry { if searchActive { return filteredPasswordsTableEntries[indexPath.row] diff --git a/passExtension/OnePasswordExtensionConstants.swift b/passExtension/OnePasswordExtensionConstants.swift index 894b921..53c922c 100644 --- a/passExtension/OnePasswordExtensionConstants.swift +++ b/passExtension/OnePasswordExtensionConstants.swift @@ -28,7 +28,7 @@ class OnePasswordExtensionKey { static let returnedFieldsKey = "returned_fields" static let oldPasswordKey = "old_password" static let passwordGeneratorOptionsKey = "password_generator_options" - + // Password Generator options - Used to set the 1Password Password Generator options when saving a new Login or when changing the password for for an existing Login static let generatedPasswordMinLengthKey = "password_min_length" static let generatedPasswordMaxLengthKey = "password_max_length" diff --git a/passExtension/PasscodeExtensionDisplay.swift b/passExtension/PasscodeExtensionDisplay.swift index 11de111..88011b8 100644 --- a/passExtension/PasscodeExtensionDisplay.swift +++ b/passExtension/PasscodeExtensionDisplay.swift @@ -30,7 +30,7 @@ class PasscodeExtensionDisplay { private var isPasscodePresented = false private let passcodeLockVC: PasscodeLockViewControllerForExtension private let extensionContext: NSExtensionContext? - + public init(extensionContext: NSExtensionContext?) { self.extensionContext = extensionContext passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) @@ -39,7 +39,7 @@ class PasscodeExtensionDisplay { } passcodeLockVC.setCancellable(true) } - + // present the passcode lock view if passcode is set and the view controller is not presented public func presentPasscodeLockIfNeeded(_ extensionVC: UIViewController) { guard PasscodeLock.shared.hasPasscode && !isPasscodePresented == true else { @@ -48,7 +48,7 @@ class PasscodeExtensionDisplay { isPasscodePresented = true extensionVC.present(passcodeLockVC, animated: true, completion: nil) } - + public func dismiss(animated: Bool = true) { isPasscodePresented = false } diff --git a/passExtension/passProcessor.js b/passExtension/passProcessor.js index 2cb114e..5f9c746 100644 --- a/passExtension/passProcessor.js +++ b/passExtension/passProcessor.js @@ -12,7 +12,7 @@ run: function(arguments) { arguments.completionFunction({"url_string": url, "error": error}); } }, - + finalize: function(arguments) { if (arguments["password"]) { var passwordElement = document.querySelector("input[type=password]") @@ -21,7 +21,7 @@ finalize: function(arguments) { passwordElement.value = arguments["password"] } } - + if (arguments["username"]) { var usernameElement = document.querySelector("input[type=email], input[type=text]") if (usernameElement) { diff --git a/passKit/Controllers/PasscodeLockPresenter.swift b/passKit/Controllers/PasscodeLockPresenter.swift index d9df482..236a3a6 100644 --- a/passKit/Controllers/PasscodeLockPresenter.swift +++ b/passKit/Controllers/PasscodeLockPresenter.swift @@ -11,7 +11,7 @@ import UIKit open class PasscodeLockPresenter { - + fileprivate var mainWindow: UIWindow? fileprivate var passcodeLockWindow: UIWindow? @@ -21,16 +21,16 @@ open class PasscodeLockPresenter { open func present(windowLevel: CGFloat?) { guard PasscodeLock.shared.hasPasscode else { return } - + // dismiss the original window dismiss() - + // new window mainWindow?.endEditing(true) passcodeLockWindow = UIWindow(frame: self.mainWindow!.frame) moveWindowsToFront(windowLevel: windowLevel) passcodeLockWindow?.isHidden = false - + // new vc let passcodeLockVC = PasscodeLockViewController() let userDismissCompletionCallback = passcodeLockVC.dismissCompletionCallback diff --git a/passKit/Controllers/PasscodeLockViewController.swift b/passKit/Controllers/PasscodeLockViewController.swift index 7be4362..f32e68c 100644 --- a/passKit/Controllers/PasscodeLockViewController.swift +++ b/passKit/Controllers/PasscodeLockViewController.swift @@ -12,23 +12,23 @@ import UIKit import LocalAuthentication open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { - + open var dismissCompletionCallback: (()->Void)? open var successCallback: (()->Void)? open var cancelCallback: (()->Void)? - + weak var passcodeLabel: UILabel? weak var passcodeWrongAttemptsLabel: UILabel? weak var passcodeTextField: UITextField? weak var biometryAuthButton: UIButton? open weak var cancelButton: UIButton? - + var passcodeFailedAttempts = 0 var isCancellable: Bool = false - + open override func loadView() { super.loadView() - + let passcodeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) passcodeLabel.text = "Enter passcode for Pass" passcodeLabel.font = UIFont.boldSystemFont(ofSize: 18) @@ -37,7 +37,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { passcodeLabel.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(passcodeLabel) self.passcodeLabel = passcodeLabel - + let passcodeWrongAttemptsLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) passcodeWrongAttemptsLabel.text = "" passcodeWrongAttemptsLabel.textColor = UIColor.red @@ -45,7 +45,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { passcodeWrongAttemptsLabel.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(passcodeWrongAttemptsLabel) self.passcodeWrongAttemptsLabel = passcodeWrongAttemptsLabel - + let passcodeTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) passcodeTextField.borderStyle = UITextBorderStyle.roundedRect passcodeTextField.placeholder = "passcode" @@ -57,7 +57,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { passcodeTextField.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(passcodeTextField) self.passcodeTextField = passcodeTextField - + let biometryAuthButton = UIButton(type: .custom) biometryAuthButton.setTitle("", for: .normal) biometryAuthButton.setTitleColor(Globals.blue, for: .normal) @@ -66,7 +66,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { biometryAuthButton.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(biometryAuthButton) self.biometryAuthButton = biometryAuthButton - + let myContext = LAContext() var authError: NSError? if #available(iOS 8.0, macOS 10.12.1, *) { @@ -81,7 +81,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { biometryAuthButton.isHidden = false } } - + let cancelButton = UIButton(type: .custom) cancelButton.setTitle("Cancel", for: .normal) cancelButton.setTitleColor(Globals.blue, for: .normal) @@ -91,7 +91,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { cancelButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left self.view.addSubview(cancelButton) self.cancelButton = cancelButton - + NSLayoutConstraint.activate([ passcodeTextField.widthAnchor.constraint(equalToConstant: 300), passcodeTextField.heightAnchor.constraint(equalToConstant: 40), @@ -118,13 +118,13 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { cancelButton.topAnchor.constraint(equalTo: self.view.safeTopAnchor), cancelButton.leftAnchor.constraint(equalTo: self.view.safeLeftAnchor, constant: 20) ]) - + } - + open override func viewDidLoad() { super.viewDidLoad() } - + open override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let biometryAuthButton = biometryAuthButton { @@ -137,7 +137,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { DispatchQueue.main.async { self.passcodeTextField?.text = "" } - + // pop if presentingViewController?.presentedViewController == self { // if presented as modal @@ -160,16 +160,16 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { passcodeWrongAttemptsLabel?.text = "" dismissPasscodeLock(completionHandler: successCallback) } - + @objc func passcodeLockDidCancel() { dismissPasscodeLock(completionHandler: cancelCallback) } - + @objc func bioButtonPressedAction(_ uiButton: UIButton) { let myContext = LAContext() let myLocalizedReasonString = "Authentication is needed to access Pass." var authError: NSError? - + if #available(iOS 8.0, *) { if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) { myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, evaluateError in @@ -183,7 +183,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { } } } - + public override func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == passcodeTextField { if !PasscodeLock.shared.check(passcode: textField.text ?? "") { @@ -198,13 +198,13 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { textField.resignFirstResponder() return true } - + @objc func passcodeTextFieldDidChange(_ textField: UITextField) { if PasscodeLock.shared.check(passcode: textField.text ?? "") { self.passcodeLockDidSucceed() } } - + public func setCancellable(_ isCancellable: Bool) { self.isCancellable = isCancellable cancelButton?.isHidden = !isCancellable diff --git a/passKit/Helpers/DefaultsKeys.swift b/passKit/Helpers/DefaultsKeys.swift index d1e972e..8f5c47e 100644 --- a/passKit/Helpers/DefaultsKeys.swift +++ b/passKit/Helpers/DefaultsKeys.swift @@ -15,10 +15,10 @@ public extension DefaultsKeys { static let pgpKeySource = DefaultsKey("pgpKeySource") static let pgpPublicKeyURL = DefaultsKey("pgpPublicKeyURL") static let pgpPrivateKeyURL = DefaultsKey("pgpPrivateKeyURL") - + static let pgpPublicKeyArmor = DefaultsKey("pgpPublicKeyArmor") static let pgpPrivateKeyArmor = DefaultsKey("pgpPrivateKeyArmor") - + static let gitURL = DefaultsKey("gitURL") static let gitAuthenticationMethod = DefaultsKey("gitAuthenticationMethod") static let gitUsername = DefaultsKey("gitUsername") @@ -29,10 +29,10 @@ public extension DefaultsKeys { static let gitSignatureEmail = DefaultsKey("gitSignatureEmail") static let lastSyncedTime = DefaultsKey("lastSyncedTime") - + static let isTouchIDOn = DefaultsKey("isTouchIDOn") static let passcodeKey = DefaultsKey("passcodeKey") - + static let isHideUnknownOn = DefaultsKey("isHideUnknownOn") static let isHideOTPOn = DefaultsKey("isHideOTPOn") static let isRememberPGPPassphraseOn = DefaultsKey("isRememberPGPPassphraseOn") @@ -40,6 +40,6 @@ public extension DefaultsKeys { static let isShowFolderOn = DefaultsKey("isShowFolderOn") static let isSearchDefaultAll = DefaultsKey("isSearchDefaultAll") static let passwordGeneratorFlavor = DefaultsKey("passwordGeneratorFlavor") - + static let encryptInArmored = DefaultsKey("encryptInArmored") } diff --git a/passKit/Helpers/FileManagerExtension.swift b/passKit/Helpers/FileManagerExtension.swift index 6a5a601..c1bfa16 100644 --- a/passKit/Helpers/FileManagerExtension.swift +++ b/passKit/Helpers/FileManagerExtension.swift @@ -10,7 +10,7 @@ import Foundation // https://gist.github.com/NikolaiRuhe/eeb135d20c84a7097516 public extension FileManager { - + /// This method calculates the accumulated size of a directory on the volume in bytes. /// /// As there's no simple way to get this information from the file system it has to crawl the entire hierarchy, @@ -20,73 +20,73 @@ public extension FileManager { /// - note: There are a couple of oddities that are not taken into account (like symbolic links, meta data of /// directories, hard links, ...). func allocatedSizeOfDirectoryAtURL(directoryURL : URL) throws -> UInt64 { - + // We'll sum up content size here: var accumulatedSize = UInt64(0) - + // prefetching some properties during traversal will speed up things a bit. let prefetchedProperties = [ URLResourceKey.isRegularFileKey, URLResourceKey.fileAllocatedSizeKey, URLResourceKey.totalFileAllocatedSizeKey, ] - + // The error handler simply signals errors to outside code. var errorDidOccur: Error? let errorHandler: (URL, Error) -> Bool = { _, error in errorDidOccur = error return false } - - + + // We have to enumerate all directory contents, including subdirectories. let enumerator = self.enumerator(at: directoryURL, includingPropertiesForKeys: prefetchedProperties, options: FileManager.DirectoryEnumerationOptions(), errorHandler: errorHandler) precondition(enumerator != nil) - + // Start the traversal: for item in enumerator! { let contentItemURL = item as! NSURL - + // Bail out on errors from the errorHandler. if let error = errorDidOccur { throw error } - + let resourceValueForKey: (URLResourceKey) throws -> NSNumber? = { key in var value: AnyObject? try contentItemURL.getResourceValue(&value, forKey: key) return value as? NSNumber } - + // Get the type of this item, making sure we only sum up sizes of regular files. guard let isRegularFile = try resourceValueForKey(URLResourceKey.isRegularFileKey) else { preconditionFailure() } - + guard isRegularFile.boolValue else { continue } - + // To get the file's size we first try the most comprehensive value in terms of what the file may use on disk. // This includes metadata, compression (on file system level) and block size. var fileSize = try resourceValueForKey(URLResourceKey.totalFileAllocatedSizeKey) - + // In case the value is unavailable we use the fallback value (excluding meta data and compression) // This value should always be available. fileSize = try fileSize ?? resourceValueForKey(URLResourceKey.fileAllocatedSizeKey) - + guard let size = fileSize else { preconditionFailure("huh? NSURLFileAllocatedSizeKey should always return a value") } - + // We're good, add up the value. accumulatedSize += size.uint64Value } - + // Bail out on errors from the errorHandler. if let error = errorDidOccur { throw error } - + // We finally got it. return accumulatedSize } diff --git a/passKit/Helpers/Globals.swift b/passKit/Helpers/Globals.swift index 990fc8b..483b052 100644 --- a/passKit/Helpers/Globals.swift +++ b/passKit/Helpers/Globals.swift @@ -10,7 +10,7 @@ import Foundation import UIKit public class Globals { - + // Legacy paths (not shared) public static let documentPathLegacy = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]; public static let libraryPathLegacy = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0]; @@ -19,11 +19,11 @@ public class Globals { public static let gitSSHPrivateKeyPathLegacy = "\(documentPathLegacy)/ssh_key" public static let gitSSHPrivateKeyURLLegacy = URL(fileURLWithPath: gitSSHPrivateKeyPathLegacy) public static let repositoryPathLegacy = "\(libraryPathLegacy)/password-store" - + public static let bundleIdentifier = "me.mssun.passforios" public static let groupIdentifier = "group." + bundleIdentifier public static let passKitBundleIdentifier = bundleIdentifier + ".passKit" - + public static let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)! public static let documentPath = sharedContainerURL.appendingPathComponent("Documents").path public static let libraryPath = sharedContainerURL.appendingPathComponent("Library").path @@ -33,19 +33,19 @@ public class Globals { public static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath) public static let repositoryPath = libraryPath + "/password-store" public static let dbPath = documentPath + "/pass.sqlite" - + public static let iTunesFileSharingPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] public static let iTunesFileSharingPGPPublic = iTunesFileSharingPath + "/gpg_key.pub" public static let iTunesFileSharingPGPPrivate = iTunesFileSharingPath + "/gpg_key" public static let iTunesFileSharingSSHPrivate = iTunesFileSharingPath + "/ssh_key" - + public static let gitSignatureDefaultName = "Pass for iOS" public static let gitSignatureDefaultEmail = "user@passforios" - + public static let passwordDots = "••••••••••••" public static let oneTimePasswordDots = "••••••" public static let passwordFont = UIFont(name: "Courier-Bold", size: UIFont.labelFontSize - 1) - + // UI related public static let red = UIColor(red:1.00, green:0.23, blue:0.19, alpha:1.0) public static let blue = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0) @@ -53,7 +53,7 @@ public class Globals { public static let symbolColor = UIColor(red:200/255.0, green:40/255.0, blue:41/255.0, alpha:1.0) public static let digitColor = UIColor(red:66/255.0, green:113/255.0, blue:174/255.0, alpha:1.0) public static let tableCellButtonSize = CGFloat(20.0) - + private init() { } } diff --git a/passKit/Helpers/NotificationNames.swift b/passKit/Helpers/NotificationNames.swift index aa7e7e3..9614cc4 100644 --- a/passKit/Helpers/NotificationNames.swift +++ b/passKit/Helpers/NotificationNames.swift @@ -13,7 +13,7 @@ public extension Notification.Name { static let passwordStoreErased = Notification.Name("passwordStoreErased") static let passwordStoreChangeDiscarded = Notification.Name("passwordStoreChangeDiscarded") static let passwordSearch = Notification.Name("passwordSearch") - + static let passwordDisplaySettingChanged = Notification.Name("passwordDisplaySettingChanged") static let passwordDetailDisplaySettingChanged = Notification.Name("passwordDetailDisplaySettingChanged") } diff --git a/passKit/Helpers/UIViewExtension.swift b/passKit/Helpers/UIViewExtension.swift index 649b032..51d0757 100644 --- a/passKit/Helpers/UIViewExtension.swift +++ b/passKit/Helpers/UIViewExtension.swift @@ -9,7 +9,7 @@ import Foundation extension UIView { - + // Save anchors: https://stackoverflow.com/questions/46317061/use-safe-area-layout-programmatically var safeTopAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { @@ -18,7 +18,7 @@ extension UIView { return self.topAnchor } } - + var safeLeftAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *){ return self.safeAreaLayoutGuide.leftAnchor @@ -26,7 +26,7 @@ extension UIView { return self.leftAnchor } } - + var safeRightAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *){ return self.safeAreaLayoutGuide.rightAnchor @@ -34,7 +34,7 @@ extension UIView { return self.rightAnchor } } - + var safeBottomAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.bottomAnchor diff --git a/passKit/Helpers/Utils.swift b/passKit/Helpers/Utils.swift index d9305bd..614de74 100644 --- a/passKit/Helpers/Utils.swift +++ b/passKit/Helpers/Utils.swift @@ -15,17 +15,17 @@ public class Utils { let keychain = Keychain(service: Globals.bundleIdentifier, accessGroup: Globals.groupIdentifier) return (try? keychain.getString(name)) ?? nil } - + public static func addPasswordToKeychain(name: String, password: String?) { let keychain = Keychain(service: Globals.bundleIdentifier, accessGroup: Globals.groupIdentifier) keychain[name] = password } - + public static func removeKeychain(name: String) { let keychain = Keychain(service: Globals.bundleIdentifier, accessGroup: Globals.groupIdentifier) try? keychain.remove(name) } - + public static func removeAllKeychain() { let keychain = Keychain(service: Globals.bundleIdentifier, accessGroup: Globals.groupIdentifier) try? keychain.removeAll() @@ -53,7 +53,7 @@ public class Utils { } return attributedPassword } - + public static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler)) diff --git a/passKit/Models/GitCredential.swift b/passKit/Models/GitCredential.swift index ddf5741..6dd046f 100644 --- a/passKit/Models/GitCredential.swift +++ b/passKit/Models/GitCredential.swift @@ -14,21 +14,21 @@ import ObjectiveGit public struct GitCredential { private var credential: Credential private let passwordStore = PasswordStore.shared - + public enum Credential { case http(userName: String) case ssh(userName: String, privateKeyFile: URL) } - + public init(credential: Credential) { self.credential = credential } - + public func credentialProvider(requestGitPassword: @escaping (Credential, String?) -> String?) throws -> GTCredentialProvider { var attempts = 0 return GTCredentialProvider { (_, _, _) -> (GTCredential?) in var credential: GTCredential? = nil - + switch self.credential { case let .http(userName): var lastPassword = self.passwordStore.gitPassword @@ -63,7 +63,7 @@ public struct GitCredential { return credential } } - + public func delete() { switch credential { case .http: diff --git a/passKit/Models/PasscodeLock.swift b/passKit/Models/PasscodeLock.swift index 7e55162..3ec15ae 100644 --- a/passKit/Models/PasscodeLock.swift +++ b/passKit/Models/PasscodeLock.swift @@ -11,24 +11,24 @@ import LocalAuthentication open class PasscodeLock { public static let shared = PasscodeLock() - + fileprivate let passcodeKey = "passcode.lock.passcode" fileprivate var passcode: String? { return SharedDefaults[.passcodeKey] } - + public var hasPasscode: Bool { return passcode != nil } - + public func save(passcode: String) { SharedDefaults[.passcodeKey] = passcode } - + public func check(passcode: String) -> Bool { return self.passcode == passcode } - + public func delete() { SharedDefaults[.passcodeKey] = nil } diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift index 88b1ec6..1924aaa 100644 --- a/passKit/Models/Password.swift +++ b/passKit/Models/Password.swift @@ -10,7 +10,7 @@ import OneTimePassword import Base32 public class Password { - + public var name: String public var url: URL public var plainText: String @@ -50,7 +50,7 @@ public class Password { public var login: String? { return getAdditionValue(withKey: Constants.LOGIN_KEYWORD) } - + public var urlString: String? { return getAdditionValue(withKey: Constants.URL_KEYWORD) } @@ -73,7 +73,7 @@ public class Password { self.plainText = plainText initEverything() } - + public func updatePassword(name: String, url: URL, plainText: String) { guard self.plainText != plainText || self.url != url else { @@ -129,7 +129,7 @@ public class Password { let toLowercase = { (string: String) -> String in caseSensitive ? string : string.lowercased() } return additions.first(where: { toLowercase($0.title) == toLowercase(key) })?.content } - + /// Set the OTP token if we are able to construct a valid one. /// /// Example of TOTP otpauth: @@ -164,7 +164,7 @@ public class Password { .usingCounter(getAdditionValue(withKey: Constants.OTP_COUNTER)) .build() } - + /// Get the OTP description and the current password. public func getOtpStrings() -> (description: String, otp: String)? { guard otpToken != nil else { @@ -178,18 +178,18 @@ public class Password { } return (description, otpToken!.currentPassword ?? "error") } - + // return the password strings // it is guaranteed that it is a HOTP password when we call this public func getNextHotp() -> String? { // increase the counter otpToken = otpToken?.updatedToken() - + // replace old HOTP settings with the new otpauth var newOtpauth = try! otpToken?.toURL().absoluteString newOtpauth?.append("&secret=") newOtpauth?.append(MF_Base32Codec.base32String(from: otpToken?.generator.secret)) - + var lines : [String] = [] self.plainText.enumerateLines() { line, _ in let (key, _) = Parser.getKeyValuePair(from: line) @@ -205,7 +205,7 @@ public class Password { lines.append(newOtpauth!) } self.updatePassword(name: self.name, url: self.url, plainText: lines.joined(separator: "\n")) - + // get and return the password return self.otpToken?.currentPassword } diff --git a/passKit/Models/PasswordEntity.swift b/passKit/Models/PasswordEntity.swift index 741fd56..886d41f 100644 --- a/passKit/Models/PasswordEntity.swift +++ b/passKit/Models/PasswordEntity.swift @@ -10,7 +10,7 @@ import Foundation import SwiftyUserDefaults extension PasswordEntity { - + public var nameWithCategory: String { get { if let p = path, p.hasSuffix(".gpg") { @@ -20,11 +20,11 @@ extension PasswordEntity { } } } - + public func getCategoryText() -> String { return getCategoryArray().joined(separator: " > ") } - + public func getCategoryArray() -> [String] { var parentEntity = parent var passwordCategoryArray: [String] = [] @@ -35,7 +35,7 @@ extension PasswordEntity { passwordCategoryArray.reverse() return passwordCategoryArray } - + public func getURL() -> URL? { if let p = getPath().stringByAddingPercentEncodingForRFC3986() { return URL(string: p) diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index a64d078..5d8fe75 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -18,7 +18,7 @@ public class PasswordStore { public static let shared = PasswordStore() public let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)") public let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp") - + public var storeRepository: GTRepository? public var pgpKeyID: String? public var publicKey: Key? { @@ -31,7 +31,7 @@ public class PasswordStore { } } public var privateKey: Key? - + public var gitSignatureForNow: GTSignature { get { let gitSignatureName = SharedDefaults[.gitSignatureName] ?? Globals.gitSignatureDefaultName @@ -39,9 +39,9 @@ public class PasswordStore { return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())! } } - + public let keyring = ObjectivePGP.defaultKeyring - + public var pgpKeyPassphrase: String? { set { Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: newValue) @@ -50,7 +50,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase") } } - + public var gitPassword: String? { set { Utils.addPasswordToKeychain(name: "gitPassword", password: newValue) @@ -59,7 +59,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "gitPassword") } } - + public var gitSSHPrivateKeyPassphrase: String? { set { Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newValue) @@ -68,7 +68,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") } } - + private let fm = FileManager.default lazy private var context: NSManagedObjectContext = { let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")! @@ -82,7 +82,7 @@ public class PasswordStore { if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - + /* Typical reasons for an error here include: * The parent directory does not exist, cannot be created, or disallows writing. @@ -96,11 +96,11 @@ public class PasswordStore { }) return container.viewContext }() - + public var numberOfPasswords : Int { - return self.fetchPasswordEntityCoreData(withDir: false).count + return self.fetchPasswordEntityCoreData(withDir: false).count } - + public var sizeOfRepositoryByteCount : UInt64 { return (try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.storeURL)) ?? 0 } @@ -112,12 +112,12 @@ public class PasswordStore { public var lastSyncedTime: Date? { return SharedDefaults[.lastSyncedTime] } - + private init() { // File migration to group migrateIfNeeded() backwardCompatibility() - + do { if fm.fileExists(atPath: storeURL.path) { try storeRepository = GTRepository.init(url: storeURL) @@ -127,14 +127,14 @@ public class PasswordStore { print(error) } } - + private func migrateIfNeeded() { // migrate happens only if the repository was cloned and pgp keys were set up using earlier versions let needMigration = !pgpKeyExists() && !gitSSHKeyExists() && !fm.fileExists(atPath: Globals.repositoryPath) && fm.fileExists(atPath: Globals.repositoryPathLegacy) guard needMigration == true else { return } - + do { // migrate Defaults let userDefaults = UserDefaults() @@ -143,7 +143,7 @@ public class PasswordStore { SharedDefaults.setValue(userDefaults.value(forKey: key), forKey: key) } } - + // migrate files try fm.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) try fm.createDirectory(atPath: Globals.libraryPath, withIntermediateDirectories: true, attributes: nil) @@ -162,7 +162,7 @@ public class PasswordStore { } updatePasswordEntityCoreData() } - + private func backwardCompatibility() { // For the newly-introduced isRememberGitCredentialPassphraseOn (20171008) if (self.gitPassword != nil || self.gitSSHPrivateKeyPassphrase != nil) && SharedDefaults[.isRememberGitCredentialPassphraseOn] == false { @@ -173,21 +173,21 @@ public class PasswordStore { SharedDefaults[.isRememberPGPPassphraseOn] = true } } - + enum SSHKeyType { case `public`, secret } - + public func initGitSSHKey(with armorKey: String) throws { let keyPath = Globals.gitSSHPrivateKeyPath try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii) } - + public func initPGPKeys() throws { try initPGPKey(.public) try initPGPKey(.secret) } - + public func initPGPKey(_ keyType: PGPKeyType) throws { switch keyType { case .public: @@ -206,7 +206,7 @@ public class PasswordStore { throw AppError.UnknownError } } - + public func initPGPKey(from url: URL, keyType: PGPKeyType) throws { var pgpKeyLocalPath = "" if keyType == .public { @@ -218,7 +218,7 @@ public class PasswordStore { try pgpKeyData.write(to: URL(fileURLWithPath: pgpKeyLocalPath), options: .atomic) try initPGPKey(keyType) } - + public func initPGPKey(with armorKey: String, keyType: PGPKeyType) throws { var pgpKeyLocalPath = "" if keyType == .public { @@ -229,8 +229,8 @@ public class PasswordStore { try armorKey.write(toFile: pgpKeyLocalPath, atomically: true, encoding: .ascii) try initPGPKey(keyType) } - - + + private func importKey(from keyPath: String) -> Key? { if fm.fileExists(atPath: keyPath) { let keys = try! ObjectivePGP.readKeys(fromPath: keyPath) @@ -245,12 +245,12 @@ public class PasswordStore { public func getPgpPrivateKey() -> Key { return keyring.keys.filter({$0.secretKey != nil})[0] } - + public func repositoryExisted() -> Bool { let fm = FileManager() return fm.fileExists(atPath: Globals.repositoryPath) } - + public func passwordExisted(password: Password) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -266,7 +266,7 @@ public class PasswordStore { } return true } - + public func passwordEntityExisted(path: String) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -282,7 +282,7 @@ public class PasswordStore { } return true } - + public func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -292,7 +292,7 @@ public class PasswordStore { fatalError("Failed to fetch password entities: \(error)") } } - + public func cloneRepository(remoteRepoURL: URL, credential: GitCredential, requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, @@ -323,7 +323,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } } - + public func pullRepository(credential: GitCredential, requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -339,7 +339,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } } - + private func updatePasswordEntityCoreData() { deleteCoreData(entityName: "PasswordEntity") do { @@ -393,7 +393,7 @@ public class PasswordStore { print("Error with save: \(error)") } } - + public func getRecentCommits(count: Int) throws -> [GTCommit] { guard let storeRepository = storeRepository else { return [] @@ -410,7 +410,7 @@ public class PasswordStore { } return commits } - + public func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -421,7 +421,7 @@ public class PasswordStore { fatalError("Failed to fetch passwords: \(error)") } } - + public func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -434,8 +434,8 @@ public class PasswordStore { fatalError("Failed to fetch passwords: \(error)") } } - - + + public func fetchUnsyncedPasswords() -> [PasswordEntity] { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0) @@ -446,7 +446,7 @@ public class PasswordStore { fatalError("Failed to fetch passwords: \(error)") } } - + public func setAllSynced() { let passwordEntities = fetchUnsyncedPasswords() for passwordEntity in passwordEntities { @@ -460,7 +460,7 @@ public class PasswordStore { fatalError("Failed to save: \(error)") } } - + public func getLatestUpdateInfo(filename: String) -> String { guard let storeRepository = storeRepository else { return "Unknown" @@ -486,10 +486,10 @@ public class PasswordStore { } return autoFormattedDifference } - + public func updateRemoteRepo() { } - + private func gitAdd(path: String) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -497,7 +497,7 @@ public class PasswordStore { try storeRepository.index().addFile(path) try storeRepository.index().write() } - + private func gitRm(path: String) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -509,7 +509,7 @@ public class PasswordStore { try storeRepository.index().removeFile(path) try storeRepository.index().write() } - + private func deleteDirectoryTree(at url: URL) throws { var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path) var count = try fm.contentsOfDirectory(atPath: tempURL.path).count @@ -519,12 +519,12 @@ public class PasswordStore { count = try fm.contentsOfDirectory(atPath: tempURL.path).count } } - + private func createDirectoryTree(at url: URL) throws { let tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path) try fm.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) } - + private func gitMv(from: String, to: String) throws { let fromURL = storeURL.appendingPathComponent(from) let toURL = storeURL.appendingPathComponent(to) @@ -532,7 +532,7 @@ public class PasswordStore { try gitAdd(path: to) try gitRm(path: from) } - + private func gitCommit(message: String) throws -> GTCommit? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -546,7 +546,7 @@ public class PasswordStore { let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name) return commit } - + private func getLocalBranch(withName branchName: String) throws -> GTBranch? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -555,7 +555,7 @@ public class PasswordStore { let branches = try storeRepository.branches(withPrefix: reference) return branches.first } - + public func pushRepository(credential: GitCredential, requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -571,12 +571,12 @@ public class PasswordStore { throw(error) } } - + private func addPasswordEntities(password: Password) throws -> PasswordEntity? { guard !passwordExisted(password: password) else { throw AppError.PasswordDuplicatedError } - + var passwordURL = password.url var previousPathLength = Int.max var paths: [String] = [] @@ -606,7 +606,7 @@ public class PasswordStore { } return nil } - + private func insertPasswordEntity(name: String, path: String, parent: PasswordEntity?, synced: Bool = false, isDir: Bool = false) -> PasswordEntity? { var ret: PasswordEntity? = nil if let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as? PasswordEntity { @@ -624,7 +624,7 @@ public class PasswordStore { } return ret } - + public func add(password: Password) throws -> PasswordEntity? { try createDirectoryTree(at: password.url) let newPasswordEntity = try addPasswordEntities(password: password) @@ -635,7 +635,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } - + public func delete(passwordEntity: PasswordEntity) throws { let deletedFileURL = passwordEntity.getURL()! try gitRm(path: deletedFileURL.path) @@ -644,7 +644,7 @@ public class PasswordStore { let _ = try gitCommit(message: "Remove \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) from store using Pass for iOS.") NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } - + public func edit(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? { var newPasswordEntity: PasswordEntity? = passwordEntity @@ -656,16 +656,16 @@ public class PasswordStore { newPasswordEntity = passwordEntity newPasswordEntity?.synced = false } - + if password.changed&PasswordChange.path.rawValue != 0 { let deletedFileURL = passwordEntity.getURL()! // add try createDirectoryTree(at: password.url) newPasswordEntity = try addPasswordEntities(password: password) - + // mv try gitMv(from: deletedFileURL.path, to: password.url.path) - + // delete try deleteDirectoryTree(at: deletedFileURL) try deletePasswordEntities(passwordEntity: passwordEntity) @@ -675,7 +675,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } - + private func deletePasswordEntities(passwordEntity: PasswordEntity) throws { var current: PasswordEntity? = passwordEntity while current != nil && (current!.children!.count == 0 || !current!.isDir) { @@ -689,7 +689,7 @@ public class PasswordStore { } } } - + public func saveUpdated(passwordEntity: PasswordEntity) { do { try context.save() @@ -697,11 +697,11 @@ public class PasswordStore { fatalError("Failed to save a PasswordEntity: \(error)") } } - + public func deleteCoreData(entityName: String) { let deleteFetchRequest = NSFetchRequest(entityName: entityName) let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest) - + do { try context.execute(deleteRequest) try context.save() @@ -710,7 +710,7 @@ public class PasswordStore { print(error) } } - + public func updateImage(passwordEntity: PasswordEntity, image: Data?) { guard let image = image else { return @@ -733,7 +733,7 @@ public class PasswordStore { } } } - + public func erase() { publicKey = nil privateKey = nil @@ -743,19 +743,19 @@ public class PasswordStore { try? fm.removeItem(atPath: Globals.pgpPublicKeyPath) try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath) try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) - + Utils.removeAllKeychain() deleteCoreData(entityName: "PasswordEntity") - + SharedDefaults.removeAll() storeRepository = nil - + NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreErased, object: nil) } - - // return the number of discarded commits + + // return the number of discarded commits public func reset() throws -> Int { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -772,7 +772,7 @@ public class PasswordStore { try storeRepository.reset(to: newHead, resetType: .hard) self.setAllSynced() self.updatePasswordEntityCoreData() - + NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil) return localCommits.count @@ -780,8 +780,8 @@ public class PasswordStore { return 0 // no new commit } } - - + + private func getLocalCommits() throws -> [GTCommit]? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSetError @@ -791,18 +791,18 @@ public class PasswordStore { throw AppError.RepositoryRemoteMasterNotFoundError } let remoteMasterBranch = try storeRepository.remoteBranches()[index] - + // check oid before calling localCommitsRelative guard remoteMasterBranch.oid != nil else { throw AppError.RepositoryRemoteMasterNotFoundError } - + // get a list of local commits return try storeRepository.localCommitsRelative(toRemoteBranch: remoteMasterBranch) } - - - + + + public func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? { let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.getPath()) let encryptedData = try Data(contentsOf: encryptedDataPath) @@ -817,7 +817,7 @@ public class PasswordStore { } return Password(name: passwordEntity.getName(), url: url, plainText: plainText) } - + public func encrypt(password: Password) throws -> Data { guard keyring.keys.count > 0 else { throw AppError.PGPPublicKeyNotExistError @@ -830,7 +830,7 @@ public class PasswordStore { return encryptedData } } - + public func removePGPKeys() { try? fm.removeItem(atPath: Globals.pgpPublicKeyPath) try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath) @@ -844,14 +844,14 @@ public class PasswordStore { publicKey = nil privateKey = nil } - + public func removeGitSSHKeys() { try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) Defaults.remove(.gitSSHPrivateKeyArmor) Defaults.remove(.gitSSHPrivateKeyURL) self.gitSSHPrivateKeyPassphrase = nil } - + public func gitSSHKeyExists(inFileSharing: Bool = false) -> Bool { if inFileSharing == false { return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath) @@ -859,7 +859,7 @@ public class PasswordStore { return fm.fileExists(atPath: Globals.iTunesFileSharingSSHPrivate) } } - + public func pgpKeyExists(inFileSharing: Bool = false) -> Bool { if inFileSharing == false { return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath) @@ -867,7 +867,7 @@ public class PasswordStore { return fm.fileExists(atPath: Globals.iTunesFileSharingPGPPublic) && fm.fileExists(atPath: Globals.iTunesFileSharingPGPPrivate) } } - + public func gitSSHKeyImportFromFileSharing() throws { try fm.moveItem(atPath: Globals.iTunesFileSharingSSHPrivate, toPath: Globals.gitSSHPrivateKeyPath) } diff --git a/passKit/Parser/AdditionField.swift b/passKit/Parser/AdditionField.swift index bffb2e0..3a17b08 100644 --- a/passKit/Parser/AdditionField.swift +++ b/passKit/Parser/AdditionField.swift @@ -35,7 +35,7 @@ extension AdditionField { } extension AdditionField: Equatable { - + public static func == (first: AdditionField, second: AdditionField) -> Bool { return first.asTuple == second.asTuple } diff --git a/passKit/Parser/OtpType.swift b/passKit/Parser/OtpType.swift index 3ae97e0..032c2dc 100644 --- a/passKit/Parser/OtpType.swift +++ b/passKit/Parser/OtpType.swift @@ -16,7 +16,7 @@ public enum OtpType: String { var description: String { return rawValue } - + init(token: Token?) { switch token?.generator.factor { case .some(.counter): diff --git a/passKitTests/Models/PasswordTest.swift b/passKitTests/Models/PasswordTest.swift index a94b209..9ab7317 100644 --- a/passKitTests/Models/PasswordTest.swift +++ b/passKitTests/Models/PasswordTest.swift @@ -14,7 +14,7 @@ class PasswordTest: XCTestCase { func testUrl() { let password = getPasswordObjectWith(content: "") - + XCTAssertEqual(password.url, PASSWORD_URL) XCTAssertEqual(password.namePath, PASSWORD_PATH) } diff --git a/passKitTests/passKitTests.swift b/passKitTests/passKitTests.swift index c248edc..1ab8ed3 100644 --- a/passKitTests/passKitTests.swift +++ b/passKitTests/passKitTests.swift @@ -10,27 +10,27 @@ import XCTest @testable import passKit class passKitTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testExample() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + func testPerformanceExample() { // This is an example of a performance test case. self.measure { // Put the code you want to measure the time of here. } } - + } diff --git a/passTests/passTests.swift b/passTests/passTests.swift index fbc5343..ae19270 100644 --- a/passTests/passTests.swift +++ b/passTests/passTests.swift @@ -9,27 +9,27 @@ import XCTest class passTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testExample() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + func testPerformanceExample() { // This is an example of a performance test case. self.measure { // Put the code you want to measure the time of here. } } - + }