diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..d346e2a --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.3 diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 0000000..3b16b2e --- /dev/null +++ b/.swiftformat @@ -0,0 +1,96 @@ +# Exclude folders + +--exclude Carthage,go,Pods + +# Enabled rules + +--rules andOperator, anyObjectProtocol, blankLinesAroundMark, blankLinesAtEndOfScope, blankLinesAtStartOfScope, blankLinesBetweenScopes, braces, consecutiveBlankLines, consecutiveSpaces, duplicateImports, elseOnSameLine, emptyBraces, fileHeader, hoistPatternLet, indent, isEmpty, leadingDelimiters, linebreakAtEndOfFile, linebreaks, modifierOrder, numberFormatting, preferKeyPath, redundantBackticks, redundantBreak, redundantExtensionACL, redundantFileprivate, redundantGet, redundantInit, redundantLet, redundantLetError, redundantNilInit, redundantObjc, redundantParens, redundantPattern, redundantRawValues, redundantReturn, redundantSelf, redundantVoidReturnType, semicolons, sortedImports, spaceAroundBraces, spaceAroundBrackets, spaceAroundComments, spaceAroundGenerics, spaceAroundOperators, spaceAroundParens, spaceInsideBraces, spaceInsideBrackets, spaceInsideComments, spaceInsideGenerics, spaceInsideParens, strongOutlets, strongifiedSelf, todos, trailingClosures, trailingCommas, trailingSpace, typeSugar, unusedArguments, void, wrap, wrapArguments, wrapAttributes, yodaConditions + +# Formatting options + +## Use allman indentation style: "true" or "false" (default) +--allman false +## Binary grouping,threshold (default: 4,8) or "none", "ignore" +--binarygrouping 4,8 +## Closing paren position: "balanced" (default) or "same-line" +--closingparen balanced +## Commas in collection literals: "always" (default) or "inline" +--commas always +## Decimal grouping,threshold (default: 3,6) or "none", "ignore" +--decimalgrouping 3,6 +## Placement of else/catch: "same-line" (default) or "next-line" +--elseposition same-line +## Case of 'e' in numbers: "lowercase" or "uppercase" (default) +--exponentcase lowercase +## Group exponent digits: "enabled" or "disabled" (default) +--exponentgrouping disabled +## Group digits after '.': "enabled" or "disabled" (default) +--fractiongrouping disabled +## Function @attributes: "preserve", "prev-line", or "same-line" +--funcattributes prev-line +## Guard else: "same-line", "next-line" or "auto" (default) +--guardelse auto +## Header comments: "strip", "ignore", or the text you wish use +--header ignore +## Hex grouping,threshold (default: 4,8) or "none", "ignore" +--hexgrouping 4,8 +## Casing for hex literals: "uppercase" (default) or "lowercase" +--hexliteralcase uppercase +## #if indenting: "indent" (default), "no-indent" or "outdent" +--ifdef indent +## "testable-top", "testable-bottom" or "alphabetized" (default) +--importgrouping testable-bottom +## Number of spaces to indent, or "tab" to use tabs +--indent 4 +## Indent cases inside a switch: "true" or "false" (default) +--indentcase false +## Linebreak character to use: "cr", "crlf" or "lf" (default) +--linebreaks lf +## Maximum length of a line before wrapping. defaults to "none" +--maxwidth none +## Comma-delimited list of modifiers in preferred order +--modifierorder +## Comma-delimited list of operators without surrounding space +--nospaceoperators +## Comma-delimited list of operators that shouldn't be wrapped +--nowrapoperators +## Octal grouping,threshold (default: 4,8) or "none", "ignore" +--octalgrouping 4,8 +## Spacing for operator funcs: "spaced" (default) or "no-space" +--operatorfunc spaced +## let/var placement in patterns: "hoist" (default) or "inline" +--patternlet hoist +## Explicit self: "insert", "remove" (default) or "init-only" +--self init-only +## Comma-delimited list of functions with @autoclosure arguments +--selfrequired +## Allow semicolons: "never" or "inline" (default) +--semicolons inline +## Use ? for Optionals "always" (default) or "except-properties" +--shortoptionals always +## Align code independently of tab width. defaults to "enabled" +--smarttabs enabled +## "closure-only", "unnamed-only" or "always" (default) +--stripunusedargs always +## The width of a tab character. Defaults to "unspecified" +--tabwidth 4 +## Comma-delimited list of functions that use trailing closures +--trailingclosures +## Trim trailing space: "always" (default) or "nonblank-lines" +--trimwhitespace always +## Type @attributes: "preserve", "prev-line", or "same-line" +--typeattributes preserve +## Property @attributes: "preserve", "prev-line", or "same-line" +--varattributes same-line +## How Void types are represented: "void" (default) or "tuple" +--voidtype void +## Wrap all arguments: "before-first", "after-first", "preserve" +--wraparguments preserve +## Wrap array/dict: "before-first", "after-first", "preserve" +--wrapcollections preserve +## Wrap func params: "before-first", "after-first", "preserve" +--wrapparameters preserve +## Xcode indent guard/enum: "enabled" or "disabled" (default) +--xcodeindentation disabled +## Swap yoda values: "always" (default) or "literals-only" +--yodaswap always diff --git a/.travis.yml b/.travis.yml index 5dca7b5..e21130c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ addons: - go - gnupg2 - pass + - swiftformat before_install: - echo -e "machine github.com\n login $GITHUB_ACCESS_TOKEN" >> ~/.netrc install: diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 3f2be65..7bf5f35 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -1080,6 +1080,7 @@ A26700191EEC450100176B8A /* Embed App Extensions */, A26075921EEC6F34005DB03E /* Embed Frameworks */, 9AF6A4F532EB900EE22C80EA /* [CP] Embed Pods Frameworks */, + 3005F34F24A9143C000519B5 /* ShellScript */, ); buildRules = ( ); @@ -1321,6 +1322,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 3005F34F24A9143C000519B5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "SWIFTFORMAT_VERSION=\"0.45.*\"\n\nif which swiftformat > /dev/null; then\n if [[ \"$(swiftformat --version)\" == $SWIFTFORMAT_VERSION ]]; then\n swiftformat .\n else\n echo \"Failure: SwiftFormat $SWIFTFORMAT_VERSION is required. Install it or update the build script to use a newer version.\"\n exit 1\n fi\nelse\n echo \"Failure: SwiftFormat not installed. Get it via 'brew install swiftformat'.\"\n exit 2\nfi\n"; + }; 3EFC287772C1D2B2762FAC45 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift index 1658566..86d7361 100644 --- a/pass/AppDelegate.swift +++ b/pass/AppDelegate.swift @@ -6,15 +6,14 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import CoreData -import SVProgressHUD import passKit +import SVProgressHUD import SwiftyUserDefaults +import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? enum ViewTag: Int { case blur = 100, appicon @@ -25,50 +24,51 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return presenter }() - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100)) passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel.rawValue) if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem { if shortcutItem.type == Globals.bundleIdentifier + ".search" { - self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4) + perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4) } } return true } - func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { + func application(_: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if let _ = window?.rootViewController as? PasscodeLockViewController { window?.frame = UIScreen.main.bounds } return .all } - @objc func postSearchNotification() { + @objc + func postSearchNotification() { NotificationCenter.default.post(name: .passwordSearch, object: nil) } - func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { + func application(_: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler _: @escaping (Bool) -> Void) { if shortcutItem.type == Globals.bundleIdentifier + ".search" { - let tabBarController = self.window!.rootViewController as! UITabBarController + let tabBarController = window!.rootViewController as! UITabBarController tabBarController.selectedIndex = 0 let navigationController = tabBarController.selectedViewController as! UINavigationController navigationController.popToRootViewController(animated: false) - self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4) + perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4) } } - func applicationWillResignActive(_ application: UIApplication) { + func applicationWillResignActive(_: 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: UIBlurEffect.Style.light) let blurEffectView = UIVisualEffectView(effect: blurEffect) - blurEffectView.frame = (self.window?.frame)! + blurEffectView.frame = (window?.frame)! blurEffectView.tag = ViewTag.blur.rawValue blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.window?.addSubview(blurEffectView) + window?.addSubview(blurEffectView) // Display the Pass icon in the middle of the screen let iconsDictionary = Bundle.main.infoDictionary?["CFBundleIcons"] as? NSDictionary @@ -78,33 +78,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let appIconView = UIImageView(image: appIcon) appIconView.layer.cornerRadius = (appIcon?.size.height)! / 5 appIconView.layer.masksToBounds = true - appIconView.center = (self.window?.center)! + appIconView.center = (window?.center)! appIconView.tag = ViewTag.appicon.rawValue - self.window?.addSubview(appIconView) + window?.addSubview(appIconView) } - func applicationDidEnterBackground(_ application: UIApplication) { + func applicationDidEnterBackground(_: 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) { + func applicationWillEnterForeground(_: UIApplication) { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel.rawValue) } - func applicationDidBecomeActive(_ application: UIApplication) { + func applicationDidBecomeActive(_: 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() + window?.viewWithTag(ViewTag.appicon.rawValue)?.removeFromSuperview() + window?.viewWithTag(ViewTag.blur.rawValue)?.removeFromSuperview() } - func applicationWillTerminate(_ application: UIApplication) { + func applicationWillTerminate(_: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. // Saves changes in the application's managed object context before the application terminates. - self.saveContext() + saveContext() } // MARK: - Core Data stack @@ -123,7 +122,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) } container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))] - container.loadPersistentStores(completionHandler: { (storeDescription, error) in + container.loadPersistentStores(completionHandler: { _, error in 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. @@ -144,7 +143,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // MARK: - Core Data Saving support - func saveContext () { + func saveContext() { let context = persistentContainer.viewContext if context.hasChanges { do { @@ -157,6 +156,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } } - } - diff --git a/pass/Controllers/AboutRepositoryTableViewController.swift b/pass/Controllers/AboutRepositoryTableViewController.swift index 0c4abde..761ce4b 100644 --- a/pass/Controllers/AboutRepositoryTableViewController.swift +++ b/pass/Controllers/AboutRepositoryTableViewController.swift @@ -6,11 +6,10 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class AboutRepositoryTableViewController: BasicStaticTableViewController { - private static let VALUE_NOT_AVAILABLE = "ValueNotAvailable".localize() private var needRefresh = false @@ -18,6 +17,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { let indicator = UIActivityIndicatorView(style: .gray) return indicator }() + private let passwordStore = PasswordStore.shared override func viewDidLoad() { @@ -41,10 +41,9 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { } private func setTableData() { - // clear current contents (if any) - self.tableData.removeAll(keepingCapacity: true) - self.tableView.reloadData() + tableData.removeAll(keepingCapacity: true) + tableView.reloadData() indicator.startAnimating() // reload the table @@ -67,8 +66,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { [.style: CellDataStyle.value1, .accessoryType: type, .title: "LocalCommits".localize(), .detailText: localCommits], [.style: CellDataStyle.value1, .accessoryType: type, .title: "LastSynced".localize(), .detailText: lastSynced], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits".localize(), .detailText: commits], - [.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"], - ], + [.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"]], ] strongSelf.indicator.stopAnimating() strongSelf.tableView.reloadData() @@ -79,15 +77,15 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { private func numberOfPasswordsString() -> String { let formatter = NumberFormatter() formatter.numberStyle = NumberFormatter.Style.decimal - return formatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords)) ?? "" + return formatter.string(from: NSNumber(value: passwordStore.numberOfPasswords)) ?? "" } private func sizeOfRepositoryString() -> String { - return ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file) + ByteCountFormatter.string(fromByteCount: Int64(passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file) } private func lastSyncedTimeString() -> String { - guard let date = self.passwordStore.lastSyncedTime else { + guard let date = passwordStore.lastSyncedTime else { return "SyncAgain?".localize() } let formatter = DateFormatter() @@ -103,7 +101,8 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController { return AboutRepositoryTableViewController.VALUE_NOT_AVAILABLE } - @objc func setNeedRefresh() { + @objc + func setNeedRefresh() { needRefresh = true } } diff --git a/pass/Controllers/AboutTableViewController.swift b/pass/Controllers/AboutTableViewController.swift index f329edf..145a3b5 100644 --- a/pass/Controllers/AboutTableViewController.swift +++ b/pass/Controllers/AboutTableViewController.swift @@ -9,17 +9,16 @@ import UIKit class AboutTableViewController: BasicStaticTableViewController { - override func viewDidLoad() { tableData = [ // section 0 [[.title: "Website".localize(), .action: "link", .link: "https://github.com/mssun/pass-ios.git"], [.title: "Help".localize(), .action: "link", .link: "https://github.com/mssun/passforios/wiki"], - [.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],], + [.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"]], // section 1, [[.title: "OpenSourceComponents".localize(), .action: "segue", .link: "showOpenSourceComponentsSegue"], - [.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"],], + [.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"]], ] super.viewDidLoad() } @@ -39,11 +38,10 @@ class AboutTableViewController: BasicStaticTableViewController { return nil } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { if section == 1 { return "Acknowledgements".localize().uppercased() } return nil } - } diff --git a/pass/Controllers/AddPasswordTableViewController.swift b/pass/Controllers/AddPasswordTableViewController.swift index 75d770a..86948c8 100644 --- a/pass/Controllers/AddPasswordTableViewController.swift +++ b/pass/Controllers/AddPasswordTableViewController.swift @@ -6,8 +6,8 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class AddPasswordTableViewController: PasswordEditorTableViewController { var defaultDirPrefix = "" @@ -17,7 +17,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { tableData[0][0][PasswordEditorCellKey.content] = defaultDirPrefix } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { + override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { if identifier == "saveAddPasswordSegue" { // check PGP key guard PGPAgent.shared.isPrepared else { diff --git a/pass/Controllers/AdvancedSettingsTableViewController.swift b/pass/Controllers/AdvancedSettingsTableViewController.swift index 5dba6a1..4716f01 100644 --- a/pass/Controllers/AdvancedSettingsTableViewController.swift +++ b/pass/Controllers/AdvancedSettingsTableViewController.swift @@ -6,16 +6,15 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SVProgressHUD import passKit +import SVProgressHUD +import UIKit class AdvancedSettingsTableViewController: UITableViewController { - - @IBOutlet weak var encryptInASCIIArmoredTableViewCell: UITableViewCell! - @IBOutlet weak var gitSignatureTableViewCell: UITableViewCell! - @IBOutlet weak var eraseDataTableViewCell: UITableViewCell! - @IBOutlet weak var discardChangesTableViewCell: UITableViewCell! + @IBOutlet var encryptInASCIIArmoredTableViewCell: UITableViewCell! + @IBOutlet var gitSignatureTableViewCell: UITableViewCell! + @IBOutlet var eraseDataTableViewCell: UITableViewCell! + @IBOutlet var discardChangesTableViewCell: UITableViewCell! let passwordStore = PasswordStore.shared let encryptInASCIIArmoredSwitch: UISwitch = { @@ -37,10 +36,10 @@ class AdvancedSettingsTableViewController: UITableViewController { private func setGitSignatureText() { let gitSignatureName = passwordStore.gitSignatureForNow?.name ?? "" let gitSignatureEmail = passwordStore.gitSignatureForNow?.email ?? "" - self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote) - self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>" - if Defaults.gitSignatureName == nil && Defaults.gitSignatureEmail == nil { - self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body) + gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote) + gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>" + if Defaults.gitSignatureName == nil, Defaults.gitSignatureEmail == nil { + gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body) gitSignatureTableViewCell.detailTextLabel?.text = "NotSet".localize() } } @@ -49,7 +48,7 @@ class AdvancedSettingsTableViewController: UITableViewController { tableView.deselectRow(at: indexPath, animated: true) if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell { let alert = UIAlertController(title: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in + alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in SVProgressHUD.show(withStatus: "Erasing...".localize()) self.passwordStore.erase() self.navigationController!.popViewController(animated: true) @@ -57,10 +56,10 @@ class AdvancedSettingsTableViewController: UITableViewController { SVProgressHUD.dismiss(withDelay: 1) })) alert.addAction(UIAlertAction.dismiss()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell { let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in + alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in SVProgressHUD.show(withStatus: "Resetting...".localize()) do { let numberDiscarded = try self.passwordStore.reset() @@ -73,15 +72,17 @@ class AdvancedSettingsTableViewController: UITableViewController { })) alert.addAction(UIAlertAction.dismiss()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } } - @objc func encryptInASCIIArmoredAction(_ sender: Any?) { + @objc + func encryptInASCIIArmoredAction(_: Any?) { Defaults.encryptInArmored = encryptInASCIIArmoredSwitch.isOn } - @IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) { + @IBAction + func saveGitConfigSetting(segue: UIStoryboardSegue) { if let controller = segue.source as? GitConfigSettingsTableViewController { if let gitSignatureName = controller.nameTextField.text, let gitSignatureEmail = controller.emailTextField.text { @@ -91,5 +92,4 @@ class AdvancedSettingsTableViewController: UITableViewController { setGitSignatureText() } } - } diff --git a/pass/Controllers/BasicStaticTableViewController.swift b/pass/Controllers/BasicStaticTableViewController.swift index c061e05..f87dcfc 100644 --- a/pass/Controllers/BasicStaticTableViewController.swift +++ b/pass/Controllers/BasicStaticTableViewController.swift @@ -6,11 +6,10 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SafariServices import MessageUI import passKit - +import SafariServices +import UIKit enum CellDataType { case link, segue, empty, detail @@ -25,7 +24,7 @@ enum CellDataKey { } class BasicStaticTableViewController: UITableViewController, MFMailComposeViewControllerDelegate { - var tableData = [[Dictionary]]() + var tableData = [[[CellDataKey: Any]]]() var navigationItemTitle: String? override func viewDidLoad() { @@ -35,12 +34,12 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo } } - override func numberOfSections(in tableView: UITableView) -> Int { - return tableData.count + override func numberOfSections(in _: UITableView) -> Int { + tableData.count } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return tableData[section].count + override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + tableData[section].count } override func didReceiveMemoryWarning() { @@ -48,8 +47,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo // Dispose of any resources that can be recreated. } - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + override func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cellData = tableData[indexPath.section][indexPath.row] let cellDataStyle = cellData[CellDataKey.style] as? CellDataStyle var cell: UITableViewCell? @@ -76,7 +74,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo return cell ?? UITableViewCell() } - override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { + override func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { let cellData = tableData[indexPath.section][indexPath.row] let selector = cellData[CellDataKey.detailDisclosureAction] as? Selector perform(selector, with: cellData[CellDataKey.detailDisclosureData]) @@ -108,7 +106,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo } case "http", "https": let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false) - self.present(svc, animated: true, completion: nil) + present(svc, animated: true, completion: nil) default: break } @@ -123,10 +121,10 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo mailVC.setToRecipients(recipients) mailVC.setSubject(subject) mailVC.setMessageBody("", isHTML: false) - self.present(mailVC, animated: true, completion: nil) + present(mailVC, animated: true, completion: nil) } - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) { controller.dismiss(animated: true) } } diff --git a/pass/Controllers/CommitLogsTableViewController.swift b/pass/Controllers/CommitLogsTableViewController.swift index 1efaa1b..f68bb12 100644 --- a/pass/Controllers/CommitLogsTableViewController.swift +++ b/pass/Controllers/CommitLogsTableViewController.swift @@ -6,9 +6,9 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import ObjectiveGit import passKit +import UIKit class CommitLogsTableViewController: UITableViewController { var commits: [GTCommit] = [] @@ -18,12 +18,12 @@ class CommitLogsTableViewController: UITableViewController { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil) commits = getCommitLogs() - self.tableView.estimatedRowHeight = 50 - self.tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 50 + tableView.rowHeight = UITableView.automaticDimension } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return commits.count + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + commits.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -42,7 +42,8 @@ class CommitLogsTableViewController: UITableViewController { return cell } - @objc func updateCommitLogs() { + @objc + func updateCommitLogs() { commits = getCommitLogs() tableView.reloadData() } diff --git a/pass/Controllers/EditPasswordTableViewController.swift b/pass/Controllers/EditPasswordTableViewController.swift index 107f1df..cd2a139 100644 --- a/pass/Controllers/EditPasswordTableViewController.swift +++ b/pass/Controllers/EditPasswordTableViewController.swift @@ -6,11 +6,11 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class EditPasswordTableViewController: PasswordEditorTableViewController { - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { + override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { if identifier == "saveEditPasswordSegue" { // check name guard checkName() else { diff --git a/pass/Controllers/GeneralSettingsTableViewController.swift b/pass/Controllers/GeneralSettingsTableViewController.swift index 6ea155d..8347abf 100644 --- a/pass/Controllers/GeneralSettingsTableViewController.swift +++ b/pass/Controllers/GeneralSettingsTableViewController.swift @@ -6,8 +6,8 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class GeneralSettingsTableViewController: BasicStaticTableViewController { let passwordStore = PasswordStore.shared @@ -67,37 +67,35 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { override func viewDidLoad() { tableData = [ // section 0 - [[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"],], + [[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"]], // section 1 [ - [.title: "RememberPgpKeyPassphrase".localize(), .action: "none",], - [.title: "RememberGitCredentialPassphrase".localize(), .action: "none",], + [.title: "RememberPgpKeyPassphrase".localize(), .action: "none"], + [.title: "RememberGitCredentialPassphrase".localize(), .action: "none"], ], - + // section 2 [ - [.title: "ShowFolders".localize(), .action: "none",], - [.title: "HidePasswordImages".localize(), .action: "none",], - [.title: "HideUnknownFields".localize(), .action: "none",], - [.title: "HideOtpFields".localize(), .action: "none",], + [.title: "ShowFolders".localize(), .action: "none"], + [.title: "HidePasswordImages".localize(), .action: "none"], + [.title: "HideUnknownFields".localize(), .action: "none"], + [.title: "HideOtpFields".localize(), .action: "none"], ], - ] super.viewDidLoad() - } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = super.tableView(tableView, cellForRowAt: indexPath) + let cell = super.tableView(tableView, cellForRowAt: indexPath) switch cell.textLabel!.text! { case "HideUnknownFields".localize(): cell.accessoryType = .none let detailButton = UIButton(type: .detailDisclosure) - hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height) + hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height) detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height) detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideUnknownSwitchDetailButton(_:)), for: UIControl.Event.touchDown) - let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width+10, height: hideUnknownSwitch.bounds.height)) + let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width + 10, height: hideUnknownSwitch.bounds.height)) accessoryView.addSubview(detailButton) accessoryView.addSubview(hideUnknownSwitch) cell.accessoryView = accessoryView @@ -106,10 +104,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { case "HideOtpFields".localize(): cell.accessoryType = .none let detailButton = UIButton(type: .detailDisclosure) - hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height) + hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height) detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height) detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideOTPSwitchDetailButton(_:)), for: UIControl.Event.touchDown) - let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width+10, height: hideOTPSwitch.bounds.height)) + let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width + 10, height: hideOTPSwitch.bounds.height)) accessoryView.addSubview(detailButton) accessoryView.addSubview(hideOTPSwitch) cell.accessoryView = accessoryView @@ -130,10 +128,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { case "HidePasswordImages".localize(): cell.accessoryType = .none let detailButton = UIButton(type: .detailDisclosure) - hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height) + hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height) detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height) detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHidePasswordImagesSwitchDetailButton(_:)), for: UIControl.Event.touchDown) - let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width+10, height: hidePasswordImagesSwitch.bounds.height)) + let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width + 10, height: hidePasswordImagesSwitch.bounds.height)) accessoryView.addSubview(detailButton) accessoryView.addSubview(hidePasswordImagesSwitch) cell.accessoryView = accessoryView @@ -144,43 +142,50 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { return cell } - @objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) { + @objc + func tapHideUnknownSwitchDetailButton(_: Any?) { let alertMessage = "HideUnknownFieldsExplanation.".localize() let alertTitle = "HideUnknownFields".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } - @objc func tapHideOTPSwitchDetailButton(_ sender: Any?) { + @objc + func tapHideOTPSwitchDetailButton(_: Any?) { let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ", ") let alertMessage = "HideOtpFieldsExplanation.".localize(keywordsString) let alertTitle = "HideOtpFields".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } - @objc func tapHidePasswordImagesSwitchDetailButton(_ sender: Any?) { + @objc + func tapHidePasswordImagesSwitchDetailButton(_: Any?) { let alertMessage = "HidePasswordImagesExplanation.".localize() let alertTitle = "HidePasswordImages".localize() Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil) } - @objc func hideUnknownSwitchAction(_ sender: Any?) { + @objc + func hideUnknownSwitchAction(_: Any?) { Defaults.isHideUnknownOn = hideUnknownSwitch.isOn NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil) } - @objc func hideOTPSwitchAction(_ sender: Any?) { + @objc + func hideOTPSwitchAction(_: Any?) { Defaults.isHideOTPOn = hideOTPSwitch.isOn NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil) } - @objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) { + @objc + func rememberPGPPassphraseSwitchAction(_: Any?) { Defaults.isRememberPGPPassphraseOn = rememberPGPPassphraseSwitch.isOn if rememberPGPPassphraseSwitch.isOn == false { AppKeychain.shared.removeAllContent(withPrefix: Globals.pgpKeyPassphrase) } } - @objc func rememberGitCredentialPassphraseSwitchAction(_ sender: Any?) { + @objc + func rememberGitCredentialPassphraseSwitchAction(_: Any?) { Defaults.isRememberGitCredentialPassphraseOn = rememberGitCredentialPassphraseSwitch.isOn if rememberGitCredentialPassphraseSwitch.isOn == false { passwordStore.gitSSHPrivateKeyPassphrase = nil @@ -188,14 +193,15 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController { } } - @objc func showFolderSwitchAction(_ sender: Any?) { + @objc + func showFolderSwitchAction(_: Any?) { Defaults.isShowFolderOn = showFolderSwitch.isOn NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil) } - @objc func hidePasswordImagesSwitchAction(_ sender: Any?) { + @objc + func hidePasswordImagesSwitchAction(_: Any?) { Defaults.isHidePasswordImagesOn = hidePasswordImagesSwitch.isOn NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil) } - } diff --git a/pass/Controllers/GitConfigSettingsTableViewController.swift b/pass/Controllers/GitConfigSettingsTableViewController.swift index 9a02af5..9a49081 100644 --- a/pass/Controllers/GitConfigSettingsTableViewController.swift +++ b/pass/Controllers/GitConfigSettingsTableViewController.swift @@ -6,14 +6,14 @@ // Copyright © 2017 Yishi Lin. All rights reserved. // -import UIKit import passKit +import UIKit class GitConfigSettingsTableViewController: UITableViewController { let passwordStore = PasswordStore.shared - @IBOutlet weak var nameTextField: UITextField! - @IBOutlet weak var emailTextField: UITextField! + @IBOutlet var nameTextField: UITextField! + @IBOutlet var emailTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() @@ -26,7 +26,7 @@ class GitConfigSettingsTableViewController: UITableViewController { emailTextField.text = Defaults.gitSignatureEmail } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { + override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { if identifier == "saveGitConfigSettingSegue" { let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text! let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text! @@ -38,4 +38,3 @@ class GitConfigSettingsTableViewController: UITableViewController { return true } } - diff --git a/pass/Controllers/GitRepositorySettingsTableViewController.swift b/pass/Controllers/GitRepositorySettingsTableViewController.swift index 1e10023..b8232a9 100644 --- a/pass/Controllers/GitRepositorySettingsTableViewController.swift +++ b/pass/Controllers/GitRepositorySettingsTableViewController.swift @@ -6,21 +6,20 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SVProgressHUD import passKit - +import SVProgressHUD +import UIKit class GitRepositorySettingsTableViewController: UITableViewController { // MARK: - View Outlet - @IBOutlet weak var gitURLTextField: UITextField! - @IBOutlet weak var usernameTextField: UITextField! - @IBOutlet weak var branchNameTextField: UITextField! - @IBOutlet weak var authSSHKeyCell: UITableViewCell! - @IBOutlet weak var authPasswordCell: UITableViewCell! - @IBOutlet weak var gitURLCell: UITableViewCell! - @IBOutlet weak var gitRepositoryURLTabelViewCell: UITableViewCell! + @IBOutlet var gitURLTextField: UITextField! + @IBOutlet var usernameTextField: UITextField! + @IBOutlet var branchNameTextField: UITextField! + @IBOutlet var authSSHKeyCell: UITableViewCell! + @IBOutlet var authPasswordCell: UITableViewCell! + @IBOutlet var gitURLCell: UITableViewCell! + @IBOutlet var gitRepositoryURLTabelViewCell: UITableViewCell! // MARK: - Properties @@ -33,27 +32,29 @@ class GitRepositorySettingsTableViewController: UITableViewController { updateAuthenticationMethodCheckView(for: newValue) } } + private var gitUrl: URL { get { Defaults.gitURL } set { Defaults.gitURL = newValue } } + private var gitBranchName: String { get { Defaults.gitBranchName } set { Defaults.gitBranchName = newValue } } + private var gitUsername: String { get { Defaults.gitUsername } set { Defaults.gitUsername = newValue } } + private var gitCredential: GitCredential { - get { - switch Defaults.gitAuthenticationMethod { - case .password: - return GitCredential(credential: .http(userName: Defaults.gitUsername)) - case .key: - let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? "" - return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey)) - } + switch Defaults.gitAuthenticationMethod { + case .password: + return GitCredential(credential: .http(userName: Defaults.gitUsername)) + case .key: + let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? "" + return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey)) } } @@ -61,9 +62,9 @@ class GitRepositorySettingsTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - gitURLTextField.text = self.gitUrl.absoluteString - usernameTextField.text = self.gitUsername - branchNameTextField.text = self.gitBranchName + gitURLTextField.text = gitUrl.absoluteString + usernameTextField.text = gitUsername + branchNameTextField.text = gitBranchName sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel authSSHKeyCell.accessoryType = .detailButton } @@ -94,7 +95,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) if cell == authPasswordCell { - self.gitAuthenticationMethod = .password + gitAuthenticationMethod = .password } else if cell == authSSHKeyCell { if !AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey()) { Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self) @@ -108,7 +109,8 @@ class GitRepositorySettingsTableViewController: UITableViewController { // MARK: - Segue Handlers - @IBAction func save(_ sender: Any) { + @IBAction + func save(_: Any) { guard let gitURLTextFieldText = gitURLTextField.text, let gitURL = URL(string: gitURLTextFieldText.trimmed) else { Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self) return @@ -137,9 +139,9 @@ class GitRepositorySettingsTableViewController: UITableViewController { } } - self.gitUrl = gitURL - self.gitBranchName = branchName.trimmed - self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed + gitUrl = gitURL + gitBranchName = branchName.trimmed + gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed if passwordStore.repositoryExists() { let overwriteAlert: UIAlertController = { @@ -150,7 +152,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { alert.addAction(UIAlertAction.cancel()) return alert }() - self.present(overwriteAlert, animated: true) + present(overwriteAlert, animated: true) } else { cloneAndSegueIfSuccess() } @@ -159,15 +161,15 @@ class GitRepositorySettingsTableViewController: UITableViewController { private func cloneAndSegueIfSuccess() { // Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone. Defaults.isRememberGitCredentialPassphraseOn = true - DispatchQueue.global(qos: .userInitiated).async() { + DispatchQueue.global(qos: .userInitiated).async { do { - let transferProgressBlock: (UnsafePointer, UnsafeMutablePointer) -> Void = { (git_transfer_progress, _) in + let transferProgressBlock: (UnsafePointer, UnsafeMutablePointer) -> Void = { git_transfer_progress, _ in let gitTransferProgress = git_transfer_progress.pointee let progress = Float(gitTransferProgress.received_objects) / Float(gitTransferProgress.total_objects) SVProgressHUD.showProgress(progress, status: "Cloning Remote Repository") } - let checkoutProgressBlock: (String, UInt, UInt) -> Void = { (_, completedSteps, totalSteps) in + let checkoutProgressBlock: (String, UInt, UInt) -> Void = { _, completedSteps, totalSteps in let progress = Float(completedSteps) / Float(totalSteps) SVProgressHUD.showProgress(progress, status: "CheckingOutBranch".localize(self.gitBranchName)) } @@ -179,7 +181,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { transferProgressBlock: transferProgressBlock, checkoutProgressBlock: checkoutProgressBlock) - SVProgressHUD.dismiss() { + SVProgressHUD.dismiss { let savePassphraseAlert: UIAlertController = { let alert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: .alert) alert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in @@ -188,7 +190,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { self.passwordStore.gitSSHPrivateKeyPassphrase = nil self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) }) - alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) {_ in + alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in Defaults.isRememberGitCredentialPassphraseOn = true self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) }) @@ -199,7 +201,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { } } } catch { - SVProgressHUD.dismiss() { + SVProgressHUD.dismiss { let error = error as NSError var message = error.localizedDescription if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError { @@ -213,7 +215,8 @@ class GitRepositorySettingsTableViewController: UITableViewController { } } - @IBAction func importSSHKey(segue: UIStoryboardSegue) { + @IBAction + func importSSHKey(segue: UIStoryboardSegue) { guard let sourceController = segue.source as? KeyImporter, sourceController.isReadyToUse() else { return } @@ -278,7 +281,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { } private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? { - return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self) + requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self) } private func updateAuthenticationMethodCheckView(for method: GitAuthenticationMethod) { @@ -297,21 +300,20 @@ class GitRepositorySettingsTableViewController: UITableViewController { private func showGitURLFormatHelp() { let message = """ - https://example.com[:port]/project.git - ssh://[user@]server[:port]/project.git - [user@]server:project.git (no scheme) - """ + https://example.com[:port]/project.git + ssh://[user@]server[:port]/project.git + [user@]server:project.git (no scheme) + """ Utils.alert(title: "Git URL Format", message: message, controller: self) } } extension GitRepositorySettingsTableViewController: KeyImporter { - static let keySource = KeySource.itunes static let label = "ITunesFileSharing".localize() func isReadyToUse() -> Bool { - return KeyFileManager.PrivateSsh.doesKeyFileExist() + KeyFileManager.PrivateSsh.doesKeyFileExist() } func importKeys() throws { diff --git a/pass/Controllers/KeyImporter.swift b/pass/Controllers/KeyImporter.swift index 61a9623..8e8635c 100644 --- a/pass/Controllers/KeyImporter.swift +++ b/pass/Controllers/KeyImporter.swift @@ -9,7 +9,6 @@ import passKit protocol KeyImporter { - static var keySource: KeySource { get } static var label: String { get } @@ -24,9 +23,8 @@ protocol KeyImporter { } extension KeyImporter { - static var isCurrentKeySource: Bool { - return Defaults.gitSSHKeySource == Self.keySource + Defaults.gitSSHKeySource == Self.keySource } static var menuLabel: String { diff --git a/pass/Controllers/OpenSourceComponentsTableViewController.swift b/pass/Controllers/OpenSourceComponentsTableViewController.swift index edf1819..5f2bbde 100644 --- a/pass/Controllers/OpenSourceComponentsTableViewController.swift +++ b/pass/Controllers/OpenSourceComponentsTableViewController.swift @@ -6,11 +6,10 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import SafariServices +import UIKit class OpenSourceComponentsTableViewController: BasicStaticTableViewController { - private static let openSourceComponents = [ ["FavIcon", "https://github.com/bitserf/FavIcon", @@ -48,12 +47,13 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController { .link: item[1], .accessoryType: UITableViewCell.AccessoryType.detailDisclosureButton, .detailDisclosureAction: #selector(actOnDetailDisclosureButton(_:)), - .detailDisclosureData: item[2] + .detailDisclosureData: item[2], ]) } } - @objc func actOnDetailDisclosureButton(_ sender: Any?) { + @objc + func actOnDetailDisclosureButton(_ sender: Any?) { if let link = sender as? String, let url = URL(string: link) { let svc = SFSafariViewController(url: url, entersReaderIfAvailable: false) present(svc, animated: true) diff --git a/pass/Controllers/PGPKeyArmorImportTableViewController.swift b/pass/Controllers/PGPKeyArmorImportTableViewController.swift index 36e353a..e4063ef 100644 --- a/pass/Controllers/PGPKeyArmorImportTableViewController.swift +++ b/pass/Controllers/PGPKeyArmorImportTableViewController.swift @@ -6,15 +6,14 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate { - - @IBOutlet weak var armorPublicKeyTextView: UITextView! - @IBOutlet weak var armorPrivateKeyTextView: UITextView! - @IBOutlet weak var scanPublicKeyCell: UITableViewCell! - @IBOutlet weak var scanPrivateKeyCell: UITableViewCell! + @IBOutlet var armorPublicKeyTextView: UITextView! + @IBOutlet var armorPrivateKeyTextView: UITextView! + @IBOutlet var scanPublicKeyCell: UITableViewCell! + @IBOutlet var scanPrivateKeyCell: UITableViewCell! var armorPublicKey: String? var armorPrivateKey: String? @@ -23,45 +22,47 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, enum KeyType { case publicKey, privateKey } + var keyType = KeyType.publicKey var segments = [String]() var message = "" func reset(keytype: KeyType) { - self.keyType = keytype - self.segments.removeAll() + keyType = keytype + segments.removeAll() message = "LookingForStartingFrame.".localize() } func addSegment(segment: String) -> (accept: Bool, message: String) { - let keyTypeStr = self.keyType == .publicKey ? "Public" : "Private" - let theOtherKeyTypeStr = self.keyType == .publicKey ? "Private" : "Public" - + let keyTypeStr = keyType == .publicKey ? "Public" : "Private" + let theOtherKeyTypeStr = keyType == .publicKey ? "Private" : "Public" + // Skip duplicated segments. - guard segment != self.segments.last else { - return (accept: false, message: self.message) + guard segment != segments.last else { + return (accept: false, message: message) } // Check whether we have found the first block. - guard !self.segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else { + guard !segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else { // Check whether we are scanning the wrong key type. if segment.contains("-----BEGIN PGP \(theOtherKeyTypeStr.uppercased()) KEY BLOCK-----") { - self.message = "Scan\(keyTypeStr)Key.".localize() + message = "Scan\(keyTypeStr)Key.".localize() } - return (accept: false, message: self.message) + return (accept: false, message: message) } - + // Update the list of scanned segment and return. - self.segments.append(segment) + segments.append(segment) if segment.contains("-----END PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") { - self.message = "Done".localize() - return (accept: true, message: self.message) + message = "Done".localize() + return (accept: true, message: message) } else { - self.message = "ScannedQrCodes(%d)".localize(self.segments.count) - return (accept: false, message: self.message) + message = "ScannedQrCodes(%d)".localize(segments.count) + return (accept: false, message: message) } } } + var scanned = ScannedPGPKey() override func viewDidLoad() { @@ -76,13 +77,14 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, scanPrivateKeyCell?.accessoryType = .disclosureIndicator } - @IBAction func save(_ sender: Any) { + @IBAction + func save(_: Any) { armorPublicKey = armorPublicKeyTextView.text armorPrivateKey = armorPrivateKeyTextView.text - self.saveImportedKeys() + saveImportedKeys() } - func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool { if text == UIPasteboard.general.string { // user pastes something, do the copy here again and clear the pasteboard in 45s SecurePasteboard.shared.copy(textToCopy: text) @@ -94,21 +96,23 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPublicKeyCell { scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey) - self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self) + performSegue(withIdentifier: "showPGPScannerSegue", sender: self) } else if selectedCell == scanPrivateKeyCell { scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey) - self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self) + performSegue(withIdentifier: "showPGPScannerSegue", sender: self) } tableView.deselectRow(at: indexPath, animated: true) } // MARK: - QRScannerControllerDelegate Methods + func checkScannedOutput(line: String) -> (accept: Bool, message: String) { return scanned.addSegment(segment: line) } // MARK: - QRScannerControllerDelegate Methods - func handleScannedOutput(line: String) { + + func handleScannedOutput(line _: String) { let key = scanned.segments.joined(separator: "") switch scanned.keyType { case .publicKey: @@ -118,7 +122,7 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, } } - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { if segue.identifier == "showPGPScannerSegue" { if let navController = segue.destination as? UINavigationController { if let viewController = navController.topViewController as? QRScannerController { @@ -132,7 +136,6 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, } extension PGPKeyArmorImportTableViewController: PGPKeyImporter { - static let keySource = KeySource.armor static let label = "AsciiArmorEncryptedKey".localize() diff --git a/pass/Controllers/PGPKeyFIleImportTableViewController.swift b/pass/Controllers/PGPKeyFIleImportTableViewController.swift index 5016fda..ac16040 100644 --- a/pass/Controllers/PGPKeyFIleImportTableViewController.swift +++ b/pass/Controllers/PGPKeyFIleImportTableViewController.swift @@ -9,18 +9,18 @@ import passKit class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController { + @IBOutlet var pgpPublicKeyFile: UITableViewCell! + @IBOutlet var pgpPrivateKeyFile: UITableViewCell! - @IBOutlet weak var pgpPublicKeyFile: UITableViewCell! - @IBOutlet weak var pgpPrivateKeyFile: UITableViewCell! - - private var publicKey: String? = nil - private var privateKey: String? = nil + private var publicKey: String? + private var privateKey: String? private enum KeyType { case none, `private`, `public` } private var currentlyPicking = KeyType.none - @IBAction func save(_ sender: Any) { - self.saveImportedKeys() + @IBAction + func save(_: Any) { + saveImportedKeys() } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -43,7 +43,6 @@ class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController { } extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate { - func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) { guard let url = url.first else { return @@ -78,12 +77,11 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate { } extension PGPKeyFileImportTableViewController: PGPKeyImporter { - static let keySource = KeySource.file static let label = "LoadFromFiles".localize() func isReadyToUse() -> Bool { - return validate(key: publicKey) && validate(key: privateKey) + validate(key: publicKey) && validate(key: privateKey) } func importKeys() throws { diff --git a/pass/Controllers/PGPKeyImporter.swift b/pass/Controllers/PGPKeyImporter.swift index 8f60dd0..e7b6744 100644 --- a/pass/Controllers/PGPKeyImporter.swift +++ b/pass/Controllers/PGPKeyImporter.swift @@ -9,19 +9,15 @@ import passKit protocol PGPKeyImporter: KeyImporter { - func doAfterImport() func saveImportedKeys() } extension PGPKeyImporter { - static var isCurrentKeySource: Bool { - return Defaults.pgpKeySource == Self.keySource + Defaults.pgpKeySource == Self.keySource } - func doAfterImport() { - - } + func doAfterImport() {} } diff --git a/pass/Controllers/PGPKeyUrlImportTableViewController.swift b/pass/Controllers/PGPKeyUrlImportTableViewController.swift index 86a25cb..7ada0d3 100644 --- a/pass/Controllers/PGPKeyUrlImportTableViewController.swift +++ b/pass/Controllers/PGPKeyUrlImportTableViewController.swift @@ -6,13 +6,12 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController { - - @IBOutlet weak var pgpPublicKeyURLTextField: UITextField! - @IBOutlet weak var pgpPrivateKeyURLTextField: UITextField! + @IBOutlet var pgpPublicKeyURLTextField: UITextField! + @IBOutlet var pgpPrivateKeyURLTextField: UITextField! var pgpPrivateKeyURL: URL? var pgpPublicKeyURL: URL? @@ -22,31 +21,31 @@ class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController { pgpPublicKeyURLTextField.text = Defaults.pgpPublicKeyURL?.absoluteString pgpPrivateKeyURLTextField.text = Defaults.pgpPrivateKeyURL?.absoluteString } - - @IBAction func save(_ sender: Any) { + + @IBAction + func save(_: Any) { guard let publicKeyURLText = pgpPublicKeyURLTextField.text, let publicKeyURL = URL(string: publicKeyURLText), let privateKeyURLText = pgpPrivateKeyURLTextField.text, let privateKeyURL = URL(string: privateKeyURLText) else { - Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self) - return + Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self) + return } if privateKeyURL.scheme?.lowercased() == "http" || publicKeyURL.scheme?.lowercased() == "http" { Utils.alert(title: "HttpNotSecure".localize(), message: "ReallyUseHttp.".localize(), controller: self) } pgpPrivateKeyURL = privateKeyURL pgpPublicKeyURL = publicKeyURL - self.saveImportedKeys() + saveImportedKeys() } } extension PGPKeyUrlImportTableViewController: PGPKeyImporter { - static let keySource = KeySource.url static let label = "DownloadFromUrl".localize() func isReadyToUse() -> Bool { - return validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "") + validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "") && validate(pgpKeyUrl: pgpPrivateKeyURLTextField.text ?? "") } diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift index 9c8d949..5b64a18 100644 --- a/pass/Controllers/PasswordDetailTableViewController.swift +++ b/pass/Controllers/PasswordDetailTableViewController.swift @@ -6,16 +6,16 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import FavIcon -import SVProgressHUD import passKit +import SVProgressHUD +import UIKit class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate { var passwordEntity: PasswordEntity? private var password: Password? private var passwordImage: UIImage? - private var oneTimePasswordIndexPath : IndexPath? + private var oneTimePasswordIndexPath: IndexPath? private var shouldPopCurrentView = false private let passwordStore = PasswordStore.shared private let keychain = AppKeychain.shared @@ -52,7 +52,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni tableView.addGestureRecognizer(tapGesture) tapGesture.delegate = self - tableView.contentInset = UIEdgeInsets.init(top: -36, left: 0, bottom: 44, right: 0); + tableView.contentInset = UIEdgeInsets(top: -36, left: 0, bottom: 44, right: 0) tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 52 @@ -66,8 +66,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni let image = UIImage(data: imageData as Data) passwordImage = image } - self.decryptThenShowPassword() - self.setupOneTimePasswordAutoRefresh() + decryptThenShowPassword() + setupOneTimePasswordAutoRefresh() // pop the current view because this password might be "discarded" NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil) @@ -78,16 +78,17 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni override func viewDidAppear(_ animated: Bool) { super.viewWillAppear(animated) - if self.shouldPopCurrentView { + if shouldPopCurrentView { let alert = UIAlertController(title: "Notice".localize(), message: "PreviousChangesDiscarded.".localize(), preferredStyle: UIAlertController.Style.alert) alert.addAction(UIAlertAction.okAndPopView(controller: self)) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } } - @objc private func decryptThenShowPassword(keyID: String? = nil) { + @objc + private func decryptThenShowPassword(keyID: String? = nil) { guard let passwordEntity = passwordEntity else { - Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: {(UIAlertAction) -> Void in + Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: { (_) -> Void in self.navigationController!.popViewController(animated: true) }) return @@ -98,7 +99,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self) self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) self.showPassword() - } catch AppError.PgpPrivateKeyNotFound(let key) { + } catch let AppError.PgpPrivateKeyNotFound(key) { DispatchQueue.main.async { // alert: cancel or try again let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) @@ -115,7 +116,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // alert: cancel or try again let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) - alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) {_ in + alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in self.decryptThenShowPassword() }) self.present(alert, animated: true, completion: nil) @@ -141,14 +142,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni private func setupOneTimePasswordAutoRefresh() { Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { - [weak self] timer in + [weak self] _ in // bail out of the timer code if the object has been freed guard let strongSelf = self, let otpType = strongSelf.password?.otpType, otpType != .none, let indexPath = strongSelf.oneTimePasswordIndexPath, let cell = strongSelf.tableView.cellForRow(at: indexPath) as? LabelTableViewCell else { - return + return } switch otpType { case .totp: @@ -163,64 +164,67 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } - @objc private func pressEdit(_ sender: Any?) { + @objc + private func pressEdit(_: Any?) { performSegue(withIdentifier: "editPasswordSegue", sender: self) } - @objc private func setShouldPopCurrentView() { - self.shouldPopCurrentView = true + @objc + private func setShouldPopCurrentView() { + shouldPopCurrentView = true } - @IBAction private func cancelEditPassword(segue: UIStoryboardSegue) { + @IBAction + private func cancelEditPassword(segue _: UIStoryboardSegue) {} - } - - @IBAction private func saveEditPassword(segue: UIStoryboardSegue) { - if self.password!.changed != 0 { - self.saveEditPassword(password: self.password!) + @IBAction + private func saveEditPassword(segue _: UIStoryboardSegue) { + if password!.changed != 0 { + saveEditPassword(password: password!) } } private func saveEditPassword(password: Password, keyID: String? = nil) { SVProgressHUD.show(withStatus: "Saving".localize()) do { - self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: password, keyID: keyID) - self.setTableData() - self.tableView.reloadData() + passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password, keyID: keyID) + setTableData() + tableView.reloadData() SVProgressHUD.showSuccess(withStatus: "Success".localize()) SVProgressHUD.dismiss(withDelay: 1) - } catch AppError.PgpPublicKeyNotFound(let key) { - DispatchQueue.main.async { - // alert: cancel or select keys - SVProgressHUD.dismiss() - let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) - let selectKey = UIAlertAction.selectKey(controller: self) { action in - self.saveEditPassword(password: password, keyID: action.title) - } - alert.addAction(selectKey) + } catch let AppError.PgpPublicKeyNotFound(key) { + DispatchQueue.main.async { + // alert: cancel or select keys + SVProgressHUD.dismiss() + let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) + alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) + let selectKey = UIAlertAction.selectKey(controller: self) { action in + self.saveEditPassword(password: password, keyID: action.title) + } + alert.addAction(selectKey) - self.present(alert, animated: true, completion: nil) - } - return - } catch { - DispatchQueue.main.async { - Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) - } - } + self.present(alert, animated: true, completion: nil) + } + return + } catch { + DispatchQueue.main.async { + Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) + } + } } - @IBAction private func deletePassword(segue: UIStoryboardSegue) { + @IBAction + private func deletePassword(segue _: UIStoryboardSegue) { do { try passwordStore.delete(passwordEntity: passwordEntity!) } catch { Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil) } - let _ = navigationController?.popViewController(animated: true) + _ = navigationController?.popViewController(animated: true) } private func setTableData() { - self.tableData = Array() + tableData = [TableSection]() // name section var section = TableSection(type: .name) @@ -239,7 +243,6 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni section.item.append(Constants.PASSWORD_KEYWORD => password.password) tableData.append(section) - // addition section // show one time password @@ -254,7 +257,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // show additional information let filteredAdditionKeys = password.getFilteredAdditions() - if filteredAdditionKeys.count > 0 { + if !filteredAdditionKeys.isEmpty { section = TableSection(type: .addition, header: "Additions".localize()) section.item.append(contentsOf: filteredAdditionKeys) tableData.append(section) @@ -264,10 +267,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni section = TableSection(type: .misc) section.item.append(AdditionField(title: "ShowRaw".localize())) tableData.append(section) - } - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { if segue.identifier == "editPasswordSegue" { if let controller = segue.destination as? UINavigationController { if let editController = controller.viewControllers.first as? EditPasswordTableViewController { @@ -288,9 +290,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni if urlString.lowercased().hasPrefix("http://") { // try to replace http url to https url newUrlString = urlString.replacingOccurrences(of: "http://", - with: "https://", - options: .caseInsensitive, - range: urlString.range(of: "http://")) + with: "https://", + options: .caseInsensitive, + range: urlString.range(of: "http://")) } else if urlString.lowercased().hasPrefix("https://") { // do nothing here } else { @@ -311,11 +313,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } - @objc private func tapMenu(recognizer: UITapGestureRecognizer) { + @objc + private func tapMenu(recognizer: UITapGestureRecognizer) { if recognizer.state == UIGestureRecognizer.State.ended { - let tapLocation = recognizer.location(in: self.tableView) - if let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation) { - if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell { + let tapLocation = recognizer.location(in: tableView) + if let tapIndexPath = tableView.indexPathForRow(at: tapLocation) { + if let tappedCell = tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell { tappedCell.becomeFirstResponder() let menuController = UIMenuController.shared let revealItem = UIMenuItem(title: "Reveal".localize(), action: #selector(LabelTableViewCell.revealPassword(_:))) @@ -330,22 +333,22 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } - func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { + func gestureRecognizer(_: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if touch.view!.isKind(of: UIButton.classForCoder()) { return false } return true } - @IBAction func back(segue:UIStoryboardSegue) { - } + @IBAction + func back(segue _: UIStoryboardSegue) {} func getNextHOTP() { guard password != nil, passwordEntity != nil, password?.otpType == .hotp else { DispatchQueue.main.async { Utils.alert(title: "Error".localize(), message: "GetNextPasswordOfNonHotp.".localize(), controller: self, completion: nil) } - return; + return } // copy HOTP to pasteboard (will update counter) @@ -356,7 +359,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni // commit the change of HOTP counter if password!.changed != 0 { do { - self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!) + passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password!) SVProgressHUD.showSuccess(withStatus: "PasswordCopied".localize() | "CounterUpdated".localize()) SVProgressHUD.dismiss(withDelay: 1) } catch { @@ -384,19 +387,19 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni return from } - override func numberOfSections(in tableView: UITableView) -> Int { - return tableData.count + override func numberOfSections(in _: UITableView) -> Int { + tableData.count } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return tableData[section].item.count + override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + tableData[section].item.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let sectionIndex = indexPath.section let rowIndex = indexPath.row let tableDataItem = tableData[sectionIndex].item[rowIndex] - switch(tableData[sectionIndex].type) { + switch tableData[sectionIndex].type { case .name: let cell = tableView.dequeueReusableCell(withIdentifier: "passwordDetailTitleTableViewCell", for: indexPath) as! PasswordDetailTitleTableViewCell if !Defaults.isHidePasswordImagesOn { @@ -453,8 +456,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni detailTextLabel.text = "HiddenFields(%d)".localize(numberOfHiddenFields) } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return tableData[section].header + override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { + tableData[section].header } override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { @@ -464,7 +467,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni footerLabel.numberOfLines = 0 footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote) footerLabel.textColor = UIColor.gray - let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path) + let dateString = passwordStore.getLatestUpdateInfo(filename: password!.url.path) footerLabel.text = "LastUpdated".localize(dateString) view.addSubview(footerLabel) return view @@ -472,15 +475,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni return nil } - override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) { + override func tableView(_: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) { if action == #selector(copy(_:)) { SecurePasteboard.shared.copy(textToCopy: tableData[indexPath.section].item[indexPath.row].content) } } - override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool { + override func tableView(_: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) -> Bool { let section = tableData[indexPath.section] - switch(section.type) { + switch section.type { case .main, .addition: return action == #selector(UIResponderStandardEditActions.copy(_:)) default: @@ -488,8 +491,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni } } - override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { - return true + override func tableView(_: UITableView, shouldShowMenuForRowAt _: IndexPath) -> Bool { + true } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift index 7575ebc..284a77a 100644 --- a/pass/Controllers/PasswordEditorTableViewController.swift +++ b/pass/Controllers/PasswordEditorTableViewController.swift @@ -6,10 +6,10 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SafariServices import OneTimePassword import passKit +import SafariServices +import UIKit enum PasswordEditorCellType: Equatable { case nameCell @@ -30,18 +30,16 @@ enum PasswordEditorCellKey { } protocol PasswordSettingSliderTableViewCellDelegate { - func generateAndCopyPassword() } class PasswordEditorTableViewController: UITableViewController { - - var tableData = [[Dictionary]]() + var tableData = [[[PasswordEditorCellKey: Any]]]() var password: Password? private var navigationItemTitle: String? - private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(),""].map {$0.uppercased()} + private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(), ""].map { $0.uppercased() } private var sectionFooterTitles = ["", "", "UseKeyValueFormat.".localize(), ""] private let nameSection = 0 private let passwordSection = 1 @@ -86,7 +84,7 @@ class PasswordEditorTableViewController: UITableViewController { passwordFlavorCell?.textLabel?.text = "PasswordGeneratorFlavor".localize() passwordFlavorCell?.selectionStyle = .none - let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map { $0.localized }) + let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map(\.localized)) passwordFlavorSelector.selectedSegmentIndex = PasswordGeneratorFlavor.allCases.firstIndex(of: passwordGenerator.flavor)! passwordFlavorSelector.addTarget(self, action: #selector(flavorChanged), for: .valueChanged) passwordFlavorCell?.accessoryView = passwordFlavorSelector @@ -126,11 +124,11 @@ class PasswordEditorTableViewController: UITableViewController { ], [ [.type: PasswordEditorCellType.scanQRCodeCell], - ] + ], ] - - if self.password != nil { - tableData[additionsSection+1].append([.type: PasswordEditorCellType.deletePasswordCell]) + + if password != nil { + tableData[additionsSection + 1].append([.type: PasswordEditorCellType.deletePasswordCell]) } updateTableData(withRespectTo: passwordGenerator.flavor) } @@ -206,11 +204,11 @@ class PasswordEditorTableViewController: UITableViewController { } } - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return 44 + override func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { + 44 } - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + override func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { switch tableData[indexPath.section][indexPath.row][PasswordEditorCellKey.type] as! PasswordEditorCellType { case .passwordLengthCell, .passwordGroupsCell: return 42 @@ -221,11 +219,11 @@ class PasswordEditorTableViewController: UITableViewController { } } - override func numberOfSections(in tableView: UITableView) -> Int { - return tableData.count + override func numberOfSections(in _: UITableView) -> Int { + tableData.count } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { if section == passwordSection, hidePasswordSettings { // hide the password section, only the password should be shown return 1 @@ -234,27 +232,27 @@ class PasswordEditorTableViewController: UITableViewController { } } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return sectionHeaderTitles[section] + override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { + sectionHeaderTitles[section] } - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return sectionFooterTitles[section] + override func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? { + sectionFooterTitles[section] } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCell = tableView.cellForRow(at: indexPath) tableView.deselectRow(at: indexPath, animated: true) - + if selectedCell == deletePasswordCell { let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in + alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in self.performSegue(withIdentifier: "deletePasswordSegue", sender: self) })) alert.addAction(UIAlertAction.cancel()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } else if selectedCell == scanQRCodeCell { - self.performSegue(withIdentifier: "showQRScannerSegue", sender: self) + performSegue(withIdentifier: "showQRScannerSegue", sender: self) } } @@ -276,11 +274,12 @@ class PasswordEditorTableViewController: UITableViewController { } } - private func isPasswordDelimiterCellData(data: Dictionary) -> Bool { - return (data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell) + private func isPasswordDelimiterCellData(data: [PasswordEditorCellKey: Any]) -> Bool { + (data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell) } - @objc func flavorChanged(_ sender: UISegmentedControl) { + @objc + func flavorChanged(_ sender: UISegmentedControl) { let flavor = PasswordGeneratorFlavor.allCases[sender.selectedSegmentIndex] guard passwordGenerator.flavor != flavor else { return @@ -327,7 +326,7 @@ class PasswordEditorTableViewController: UITableViewController { additionsCell?.setContent(content: additionsString) } - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { if segue.identifier == "showQRScannerSegue" { if let navController = segue.destination as? UINavigationController { if let viewController = navController.topViewController as? QRScannerController { @@ -362,8 +361,8 @@ class PasswordEditorTableViewController: UITableViewController { // the name field should be a valid url guard let path = name.stringByAddingPercentEncodingForRFC3986(), var passwordURL = URL(string: path) else { - Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil) - return false + Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil) + return false } // check whether we can parse the filename (be consistent with PasswordStore::addPasswordEntities) @@ -382,20 +381,20 @@ class PasswordEditorTableViewController: UITableViewController { } // MARK: - FillPasswordTableViewCellDelegate -extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate { +extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate { // generate password, copy to pasteboard, and set the cell // check whether the current password looks like an OTP field func generateAndCopyPassword() { if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) { let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: {_ in + alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: { _ in self.generateAndCopyPasswordNoOtpCheck() })) alert.addAction(UIAlertAction.cancel()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } else { - self.generateAndCopyPasswordNoOtpCheck() + generateAndCopyPasswordNoOtpCheck() } } @@ -407,11 +406,12 @@ extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate { } // MARK: - PasswordSettingSliderTableViewCellDelegate + extension PasswordEditorTableViewController: PasswordSettingSliderTableViewCellDelegate {} // MARK: - QRScannerControllerDelegate -extension PasswordEditorTableViewController: QRScannerControllerDelegate { +extension PasswordEditorTableViewController: QRScannerControllerDelegate { func checkScannedOutput(line: String) -> (accept: Bool, message: String) { if let url = URL(string: line), let _ = Token(url: url) { return (accept: true, message: "ValidTokenUrl".localize()) @@ -426,31 +426,31 @@ extension PasswordEditorTableViewController: QRScannerControllerDelegate { } // MARK: - SFSafariViewControllerDelegate -extension PasswordEditorTableViewController: SFSafariViewControllerDelegate { - func safariViewControllerDidFinish(_ controller: SFSafariViewController) { - let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty }) +extension PasswordEditorTableViewController: SFSafariViewControllerDelegate { + func safariViewControllerDidFinish(_: SFSafariViewController) { + let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter { !$0.isEmpty } if copiedLinesSplit?.count ?? 0 > 0 { let generatedPassword = copiedLinesSplit![0] let alert = UIAlertController(title: "WannaUseIt?".localize(), message: "", preferredStyle: UIAlertController.Style.alert) let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\n") message.append(Utils.attributedPassword(plainPassword: generatedPassword)) alert.setValue(message, forKey: "attributedMessage") - alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: {[unowned self] (action) -> Void in + alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { [unowned self] (_) -> Void in // update tableData so to make sure reloadData() works correctly self.tableData[self.passwordSection][0][PasswordEditorCellKey.content] = generatedPassword // update cell manually, no need to call reloadData() self.fillPasswordCell?.setContent(content: generatedPassword) })) alert.addAction(UIAlertAction.cancel()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } } } // MARK: - UITextFieldDelegate -extension PasswordEditorTableViewController: UITextFieldDelegate { +extension PasswordEditorTableViewController: UITextFieldDelegate { // update tableData so to make sure reloadData() works correctly func textFieldDidEndEditing(_ textField: UITextField) { if textField == nameCell?.contentTextField { @@ -471,8 +471,8 @@ extension PasswordEditorTableViewController: UITextFieldDelegate { } // MARK: - UITextViewDelegate -extension PasswordEditorTableViewController: UITextViewDelegate { +extension PasswordEditorTableViewController: UITextViewDelegate { // update tableData so to make sure reloadData() works correctly func textViewDidEndEditing(_ textView: UITextView) { if textView == additionsCell?.contentTextView { diff --git a/pass/Controllers/PasswordsViewController.swift b/pass/Controllers/PasswordsViewController.swift index 0ad0ae9..8c1c20b 100644 --- a/pass/Controllers/PasswordsViewController.swift +++ b/pass/Controllers/PasswordsViewController.swift @@ -6,16 +6,16 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SVProgressHUD import passKit +import SVProgressHUD +import UIKit -fileprivate let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold +private let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold class PasswordsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITabBarControllerDelegate, UISearchBarDelegate { private var passwordsTableEntries: [PasswordTableEntry] = [] private var passwordsTableAllEntries: [PasswordTableEntry] = [] - private var parentPasswordEntity: PasswordEntity? = nil + private var parentPasswordEntity: PasswordEntity? private let passwordStore = PasswordStore.shared private let keychain = AppKeychain.shared @@ -30,14 +30,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private var gitCredential: GitCredential { - get { - switch Defaults.gitAuthenticationMethod { - case .password: - return GitCredential(credential: .http(userName: Defaults.gitUsername)) - case .key: - let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? "" - return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey)) - } + switch Defaults.gitAuthenticationMethod { + case .password: + return GitCredential(credential: .http(userName: Defaults.gitUsername)) + case .key: + let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? "" + return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey)) } } @@ -49,11 +47,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV uiSearchController.searchBar.sizeToFit() return uiSearchController }() + private lazy var syncControl: UIRefreshControl = { let syncControl = UIRefreshControl() syncControl.addTarget(self, action: #selector(handleRefresh(_:)), for: UIControl.Event.valueChanged) return syncControl }() + private lazy var searchBarView: UIView? = { guard #available(iOS 11, *) else { let uiView = UIView(frame: CGRect(x: 0, y: 64, width: self.view.bounds.width, height: 44)) @@ -62,6 +62,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } return nil }() + private lazy var backUIBarButtonItem: UIBarButtonItem = { let backUIButton = UIButton(type: .system) if #available(iOS 13.0, *) { @@ -116,28 +117,29 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV return transition }() - @IBOutlet weak var tableView: UITableView! + @IBOutlet var tableView: UITableView! private func initPasswordsTableEntries(parent: PasswordEntity?) { - let passwordAllEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false) + let passwordAllEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false) passwordsTableAllEntries = passwordAllEntities.compactMap { PasswordTableEntry($0) } - + let passwordEntities = Defaults.isShowFolderOn ? - self.passwordStore.fetchPasswordEntityCoreData(parent: parent) : + passwordStore.fetchPasswordEntityCoreData(parent: parent) : passwordAllEntities passwordsTableEntries = passwordEntities.compactMap { PasswordTableEntry($0) } - + parentPasswordEntity = parent } - @IBAction func cancelAddPassword(segue: UIStoryboardSegue) { + @IBAction + func cancelAddPassword(segue _: UIStoryboardSegue) {} - } - @IBAction func saveAddPassword(segue: UIStoryboardSegue) { + @IBAction + func saveAddPassword(segue: UIStoryboardSegue) { if let controller = segue.source as? AddPasswordTableViewController { addPassword(password: controller.password!) } @@ -149,13 +151,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV SVProgressHUD.show(withStatus: "Saving".localize()) DispatchQueue.global(qos: .userInitiated).async { do { - let _ = try self.passwordStore.add(password: password, keyID: keyID) + _ = try self.passwordStore.add(password: password, keyID: keyID) DispatchQueue.main.async { // will trigger reloadTableView() by a notification SVProgressHUD.showSuccess(withStatus: "Done".localize()) SVProgressHUD.dismiss(withDelay: 1) } - } catch AppError.PgpPublicKeyNotFound(let key) { + } catch let AppError.PgpPublicKeyNotFound(key) { DispatchQueue.main.async { // alert: cancel or select keys SVProgressHUD.dismiss() @@ -190,15 +192,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { - try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: {(git_transfer_progress, stop) in + try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: { git_transfer_progress, _ in DispatchQueue.main.async { - SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize()) + SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize()) } }) if self.passwordStore.numberOfLocalCommits > 0 { - try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: {(current, total, bytes, stop) in + try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: { current, total, _, _ in DispatchQueue.main.async { - SVProgressHUD.showProgress(Float(current)/Float(total), status: "PushingToRemoteRepository".localize()) + SVProgressHUD.showProgress(Float(current) / Float(total), status: "PushingToRemoteRepository".localize()) } }) } @@ -232,7 +234,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV super.viewDidAppear(animated) if Defaults.isShowFolderOn { - searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map { $0.localizedName } + searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map(\.localizedName) } else { searchController.searchBar.scopeButtonTitles = nil } @@ -251,7 +253,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV navigationItem.hidesSearchBarWhenScrolling = false } else { // Fallback on earlier versions - tableView.contentInset = UIEdgeInsets.init(top: 44, left: 0, bottom: 0, right: 0) + tableView.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: 0, right: 0) view.addSubview(searchBarView!) } navigationItem.title = "PasswordStore".localize() @@ -272,16 +274,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: UIApplication.willEnterForegroundNotification, object: nil) // listen to the swipe back guesture - let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture)) + let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture)) swipeRight.direction = UISwipeGestureRecognizer.Direction.right - self.view.addGestureRecognizer(swipeRight) + view.addGestureRecognizer(swipeRight) } - @objc func didTapNavigationBar(_ sender: UITapGestureRecognizer) { - let location = sender.location(in: self.navigationController?.navigationBar) - let hitView = self.navigationController?.navigationBar.hitTest(location, with: nil) + @objc + func didTapNavigationBar(_ sender: UITapGestureRecognizer) { + let location = sender.location(in: navigationController?.navigationBar) + let hitView = navigationController?.navigationBar.hitTest(location, with: nil) guard !(hitView is UIControl) else { return } - guard (passwordStore.numberOfLocalCommits != 0) else { return } + guard passwordStore.numberOfLocalCommits != 0 else { return } let ac = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let allAction = UIAlertAction(title: "All Passwords", style: .default) { _ in @@ -289,7 +292,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } let unsyncedAction = UIAlertAction(title: "Unsynced Passwords", style: .default) { _ in let filteredPasswordsTableEntries = self.passwordsTableEntries.filter { entry in - return !entry.synced + !entry.synced } self.reloadTableView(data: filteredPasswordsTableEntries, label: .unsynced) } @@ -299,7 +302,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV ac.addAction(unsyncedAction) ac.addAction(cancelAction) - self.present(ac, animated: true, completion: nil) + present(ac, animated: true, completion: nil) } override func viewWillAppear(_ animated: Bool) { @@ -310,7 +313,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } // Add gesture recognizer to the navigation bar when the view is about to appear - self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer) + navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer) // This allows controlls in the navigation bar to continue receiving touches tapNavigationBarGestureRecognizer.cancelsTouchesInView = false @@ -318,9 +321,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV tableView.refreshControl = passwordStore.repositoryExists() ? syncControl : nil } - override func viewWillDisappear(_ animated: Bool) { + override func viewWillDisappear(_: Bool) { // Remove gesture recognizer from navigation bar when view is about to disappear - self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer) + navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer) } override func viewWillLayoutSubviews() { @@ -332,12 +335,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } - func numberOfSections(in tableView: UITableView) -> Int { - return sections.count + func numberOfSections(in _: UITableView) -> Int { + sections.count } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return sections[section].entries.count + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + sections[section].entries.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -372,7 +375,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private func getPasswordEntry(by indexPath: IndexPath) -> PasswordTableEntry { - return sections[indexPath.section].entries[indexPath.row] + sections[indexPath.section].entries[indexPath.row] } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -390,16 +393,18 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } - @objc func respondToSwipeGesture(gesture: UIGestureRecognizer) { + @objc + func respondToSwipeGesture(gesture: UIGestureRecognizer) { if let swipeGesture = gesture as? UISwipeGestureRecognizer { // swipe right -> swipe back - if swipeGesture.direction == .right && parentPasswordEntity != nil { - self.backAction(nil) + if swipeGesture.direction == .right, parentPasswordEntity != nil { + backAction(nil) } } } - @objc func backAction(_ sender: Any?) { + @objc + func backAction(_: Any?) { guard Defaults.isShowFolderOn else { return } var anim: CATransition? = transitionFromLeft if parentPasswordEntity == nil { @@ -408,13 +413,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV reloadTableView(parent: parentPasswordEntity?.parent, anim: anim) } - @objc func addPasswordAction(_ sender: Any?) { + @objc + func addPasswordAction(_: Any?) { if shouldPerformSegue(withIdentifier: "addPasswordSegue", sender: self) { performSegue(withIdentifier: "addPasswordSegue", sender: self) } } - @objc func longPressAction(_ gesture: UILongPressGestureRecognizer) { + @objc + func longPressAction(_ gesture: UILongPressGestureRecognizer) { if gesture.state == UIGestureRecognizer.State.began { let touchPoint = gesture.location(in: tableView) if let indexPath = tableView.indexPathForRow(at: touchPoint) { @@ -424,31 +431,31 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private func hideSectionHeader() -> Bool { - if passwordsTableEntries.count < hideSectionHeaderThreshold || self.searchController.isActive { + if passwordsTableEntries.count < hideSectionHeaderThreshold || searchController.isActive { return true } return false } - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { if hideSectionHeader() { return nil } return sections[section].title } - func sectionIndexTitles(for tableView: UITableView) -> [String]? { + func sectionIndexTitles(for _: UITableView) -> [String]? { if hideSectionHeader() { return nil } - return sections.map { $0.title } + return sections.map(\.title) } - func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - return index + func tableView(_: UITableView, sectionForSectionIndexTitle _: String, at index: Int) -> Int { + index } - func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { + func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { decryptThenCopyPassword(from: indexPath) } @@ -460,7 +467,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity UIImpactFeedbackGenerator(style: .medium).impactOccurred() SVProgressHUD.dismiss() - self.decryptPassword(passwordEntity: passwordEntity) + decryptPassword(passwordEntity: passwordEntity) } private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) { @@ -476,7 +483,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize()) SVProgressHUD.dismiss(withDelay: 0.6) } - } catch AppError.PgpPrivateKeyNotFound(let key) { + } catch let AppError.PgpPrivateKeyNotFound(key) { DispatchQueue.main.async { // alert: cancel or try again let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) @@ -488,7 +495,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV self.present(alert, animated: true) } - } catch { + } catch { DispatchQueue.main.async { Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self) } @@ -496,14 +503,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } - private func generateSections(item: [PasswordTableEntry]) { let collation = UILocalizedIndexedCollation.current() let sectionTitles = collation.sectionIndexTitles var newSections = [(title: String, entries: [PasswordTableEntry])]() // initialize all sections - for i in 0.. 0} + sections = newSections.filter { !$0.entries.isEmpty } } - @objc func actOnSearchNotification() { + @objc + func actOnSearchNotification() { searchController.searchBar.becomeFirstResponder() } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if identifier == "showPasswordDetail" { guard PGPAgent.shared.isPrepared else { @@ -540,7 +546,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV return false } } else if identifier == "addPasswordSegue" { - guard PGPAgent.shared.isPrepared && self.passwordStore.storeRepository != nil else { + guard PGPAgent.shared.isPrepared && passwordStore.storeRepository != nil else { Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil) return false } @@ -551,7 +557,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showPasswordDetail" { if let viewController = segue.destination as? PasswordDetailTableViewController { - let selectedIndexPath = self.tableView.indexPath(for: sender as! UITableViewCell)! + let selectedIndexPath = tableView.indexPath(for: sender as! UITableViewCell)! let passwordEntity = getPasswordEntry(by: selectedIndexPath).passwordEntity viewController.passwordEntity = passwordEntity } @@ -568,8 +574,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV func filterContentForSearchText(searchText: String, scope: SearchBarScope = .all) { var entries: [PasswordTableEntry] = scope == .all ? passwordsTableAllEntries : passwordsTableEntries - if searchController.isActive && searchController.searchBar.text != "" { - entries = entries.filter {$0.match(searchText)} + if searchController.isActive, searchController.searchBar.text != "" { + entries = entries.filter { $0.match(searchText) } } reloadTableView(data: entries) } @@ -587,7 +593,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV if #available(iOS 11, *) { navigationController?.navigationBar.prefersLargeTitles = false } - self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer) + navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer) } else { navigationItem.leftBarButtonItem = nil switch label { @@ -599,17 +605,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV if #available(iOS 11, *) { navigationController?.navigationBar.prefersLargeTitles = true } - self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer) + navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer) } navigationItem.rightBarButtonItem = addPasswordUIBarButtonItem // set the password table generateSections(item: data) if anim != nil { - self.tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey") + tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey") } tableView.reloadData() - self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey") + tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey") // set the sync control title let atribbutedTitle = "LastSynced".localize() + ": \(lastSyncedTimeString())" @@ -617,7 +623,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private func lastSyncedTimeString() -> String { - guard let date = self.passwordStore.lastSyncedTime else { + guard let date = passwordStore.lastSyncedTime else { return "SyncAgain?".localize() } let formatter = DateFormatter() @@ -631,7 +637,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV reloadTableView(data: passwordsTableEntries, label: label, anim: anim) } - @objc func actOnReloadTableViewRelatedNotification() { + @objc + func actOnReloadTableViewRelatedNotification() { DispatchQueue.main.async { [weak weakSelf = self] in guard let strongSelf = weakSelf else { return } // Reset selectedScopeButtonIndex to make sure the correct reloadTableView @@ -641,36 +648,37 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } } - @objc func handleRefresh(_ syncControl: UIRefreshControl) { + @objc + func handleRefresh(_: UIRefreshControl) { syncPasswords() } - func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { - if viewController == self.navigationController { + func tabBarController(_: UITabBarController, didSelect viewController: UIViewController) { + if viewController == navigationController { let currentTime = Date().timeIntervalSince1970 - let duration = currentTime - self.tapTabBarTime - self.tapTabBarTime = currentTime + let duration = currentTime - tapTabBarTime + tapTabBarTime = currentTime if duration < 0.35 { let topIndexPath = IndexPath(row: 0, section: 0) - if tableView.numberOfSections > 0 { - tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true) - } - self.tapTabBarTime = 0 + if tableView.numberOfSections > 0 { + tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true) + } + tapTabBarTime = 0 return } backAction(self) } } - func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { + func searchBar(_: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { // update the default search scope Defaults.searchDefault = SearchBarScope(rawValue: selectedScope) updateSearchResults(for: searchController) } - func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { + func searchBarShouldBeginEditing(_: UISearchBar) -> Bool { // set the default search scope to "all" - if Defaults.isShowFolderOn && Defaults.searchDefault == .all { + if Defaults.isShowFolderOn, Defaults.searchDefault == .all { searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.all.rawValue } else { searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue @@ -678,7 +686,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV return true } - func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool { + func searchBarShouldEndEditing(_: UISearchBar) -> Bool { // set the default search scope to "current" searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue updateSearchResults(for: searchController) @@ -686,13 +694,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? { - return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self) + requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self) } - } extension PasswordsViewController: UISearchResultsUpdating { - func updateSearchResults(for searchController: UISearchController) { let scope = SearchBarScope(rawValue: searchController.searchBar.selectedScopeButtonIndex) ?? .all filterContentForSearchText(searchText: searchController.searchBar.text!, scope: scope) @@ -700,8 +706,7 @@ extension PasswordsViewController: UISearchResultsUpdating { } extension PasswordsViewController: CAAnimationDelegate { - - func animationDidStart(_ anim: CAAnimation) { + func animationDidStart(_: CAAnimation) { view.window?.backgroundColor = Colors.systemBackground view.layer.backgroundColor = Colors.systemBackground.cgColor } diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift index 2f33b71..0ee9453 100644 --- a/pass/Controllers/QRScannerController.swift +++ b/pass/Controllers/QRScannerController.swift @@ -6,11 +6,11 @@ // Copyright © 2017 Yishi Lin. All rights reserved. // -import UIKit import AVFoundation import OneTimePassword -import SVProgressHUD import passKit +import SVProgressHUD +import UIKit protocol QRScannerControllerDelegate { func checkScannedOutput(line: String) -> (accept: Bool, message: String) @@ -18,8 +18,7 @@ protocol QRScannerControllerDelegate { } class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { - - @IBOutlet weak var scannerOutput: UILabel! + @IBOutlet var scannerOutput: UILabel! var captureSession: AVCaptureSession? var videoPreviewLayer: AVCaptureVideoPreviewLayer? @@ -93,15 +92,12 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg // Dispose of any resources that can be recreated. } - // MARK: - AVCaptureMetadataOutputObjectsDelegate Methods - func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { - + func metadataOutput(_: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from _: AVCaptureConnection) { if let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject, supportedCodeTypes.contains(metadataObj.type), let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) { - // draw a bounds on the found QR code qrCodeFrameView?.frame = barCodeObject.bounds diff --git a/pass/Controllers/RawPasswordViewController.swift b/pass/Controllers/RawPasswordViewController.swift index 0a8bdce..41e3462 100644 --- a/pass/Controllers/RawPasswordViewController.swift +++ b/pass/Controllers/RawPasswordViewController.swift @@ -6,12 +6,11 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class RawPasswordViewController: UIViewController { - - @IBOutlet weak var rawPasswordTextView: UITextView! + @IBOutlet var rawPasswordTextView: UITextView! var password: Password? override func viewDidLoad() { diff --git a/pass/Controllers/SSHKeyArmorImportTableViewController.swift b/pass/Controllers/SSHKeyArmorImportTableViewController.swift index 15c286f..bae3bc1 100644 --- a/pass/Controllers/SSHKeyArmorImportTableViewController.swift +++ b/pass/Controllers/SSHKeyArmorImportTableViewController.swift @@ -6,13 +6,12 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate { - - @IBOutlet weak var armorPrivateKeyTextView: UITextView! - @IBOutlet weak var scanPrivateKeyCell: UITableViewCell! + @IBOutlet var armorPrivateKeyTextView: UITextView! + @IBOutlet var scanPrivateKeyCell: UITableViewCell! var gitSSHPrivateKeyPassphrase: String? var armorPrivateKey: String? @@ -22,32 +21,33 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, var message = "" func reset() { - self.segments.removeAll() + segments.removeAll() message = "LookingForStartingFrame.".localize() } func addSegment(segment: String) -> (accept: Bool, message: String) { // Skip duplicated segments. - guard segment != self.segments.last else { - return (accept: false, message: self.message) + guard segment != segments.last else { + return (accept: false, message: message) } - + // Check whether we have found the first block. - guard !self.segments.isEmpty || segment.contains("-----BEGIN") else { - return (accept: false, message: self.message) + guard !segments.isEmpty || segment.contains("-----BEGIN") else { + return (accept: false, message: message) } - + // Update the list of scanned segment and return. - self.segments.append(segment) + segments.append(segment) if segment.range(of: "-----END.*KEY-----", options: .regularExpression, range: nil, locale: nil) != nil { - self.message = "Done".localize() - return (accept: true, message: self.message) + message = "Done".localize() + return (accept: true, message: message) } else { - self.message = "ScannedQrCodes(%d)".localize(self.segments.count) - return (accept: false, message: self.message) + message = "ScannedQrCodes(%d)".localize(segments.count) + return (accept: false, message: message) } } } + var scanned = ScannedSSHKey() override func viewDidLoad() { @@ -59,12 +59,13 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, scanPrivateKeyCell?.accessoryType = .disclosureIndicator } - @IBAction func doneButtonTapped(_ sender: Any) { + @IBAction + func doneButtonTapped(_: Any) { armorPrivateKey = armorPrivateKeyTextView.text performSegue(withIdentifier: "importSSHKeySegue", sender: self) } - func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool { if text == UIPasteboard.general.string { // user pastes something, do the copy here again and clear the pasteboard in 45s SecurePasteboard.shared.copy(textToCopy: text) @@ -76,23 +77,24 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, let selectedCell = tableView.cellForRow(at: indexPath) if selectedCell == scanPrivateKeyCell { scanned.reset() - self.performSegue(withIdentifier: "showSSHScannerSegue", sender: self) + performSegue(withIdentifier: "showSSHScannerSegue", sender: self) } tableView.deselectRow(at: indexPath, animated: true) } - // MARK: - QRScannerControllerDelegate Methods + func checkScannedOutput(line: String) -> (accept: Bool, message: String) { return scanned.addSegment(segment: line) } // MARK: - QRScannerControllerDelegate Methods - func handleScannedOutput(line: String) { + + func handleScannedOutput(line _: String) { armorPrivateKeyTextView.text = scanned.segments.joined(separator: "") } - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { if segue.identifier == "showSSHScannerSegue" { if let navController = segue.destination as? UINavigationController { if let viewController = navController.topViewController as? QRScannerController { @@ -104,13 +106,11 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, } } - @IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) { - - } + @IBAction + private func cancelSSHScanner(segue _: UIStoryboardSegue) {} } extension SSHKeyArmorImportTableViewController: KeyImporter { - static let keySource = KeySource.armor static let label = "AsciiArmorEncryptedKey".localize() diff --git a/pass/Controllers/SSHKeyFileImportTableViewController.swift b/pass/Controllers/SSHKeyFileImportTableViewController.swift index 47f126e..4b6fb8f 100644 --- a/pass/Controllers/SSHKeyFileImportTableViewController.swift +++ b/pass/Controllers/SSHKeyFileImportTableViewController.swift @@ -10,12 +10,12 @@ import passKit import SVProgressHUD class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController { + @IBOutlet var sshPrivateKeyFile: UITableViewCell! - @IBOutlet weak var sshPrivateKeyFile: UITableViewCell! + private var privateKey: String? - private var privateKey: String? = nil - - @IBAction func doneButtonTapped(_ sender: Any) { + @IBAction + func doneButtonTapped(_: Any) { performSegue(withIdentifier: "importSSHKeySegue", sender: self) } @@ -35,7 +35,6 @@ class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController { } extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate { - func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) { guard let url = url.first else { return @@ -61,7 +60,6 @@ extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate { } extension SSHKeyFileImportTableViewController: KeyImporter { - static let keySource = KeySource.file static let label = "LoadFromFiles".localize() diff --git a/pass/Controllers/SSHKeyUrlImportTableViewController.swift b/pass/Controllers/SSHKeyUrlImportTableViewController.swift index 4e09ac2..2fb83b6 100644 --- a/pass/Controllers/SSHKeyUrlImportTableViewController.swift +++ b/pass/Controllers/SSHKeyUrlImportTableViewController.swift @@ -6,12 +6,11 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import SVProgressHUD import passKit +import SVProgressHUD class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController { - - @IBOutlet weak var privateKeyURLTextField: UITextField! + @IBOutlet var privateKeyURLTextField: UITextField! var sshPrivateKeyURL: URL? @@ -20,11 +19,12 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController { privateKeyURLTextField.text = Defaults.gitSSHPrivateKeyURL?.absoluteString } - @IBAction func doneButtonTapped(_ sender: UIButton) { + @IBAction + func doneButtonTapped(_: UIButton) { guard let text = privateKeyURLTextField.text, let privateKeyURL = URL(string: text) else { - Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self) - return + Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self) + return } if privateKeyURL.scheme?.lowercased() == "http" { @@ -41,7 +41,6 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController { } extension SSHKeyUrlImportTableViewController: KeyImporter { - static let keySource = KeySource.url static let label = "DownloadFromUrl".localize() diff --git a/pass/Controllers/SettingsSplitViewController.swift b/pass/Controllers/SettingsSplitViewController.swift index 1ac4e54..153a267 100644 --- a/pass/Controllers/SettingsSplitViewController.swift +++ b/pass/Controllers/SettingsSplitViewController.swift @@ -10,15 +10,16 @@ import UIKit class SettingsSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { - self.delegate = self - self.preferredDisplayMode = .allVisible + delegate = self + preferredDisplayMode = .allVisible } func splitViewController( - _ splitViewController: UISplitViewController, - collapseSecondary secondaryViewController: UIViewController, - onto primaryViewController: UIViewController) -> Bool { + _: UISplitViewController, + collapseSecondary _: UIViewController, + onto _: UIViewController + ) -> Bool { // Return true to prevent UIKit from applying its default behavior - return true + true } } diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index a761085..f98be35 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -6,26 +6,27 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SVProgressHUD import CoreData import passKit +import SVProgressHUD +import UIKit class SettingsTableViewController: UITableViewController, UITabBarControllerDelegate { - @IBOutlet weak var pgpKeyTableViewCell: UITableViewCell! - @IBOutlet weak var passcodeTableViewCell: UITableViewCell! - @IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell! + @IBOutlet var pgpKeyTableViewCell: UITableViewCell! + @IBOutlet var passcodeTableViewCell: UITableViewCell! + @IBOutlet var passwordRepositoryTableViewCell: UITableViewCell! var setPasscodeLockAlert: UIAlertController? let passwordStore = PasswordStore.shared let keychain = AppKeychain.shared var passcodeLock = PasscodeLock.shared - func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { + func tabBarController(_: UITabBarController, didSelect _: UIViewController) { navigationController?.popViewController(animated: true) } - @IBAction func savePGPKey(segue: UIStoryboardSegue) { + @IBAction + func savePGPKey(segue: UIStoryboardSegue) { guard let sourceController = segue.source as? PGPKeyImporter, sourceController.isReadyToUse() else { return } @@ -58,19 +59,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele } } - @IBAction func saveGitServerSetting(segue: UIStoryboardSegue) { - self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host + @IBAction + func saveGitServerSetting(segue _: UIStoryboardSegue) { + passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host } override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil) - self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host + passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host setPGPKeyTableViewCellDetailText() setPasscodeLockCell() } - override func viewWillAppear(_ animated: Bool) { + override func viewWillAppear(_: Bool) { super.viewWillAppear(true) tabBarController!.delegate = self setPasswordRepositoryTableViewCellDetailText() @@ -78,9 +80,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele private func setPasscodeLockCell() { if passcodeLock.hasPasscode { - self.passcodeTableViewCell.detailTextLabel?.text = "On".localize() + passcodeTableViewCell.detailTextLabel?.text = "On".localize() } else { - self.passcodeTableViewCell.detailTextLabel?.text = "Off".localize() + passcodeTableViewCell.detailTextLabel?.text = "Off".localize() } } @@ -107,7 +109,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele passwordRepositoryTableViewCell.detailTextLabel?.text = host } - @objc func actOnPasswordStoreErasedNotification() { + @objc + func actOnPasswordStoreErasedNotification() { setPGPKeyTableViewCellDetailText() setPasswordRepositoryTableViewCellDetailText() setPasscodeLockCell() @@ -180,9 +183,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let passcodeRemoveViewController = PasscodeLockViewController() - let removePasscodeAction = UIAlertAction(title: "RemovePasscode".localize(), style: .destructive) { [weak self] _ in - passcodeRemoveViewController.successCallback = { + passcodeRemoveViewController.successCallback = { self?.passcodeLock.delete() self?.setPasscodeLockCell() } @@ -198,10 +200,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele optionMenu.addAction(UIAlertAction.cancel()) optionMenu.popoverPresentationController?.sourceView = passcodeTableViewCell optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds - self.present(optionMenu, animated: true, completion: nil) + present(optionMenu, animated: true, completion: nil) } - @objc func alertTextFieldDidChange(_ sender: UITextField) { + @objc + func alertTextFieldDidChange(_ sender: UITextField) { // check whether we should enable the Save button in setPasscodeLockAlert if let setPasscodeLockAlert = self.setPasscodeLockAlert, let setPasscodeLockAlertTextFields0 = setPasscodeLockAlert.textFields?[0], @@ -218,25 +221,25 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele func setPasscodeLock() { // prepare the alert for setting the passcode setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert) - setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in + setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in textField.placeholder = "Passcode".localize() textField.isSecureTextEntry = true textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) }) - setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in + setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in textField.placeholder = "PasswordConfirmation".localize() textField.isSecureTextEntry = true textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) }) // save action - let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (action:UIAlertAction) -> Void in + let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (_: UIAlertAction) -> Void in let passcode: String = self.setPasscodeLockAlert!.textFields![0].text! self.passcodeLock.save(passcode: passcode) // refresh the passcode lock cell ("On") self.setPasscodeLockCell() } - saveAction.isEnabled = false // disable the Save button by default + saveAction.isEnabled = false // disable the Save button by default // cancel action let cancelAction = UIAlertAction.cancel() @@ -244,17 +247,16 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele // present setPasscodeLockAlert?.addAction(saveAction) setPasscodeLockAlert?.addAction(cancelAction) - self.present(setPasscodeLockAlert!, animated: true, completion: nil) + present(setPasscodeLockAlert!, animated: true, completion: nil) } } extension SettingsTableViewController: PGPKeyImporter { - static let keySource = KeySource.itunes static let label = "ITunesFileSharing".localize() func isReadyToUse() -> Bool { - return KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist() + KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist() } func importKeys() throws { diff --git a/pass/Controllers/SpecialThanksTableViewController.swift b/pass/Controllers/SpecialThanksTableViewController.swift index baec567..130ad5f 100644 --- a/pass/Controllers/SpecialThanksTableViewController.swift +++ b/pass/Controllers/SpecialThanksTableViewController.swift @@ -18,7 +18,7 @@ class SpecialThanksTableViewController: BasicStaticTableViewController { "https://icons8.com"], ["FlatIcon", "https://www.flaticon.com"], - ] + ] override func viewDidLoad() { tableData.append([]) diff --git a/pass/Helpers/GitCredentialPassword.swift b/pass/Helpers/GitCredentialPassword.swift index c07beef..5ba21f3 100644 --- a/pass/Helpers/GitCredentialPassword.swift +++ b/pass/Helpers/GitCredentialPassword.swift @@ -7,12 +7,12 @@ // import Foundation -import SVProgressHUD import passKit +import SVProgressHUD public func requestGitCredentialPassword(credential: GitCredential.Credential, - lastPassword: String?, - controller: UIViewController) -> String? { + lastPassword: String?, + controller: UIViewController) -> String? { let sem = DispatchSemaphore(value: 0) var password: String? let message: String = { @@ -27,21 +27,21 @@ public func requestGitCredentialPassword(credential: GitCredential.Credential, DispatchQueue.main.async { SVProgressHUD.dismiss() let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: .alert) - alert.addTextField() { + alert.addTextField { $0.text = lastPassword ?? "" $0.isSecureTextEntry = true } - alert.addAction(UIAlertAction.ok() { _ in + alert.addAction(UIAlertAction.ok { _ in password = alert.textFields?.first?.text sem.signal() }) - alert.addAction(UIAlertAction.cancel() { _ in + alert.addAction(UIAlertAction.cancel { _ in password = nil sem.signal() }) controller.present(alert, animated: true) } - let _ = sem.wait(timeout: .distantFuture) + _ = sem.wait(timeout: .distantFuture) return password } diff --git a/pass/Helpers/SecurePasteboard.swift b/pass/Helpers/SecurePasteboard.swift index 302ca02..e050e1b 100644 --- a/pass/Helpers/SecurePasteboard.swift +++ b/pass/Helpers/SecurePasteboard.swift @@ -25,7 +25,7 @@ class SecurePasteboard { // exit the existing background task, if any if backgroundTaskID != UIBackgroundTaskIdentifier.invalid { UIApplication.shared.endBackgroundTask(UIBackgroundTaskIdentifier.invalid) - self.backgroundTaskID = UIBackgroundTaskIdentifier.invalid + backgroundTaskID = UIBackgroundTaskIdentifier.invalid } backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in @@ -40,5 +40,4 @@ class SecurePasteboard { self?.backgroundTaskID = UIBackgroundTaskIdentifier.invalid } } - } diff --git a/pass/Helpers/UtilsExtension.swift b/pass/Helpers/UtilsExtension.swift index 4112972..d2d0316 100644 --- a/pass/Helpers/UtilsExtension.swift +++ b/pass/Helpers/UtilsExtension.swift @@ -7,8 +7,8 @@ // import Foundation -import SVProgressHUD import passKit +import SVProgressHUD extension Utils { static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) { diff --git a/pass/Views/FillPasswordTableViewCell.swift b/pass/Views/FillPasswordTableViewCell.swift index 442fffb..cff46a6 100644 --- a/pass/Views/FillPasswordTableViewCell.swift +++ b/pass/Views/FillPasswordTableViewCell.swift @@ -6,8 +6,8 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit import passKit +import UIKit protocol FillPasswordTableViewCellDelegate { func generateAndCopyPassword() @@ -15,12 +15,11 @@ protocol FillPasswordTableViewCellDelegate { } class FillPasswordTableViewCell: UITableViewCell, ContentProvider { - - @IBOutlet weak var contentTextField: UITextField! + @IBOutlet var contentTextField: UITextField! var delegate: FillPasswordTableViewCellDelegate? - @IBOutlet weak var settingButton: UIButton! - @IBOutlet weak var generateButton: UIButton! + @IBOutlet var settingButton: UIButton! + @IBOutlet var generateButton: UIButton! override func awakeFromNib() { super.awakeFromNib() @@ -32,21 +31,24 @@ class FillPasswordTableViewCell: UITableViewCell, ContentProvider { generateButton.imageView?.contentMode = .scaleAspectFit } - @IBAction func generatePassword(_ sender: UIButton) { - self.delegate?.generateAndCopyPassword() + @IBAction + func generatePassword(_: UIButton) { + delegate?.generateAndCopyPassword() } - @IBAction func showHidePasswordSettings() { - self.delegate?.showHidePasswordSettings() + @IBAction + func showHidePasswordSettings() { + delegate?.showHidePasswordSettings() } // re-color - @IBAction func textFieldDidChange(_ sender: UITextField) { + @IBAction + func textFieldDidChange(_ sender: UITextField) { contentTextField.attributedText = Utils.attributedPassword(plainPassword: sender.text ?? "") } func getContent() -> String? { - return contentTextField.attributedText?.string + contentTextField.attributedText?.string } func setContent(content: String?) { diff --git a/pass/Views/LabelTableViewCell.swift b/pass/Views/LabelTableViewCell.swift index 33561a0..972349b 100644 --- a/pass/Views/LabelTableViewCell.swift +++ b/pass/Views/LabelTableViewCell.swift @@ -6,9 +6,9 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import UIKit -import SVProgressHUD import passKit +import SVProgressHUD +import UIKit struct LabelTableViewCellData { var title: String @@ -16,9 +16,8 @@ struct LabelTableViewCellData { } class LabelTableViewCell: UITableViewCell { - - @IBOutlet weak var contentLabel: UILabel! - @IBOutlet weak var titleLabel: UILabel! + @IBOutlet var contentLabel: UILabel! + @IBOutlet var titleLabel: UILabel! private enum CellType { case password, URL, HOTP, other @@ -27,7 +26,7 @@ class LabelTableViewCell: UITableViewCell { private var type = CellType.other private var isReveal = false - weak var delegatePasswordTableView : PasswordDetailTableViewController? + weak var delegatePasswordTableView: PasswordDetailTableViewController? private var passwordDisplayButton: UIButton? private var buttons: UIView? @@ -74,12 +73,10 @@ class LabelTableViewCell: UITableViewCell { } override var canBecomeFirstResponder: Bool { - get { - return true - } + true } - override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + override func canPerformAction(_ action: Selector, withSender _: Any?) -> Bool { switch type { case .password: if isReveal { @@ -100,11 +97,12 @@ class LabelTableViewCell: UITableViewCell { } } - override func copy(_ sender: Any?) { + override func copy(_: Any?) { SecurePasteboard.shared.copy(textToCopy: cellData?.content) } - @objc func revealPassword(_ sender: Any?) { + @objc + func revealPassword(_: Any?) { let plainPassword = cellData?.content ?? "" if type == .password { contentLabel.attributedText = Utils.attributedPassword(plainPassword: plainPassword) @@ -115,7 +113,8 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Invisible"), for: .normal) } - @objc func concealPassword(_ sender: Any?) { + @objc + func concealPassword(_: Any?) { if type == .password { if cellData?.content.isEmpty == false { contentLabel.text = Globals.passwordDots @@ -130,7 +129,8 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Visible"), for: .normal) } - @objc func reversePasswordDisplay(_ sender: Any?) { + @objc + func reversePasswordDisplay(_ sender: Any?) { if isReveal { // conceal concealPassword(sender) @@ -140,19 +140,21 @@ class LabelTableViewCell: UITableViewCell { } } - @objc func openLink(_ sender: Any?) { + @objc + func openLink(_: Any?) { // if isURLCell, passwordTableView should not be nil delegatePasswordTableView!.openLink(to: cellData?.content) } - @objc func getNextHOTP(_ sender: Any?) { + @objc + func getNextHOTP(_: 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 height = min(bounds.height, 36.0) let width = max(height * 0.8, Globals.tableCellButtonSize) // margins (between button boundary and icon) @@ -167,7 +169,7 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton!.frame = CGRect(x: 0, y: 0, width: width, height: height) passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal) passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit - passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX) + passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX) passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside) buttons = passwordDisplayButton } @@ -177,7 +179,7 @@ class LabelTableViewCell: UITableViewCell { nextButton.frame = CGRect(x: 0, y: 0, width: width, height: height) nextButton.setImage(#imageLiteral(resourceName: "Refresh"), for: .normal) nextButton.imageView?.contentMode = .scaleAspectFit - nextButton.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX) + nextButton.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX) nextButton.addTarget(self, action: #selector(getNextHOTP), for: UIControl.Event.touchUpInside) // password button @@ -186,7 +188,7 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal) passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit - passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX) + passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX) passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside) buttons = UIView() @@ -197,6 +199,6 @@ class LabelTableViewCell: UITableViewCell { passwordDisplayButton = nil buttons = nil } - self.accessoryView = buttons + accessoryView = buttons } } diff --git a/pass/Views/PasswordDetailTitleTableViewCell.swift b/pass/Views/PasswordDetailTitleTableViewCell.swift index 352cf2f..c45d455 100644 --- a/pass/Views/PasswordDetailTitleTableViewCell.swift +++ b/pass/Views/PasswordDetailTitleTableViewCell.swift @@ -9,13 +9,12 @@ import UIKit class PasswordDetailTitleTableViewCell: UITableViewCell { - @IBOutlet weak var categoryLabel: UILabel! - @IBOutlet weak var nameLabel: UILabel! - @IBOutlet weak var passwordImageImageView: UIImageView! + @IBOutlet var categoryLabel: UILabel! + @IBOutlet var nameLabel: UILabel! + @IBOutlet var passwordImageImageView: UIImageView! @IBOutlet var labelImageConstraint: NSLayoutConstraint! @IBOutlet var labelCellConstraint: NSLayoutConstraint! - override func awakeFromNib() { super.awakeFromNib() } @@ -25,5 +24,4 @@ class PasswordDetailTitleTableViewCell: UITableViewCell { // Configure the view for the selected state } - } diff --git a/pass/Views/SliderTableViewCell.swift b/pass/Views/SliderTableViewCell.swift index a541615..dd3af42 100644 --- a/pass/Views/SliderTableViewCell.swift +++ b/pass/Views/SliderTableViewCell.swift @@ -10,7 +10,6 @@ import passKit import UIKit class SliderTableViewCell: UITableViewCell { - @IBOutlet var titleLabel: UILabel! @IBOutlet var valueLabel: UILabel! @IBOutlet var slider: UISlider! @@ -20,7 +19,8 @@ class SliderTableViewCell: UITableViewCell { private var delegate: PasswordSettingSliderTableViewCellDelegate! - @IBAction func handleSliderValueChange(_ sender: UISlider) { + @IBAction + func handleSliderValueChange(_ sender: UISlider) { let newRoundedValue = Int(sender.value) // Proceed only if the rounded value gets updated. guard checker(newRoundedValue) else { @@ -67,9 +67,8 @@ class SliderTableViewCell: UITableViewCell { } extension SliderTableViewCell: ContentProvider { - func getContent() -> String? { - return nil + nil } func setContent(content _: String?) {} diff --git a/pass/Views/SwitchTableViewCell.swift b/pass/Views/SwitchTableViewCell.swift index c515a22..772b273 100644 --- a/pass/Views/SwitchTableViewCell.swift +++ b/pass/Views/SwitchTableViewCell.swift @@ -10,7 +10,6 @@ import passKit import UIKit class SwitchTableViewCell: UITableViewCell { - @IBOutlet var titleLabel: UILabel! @IBOutlet var controlSwitch: UISwitch! @@ -18,7 +17,8 @@ class SwitchTableViewCell: UITableViewCell { private var delegate: PasswordSettingSliderTableViewCellDelegate! - @IBAction func switchValueChanged(_: Any) { + @IBAction + func switchValueChanged(_: Any) { updater(controlSwitch.isOn) delegate.generateAndCopyPassword() } diff --git a/pass/Views/TextFieldTableViewCell.swift b/pass/Views/TextFieldTableViewCell.swift index 72ee559..3037ff8 100644 --- a/pass/Views/TextFieldTableViewCell.swift +++ b/pass/Views/TextFieldTableViewCell.swift @@ -9,11 +9,10 @@ import UIKit class TextFieldTableViewCell: UITableViewCell, ContentProvider { - - @IBOutlet weak var contentTextField: UITextField! + @IBOutlet var contentTextField: UITextField! func getContent() -> String? { - return contentTextField.text + contentTextField.text } func setContent(content: String?) { diff --git a/pass/Views/TextViewTableViewCell.swift b/pass/Views/TextViewTableViewCell.swift index bd4bdde..6f983c1 100644 --- a/pass/Views/TextViewTableViewCell.swift +++ b/pass/Views/TextViewTableViewCell.swift @@ -9,17 +9,16 @@ import UIKit class TextViewTableViewCell: UITableViewCell, ContentProvider { + @IBOutlet var contentTextView: UITextView! - @IBOutlet weak var contentTextView: UITextView! - override func awakeFromNib() { super.awakeFromNib() - self.contentTextView.textContainer.lineFragmentPadding = 0 - self.contentTextView.textContainerInset = .zero + contentTextView.textContainer.lineFragmentPadding = 0 + contentTextView.textContainerInset = .zero } func getContent() -> String? { - return contentTextView.text + contentTextView.text } func setContent(content: String?) { diff --git a/pass/Views/UICodeHighlightingLabel.swift b/pass/Views/UICodeHighlightingLabel.swift index 2d931b3..f05586b 100644 --- a/pass/Views/UICodeHighlightingLabel.swift +++ b/pass/Views/UICodeHighlightingLabel.swift @@ -6,11 +6,10 @@ Copyright © 2019 Bob Sun. All rights reserved. */ -import UIKit import passKit +import UIKit class UICodeHighlightingLabel: UILocalizedLabel { - private static let CODE_ATTRIBUTES: [NSAttributedString.Key: Any] = [.font: UIFont(name: "Menlo-Regular", size: 12)!] private static let ATTRIBUTED_NEWLINE = NSAttributedString(string: "\n") @@ -43,4 +42,3 @@ class UICodeHighlightingLabel: UILocalizedLabel { return formattedText } } - diff --git a/pass/Views/UILocalizedLabel.swift b/pass/Views/UILocalizedLabel.swift index 6c2b0d1..ba32208 100644 --- a/pass/Views/UILocalizedLabel.swift +++ b/pass/Views/UILocalizedLabel.swift @@ -6,11 +6,10 @@ Copyright © 2019 Bob Sun. All rights reserved. */ -import UIKit import passKit +import UIKit class UILocalizedLabel: UILabel { - override func awakeFromNib() { super.awakeFromNib() text = text?.localize() diff --git a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift index e2e8373..004bf83 100644 --- a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift +++ b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift @@ -10,8 +10,8 @@ import AuthenticationServices import passKit class CredentialProviderViewController: ASCredentialProviderViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate { - @IBOutlet weak var searchBar: UISearchBar! - @IBOutlet weak var tableView: UITableView! + @IBOutlet var searchBar: UISearchBar! + @IBOutlet var tableView: UITableView! private let passwordStore = PasswordStore.shared private let keychain = AppKeychain.shared @@ -26,13 +26,13 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa }() /* - 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 - prioritize the most relevant credentials in the list. - */ + 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 + prioritize the most relevant credentials in the list. + */ override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) { // clean up the search bar - guard serviceIdentifiers.count > 0 else { + guard !serviceIdentifiers.isEmpty else { searchBar.text = "" searchBar.becomeFirstResponder() searchBarSearchButtonClicked(searchBar) @@ -41,7 +41,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa // get the domain var identifier = serviceIdentifiers[0].identifier - if !identifier.hasPrefix("http://") && !identifier.hasPrefix("https://") { + if !identifier.hasPrefix("http://"), !identifier.hasPrefix("https://") { identifier = "http://" + identifier } let url = URL(string: identifier)?.host ?? "" @@ -53,37 +53,38 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } /* - Implement this method if your extension support - s showing credentials in the QuickType bar. - When the user selects a credential from your app, this method will be called with the - ASPasswordCredentialIdentity your app has previously saved to the ASCredentialIdentityStore. - Provide the password by completing the extension request with the associated ASPasswordCredential. - If using the credential would require showing custom UI for authenticating the user, cancel - the request with error code ASExtensionError.userInteractionRequired. + Implement this method if your extension support + s showing credentials in the QuickType bar. + When the user selects a credential from your app, this method will be called with the + ASPasswordCredentialIdentity your app has previously saved to the ASCredentialIdentityStore. + Provide the password by completing the extension request with the associated ASPasswordCredential. + If using the credential would require showing custom UI for authenticating the user, cancel + the request with error code ASExtensionError.userInteractionRequired. - override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) { - let databaseIsUnlocked = true - if (databaseIsUnlocked) { - let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234") - self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil) - } else { - self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue)) - } - } - */ + override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) { + let databaseIsUnlocked = true + if (databaseIsUnlocked) { + let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234") + self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil) + } else { + self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue)) + } + } + */ /* - Implement this method if provideCredentialWithoutUserInteraction(for:) can fail with - ASExtensionError.userInteractionRequired. In this case, the system may present your extension's - UI and call this method. Show appropriate UI for authenticating the user then provide the password - by completing the extension request with the associated ASPasswordCredential. + Implement this method if provideCredentialWithoutUserInteraction(for:) can fail with + ASExtensionError.userInteractionRequired. In this case, the system may present your extension's + UI and call this method. Show appropriate UI for authenticating the user then provide the password + by completing the extension request with the associated ASPasswordCredential. - override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) { - } - */ + override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) { + } + */ - @IBAction func cancel(_ sender: AnyObject?) { - self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) + @IBAction + func cancel(_: AnyObject?) { + extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) } override func viewWillAppear(_ animated: Bool) { @@ -106,8 +107,8 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa private func initPasswordsTableEntries() { filteredPasswordsTableEntries.removeAll() - - let passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false) + + let passwordEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false) passwordsTableEntries = passwordEntities.compactMap { PasswordTableEntry($0) } @@ -129,7 +130,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } // select row -> extension returns (with username and password) - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { let entry = getPasswordEntry(by: indexPath) guard PGPAgent.shared.isPrepared else { @@ -139,7 +140,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa let passwordEntity = entry.passwordEntity UIImpactFeedbackGenerator(style: .medium).impactOccurred() - self.decryptPassword(passwordEntity: passwordEntity) + decryptPassword(passwordEntity: passwordEntity) } private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) { @@ -154,7 +155,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa let passwordCredential = ASPasswordCredential(user: username, password: password) self.extensionContext.completeRequest(withSelectedCredential: passwordCredential) } - } catch AppError.PgpPrivateKeyNotFound(let key) { + } catch let AppError.PgpPrivateKeyNotFound(key) { DispatchQueue.main.async { let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) @@ -173,34 +174,34 @@ class CredentialProviderViewController: ASCredentialProviderViewController, UITa } } - func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return 1 + func numberOfSectionsInTableView(tableView _: UITableView) -> Int { + 1 } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { if searchActive { return filteredPasswordsTableEntries.count } - return passwordsTableEntries.count; + return passwordsTableEntries.count } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" searchActive = false - self.tableView.reloadData() + tableView.reloadData() } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { if let searchText = searchBar.text, searchText.isEmpty == false { - filteredPasswordsTableEntries = passwordsTableEntries.filter {$0.match(searchText)} + filteredPasswordsTableEntries = passwordsTableEntries.filter { $0.match(searchText) } searchActive = true } else { searchActive = false } - self.tableView.reloadData() + tableView.reloadData() } - func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + func searchBar(_ searchBar: UISearchBar, textDidChange _: String) { searchBarSearchButtonClicked(searchBar) } diff --git a/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift b/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift index 6863378..92e5358 100644 --- a/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift +++ b/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift @@ -6,23 +6,26 @@ // Copyright © 2017 Bob Sun. All rights reserved. // +import AuthenticationServices import Foundation import passKit -import AuthenticationServices // cancel means cancel the extension class PasscodeLockViewControllerForExtension: PasscodeLockViewController { var originalExtensionContest: ASCredentialProviderExtensionContext? public convenience init(extensionContext: ASCredentialProviderExtensionContext?) { self.init() - originalExtensionContest = extensionContext + self.originalExtensionContest = extensionContext } + override func viewDidLoad() { super.viewDidLoad() cancelButton?.removeTarget(nil, action: nil, for: .allEvents) cancelButton?.addTarget(self, action: #selector(cancelExtension), for: .touchUpInside) } - @objc func cancelExtension() { + + @objc + func cancelExtension() { originalExtensionContest?.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) } } @@ -34,7 +37,7 @@ class PasscodeExtensionDisplay { public init(extensionContext: ASCredentialProviderExtensionContext?) { self.extensionContext = extensionContext - passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) + self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) passcodeLockVC.dismissCompletionCallback = { [weak self] in self?.dismiss() } @@ -43,14 +46,14 @@ class PasscodeExtensionDisplay { // 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 { + guard PasscodeLock.shared.hasPasscode, !isPasscodePresented == true else { return } isPasscodePresented = true extensionVC.present(passcodeLockVC, animated: true, completion: nil) } - public func dismiss(animated: Bool = true) { + public func dismiss(animated _: Bool = true) { isPasscodePresented = false } } diff --git a/passExtension/Controllers/ExtensionViewController.swift b/passExtension/Controllers/ExtensionViewController.swift index bc39800..1aff5fa 100644 --- a/passExtension/Controllers/ExtensionViewController.swift +++ b/passExtension/Controllers/ExtensionViewController.swift @@ -11,8 +11,8 @@ import MobileCoreServices import passKit class ExtensionViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationBarDelegate { - @IBOutlet weak var searchBar: UISearchBar! - @IBOutlet weak var tableView: UITableView! + @IBOutlet var searchBar: UISearchBar! + @IBOutlet var tableView: UITableView! private let passwordStore = PasswordStore.shared private let keychain = AppKeychain.shared @@ -34,8 +34,8 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV private func initPasswordsTableEntries() { filteredPasswordsTableEntries.removeAll() - - let passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false) + + let passwordEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false) passwordsTableEntries = passwordEntities.map { PasswordTableEntry($0) } @@ -67,11 +67,11 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV for provider in itemProviders { // search using the extensionContext inputs if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) { - provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, error) -> Void in + provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil, completionHandler: { (item, _) -> Void in let dictionary = item as! NSDictionary var url: String? if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String { - if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") { + if !urlString.hasPrefix("http://"), !urlString.hasPrefix("https://") { urlString = "http://" + urlString } url = URL(string: urlString)?.host @@ -84,14 +84,13 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV self?.searchBarSearchButtonClicked((self?.searchBar)!) } }) - } - else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) { - provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { (item, error) -> Void in + } else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) { + provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { (item, _) -> Void in var url: String? if let dictionary = item as? NSDictionary, let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary, var urlString = results[OnePasswordExtensionKey.URLStringKey] as? String { - if !urlString.hasPrefix("http://") && !urlString.hasPrefix("https://") { + if !urlString.hasPrefix("http://"), !urlString.hasPrefix("https://") { urlString = "http://" + urlString } url = URL(string: urlString)?.host @@ -105,7 +104,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } }) } else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) { - provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, error) -> Void in + provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { (item, _) -> Void in let url = (item as? NSURL)!.host DispatchQueue.main.async { [weak self] in self?.extensionAction = .fillBrowser @@ -137,7 +136,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } // select row -> extension returns (with username and password) - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { let entry = getPasswordEntry(by: indexPath) guard PGPAgent.shared.isPrepared else { @@ -147,7 +146,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV let passwordEntity = entry.passwordEntity UIImpactFeedbackGenerator(style: .medium).impactOccurred() - self.decryptPassword(passwordEntity: passwordEntity) + decryptPassword(passwordEntity: passwordEntity) } private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) { @@ -158,7 +157,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV let username = decryptedPassword.getUsernameForCompletion() let password = decryptedPassword.password - DispatchQueue.main.async {// prepare a dictionary to return + DispatchQueue.main.async { // prepare a dictionary to return switch self.extensionAction { case .findLogin: let extensionItem = NSExtensionItem() @@ -173,14 +172,14 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV Utils.copyToPasteboard(textToCopy: decryptedPassword.password) // return a dictionary for JavaScript for best-effor fill in let extensionItem = NSExtensionItem() - let returnDictionary = [NSExtensionJavaScriptFinalizeArgumentKey : ["username": username, "password": password]] + let returnDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: ["username": username, "password": password]] extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))] self.extensionContext?.completeRequest(returningItems: [extensionItem], completionHandler: nil) default: self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } } - } catch AppError.PgpPrivateKeyNotFound(let key) { + } catch let AppError.PgpPrivateKeyNotFound(key) { DispatchQueue.main.async { // alert: cancel or try again let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) @@ -192,7 +191,7 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV self.present(alert, animated: true, completion: nil) } - } catch { + } catch { DispatchQueue.main.async { Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil) } @@ -200,39 +199,39 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } } - - func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return 1 + func numberOfSectionsInTableView(tableView _: UITableView) -> Int { + 1 } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - if searchActive{ + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + if searchActive { return filteredPasswordsTableEntries.count } - return passwordsTableEntries.count; + return passwordsTableEntries.count } - @IBAction func cancelExtension(_ sender: Any) { + @IBAction + func cancelExtension(_: Any) { extensionContext!.completeRequest(returningItems: [], completionHandler: nil) } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" searchActive = false - self.tableView.reloadData() + tableView.reloadData() } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { if let searchText = searchBar.text, searchText.isEmpty == false { - filteredPasswordsTableEntries = passwordsTableEntries.filter {$0.match(searchText)} + filteredPasswordsTableEntries = passwordsTableEntries.filter { $0.match(searchText) } searchActive = true } else { searchActive = false } - self.tableView.reloadData() + tableView.reloadData() } - func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + func searchBar(_ searchBar: UISearchBar, textDidChange _: String) { searchBarSearchButtonClicked(searchBar) } diff --git a/passExtension/Controllers/PasscodeExtensionDisplay.swift b/passExtension/Controllers/PasscodeExtensionDisplay.swift index 88011b8..51160c7 100644 --- a/passExtension/Controllers/PasscodeExtensionDisplay.swift +++ b/passExtension/Controllers/PasscodeExtensionDisplay.swift @@ -14,14 +14,17 @@ class PasscodeLockViewControllerForExtension: PasscodeLockViewController { var originalExtensionContest: NSExtensionContext? public convenience init(extensionContext: NSExtensionContext?) { self.init() - originalExtensionContest = extensionContext + self.originalExtensionContest = extensionContext } + override func viewDidLoad() { super.viewDidLoad() cancelButton?.removeTarget(nil, action: nil, for: .allEvents) cancelButton?.addTarget(self, action: #selector(cancelExtension), for: .touchUpInside) } - @objc func cancelExtension() { + + @objc + func cancelExtension() { originalExtensionContest?.completeRequest(returningItems: [], completionHandler: nil) } } @@ -33,7 +36,7 @@ class PasscodeExtensionDisplay { public init(extensionContext: NSExtensionContext?) { self.extensionContext = extensionContext - passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) + self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) passcodeLockVC.dismissCompletionCallback = { [weak self] in self?.dismiss() } @@ -42,14 +45,14 @@ class PasscodeExtensionDisplay { // 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 { + guard PasscodeLock.shared.hasPasscode, !isPasscodePresented == true else { return } isPasscodePresented = true extensionVC.present(passcodeLockVC, animated: true, completion: nil) } - public func dismiss(animated: Bool = true) { + public func dismiss(animated _: Bool = true) { isPasscodePresented = false } } diff --git a/passExtension/Crypto/GopenPGPInterface.swift b/passExtension/Crypto/GopenPGPInterface.swift index 3614a7a..118a5d2 100644 --- a/passExtension/Crypto/GopenPGPInterface.swift +++ b/passExtension/Crypto/GopenPGPInterface.swift @@ -9,10 +9,9 @@ import Crypto struct GopenPGPInterface: PGPInterface { - private static let errorMapping: [String: Error] = [ - "gopenpgp: error in unlocking key: openpgp: invalid data: private key checksum failure": AppError.WrongPassphrase, - "openpgp: incorrect key": AppError.KeyExpiredOrIncompatible, + "gopenpgp: error in unlocking key: openpgp: invalid data: private key checksum failure": AppError.WrongPassphrase, + "openpgp: incorrect key": AppError.KeyExpiredOrIncompatible, ] private var publicKeys: [String: CryptoKey] = [:] @@ -43,26 +42,25 @@ struct GopenPGPInterface: PGPInterface { } privateKeys[k.getFingerprint().lowercased()] = k } - } func extractKeysFromArmored(str: String) -> [String] { - var keys: [String] = [] - var key: String = "" - for line in str.splitByNewline() { - if line.trimmed.uppercased().hasPrefix("-----BEGIN PGP") { - key = "" - key += line - } else if line.trimmed.uppercased().hasPrefix("-----END PGP") { - key += line - keys.append(key) - } else { - key += line - } + var keys: [String] = [] + var key: String = "" + for line in str.splitByNewline() { + if line.trimmed.uppercased().hasPrefix("-----BEGIN PGP") { + key = "" + key += line + } else if line.trimmed.uppercased().hasPrefix("-----END PGP") { + key += line + keys.append(key) + } else { + key += line + } key += "\n" - } - return keys - } + } + return keys + } func containsPublicKey(with keyID: String) -> Bool { publicKeys.keys.contains(where: { key in key.hasSuffix(keyID.lowercased()) }) @@ -73,7 +71,7 @@ struct GopenPGPInterface: PGPInterface { } func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? { - guard let e = privateKeys.first(where: { (key, _) in key.hasSuffix(keyID.lowercased()) }), + guard let e = privateKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }), let privateKey = privateKeys[e.key] else { throw AppError.Decryption } @@ -97,7 +95,7 @@ struct GopenPGPInterface: PGPInterface { } func encrypt(plainData: Data, keyID: String) throws -> Data { - guard let e = publicKeys.first(where: { (key, _) in key.hasSuffix(keyID.lowercased()) }), + guard let e = publicKeys.first(where: { key, _ in key.hasSuffix(keyID.lowercased()) }), let publicKey = publicKeys[e.key] else { throw AppError.Encryption } @@ -124,11 +122,11 @@ struct GopenPGPInterface: PGPInterface { } var keyID: [String] { - return publicKeys.keys.map({ $0.uppercased() }) + publicKeys.keys.map { $0.uppercased() } } var shortKeyID: [String] { - return publicKeys.keys.map({ $0.suffix(8).uppercased()}) + publicKeys.keys.map { $0.suffix(8).uppercased() } } private func createPgpMessage(from encryptedData: Data) -> CryptoPGPMessage? { diff --git a/passExtension/Crypto/ObjectivePGPInterface.swift b/passExtension/Crypto/ObjectivePGPInterface.swift index 34c9c80..aa1ef57 100644 --- a/passExtension/Crypto/ObjectivePGPInterface.swift +++ b/passExtension/Crypto/ObjectivePGPInterface.swift @@ -9,7 +9,6 @@ import ObjectivePGP struct ObjectivePGPInterface: PGPInterface { - private let publicKey: Key private let privateKey: Key @@ -30,11 +29,11 @@ struct ObjectivePGPInterface: PGPInterface { self.privateKey = privateKey } - func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? { - return try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys) { _ in passphrase } + func decrypt(encryptedData: Data, keyID _: String, passphrase: String) throws -> Data? { + try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys) { _ in passphrase } } - func encrypt(plainData: Data, keyID: String) throws -> Data { + func encrypt(plainData: Data, keyID _: String) throws -> Data { let encryptedData = try ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil) if Defaults.encryptInArmored { return Armor.armored(encryptedData, as: .message).data(using: .ascii)! @@ -51,10 +50,10 @@ struct ObjectivePGPInterface: PGPInterface { } var keyID: [String] { - return keyring.keys.map({ $0.keyID.longIdentifier }) + keyring.keys.map(\.keyID.longIdentifier) } var shortKeyID: [String] { - return keyring.keys.map({ $0.keyID.shortIdentifier }) + keyring.keys.map(\.keyID.shortIdentifier) } } diff --git a/passExtension/Crypto/PGPAgent.swift b/passExtension/Crypto/PGPAgent.swift index 7ffe020..e34d826 100644 --- a/passExtension/Crypto/PGPAgent.swift +++ b/passExtension/Crypto/PGPAgent.swift @@ -7,7 +7,6 @@ // public class PGPAgent { - public static let shared: PGPAgent = PGPAgent() private let keyStore: KeyStore @@ -20,7 +19,7 @@ public class PGPAgent { public func initKeys() throws { guard let publicKey: String = keyStore.get(for: PgpKey.PUBLIC.getKeychainKey()), - let privateKey: String = keyStore.get(for: PgpKey.PRIVATE.getKeychainKey()) else { + let privateKey: String = keyStore.get(for: PgpKey.PRIVATE.getKeychainKey()) else { pgpInterface = nil throw AppError.KeyImport } @@ -52,7 +51,7 @@ public class PGPAgent { throw AppError.Decryption } - var keyID = keyID; + var keyID = keyID if !pgpInterface.containsPrivateKey(with: keyID) { if pgpInterface.keyID.count == 1 { keyID = pgpInterface.keyID.first! @@ -62,8 +61,8 @@ public class PGPAgent { } // Remember the previous status and set the current status - let previousDecryptStatus = self.latestDecryptStatus - self.latestDecryptStatus = false + let previousDecryptStatus = latestDecryptStatus + latestDecryptStatus = false // Get the PGP key passphrase. var passphrase = "" @@ -77,7 +76,7 @@ public class PGPAgent { return nil } // The decryption step has succeed. - self.latestDecryptStatus = true + latestDecryptStatus = true return result } @@ -98,7 +97,7 @@ public class PGPAgent { } public var isPrepared: Bool { - return keyStore.contains(key: PgpKey.PUBLIC.getKeychainKey()) + keyStore.contains(key: PgpKey.PUBLIC.getKeychainKey()) && keyStore.contains(key: PgpKey.PRIVATE.getKeychainKey()) } diff --git a/passExtension/Crypto/PGPInterface.swift b/passExtension/Crypto/PGPInterface.swift index 2052b84..ec4792f 100644 --- a/passExtension/Crypto/PGPInterface.swift +++ b/passExtension/Crypto/PGPInterface.swift @@ -7,7 +7,6 @@ // protocol PGPInterface { - func decrypt(encryptedData: Data, keyID: String, passphrase: String) throws -> Data? func encrypt(plainData: Data, keyID: String) throws -> Data diff --git a/passKit/Controllers/PasscodeLockPresenter.swift b/passKit/Controllers/PasscodeLockPresenter.swift index 8d9c356..f6aab67 100644 --- a/passKit/Controllers/PasscodeLockPresenter.swift +++ b/passKit/Controllers/PasscodeLockPresenter.swift @@ -11,9 +11,8 @@ import UIKit open class PasscodeLockPresenter { - - fileprivate var mainWindow: UIWindow? - fileprivate var passcodeLockWindow: UIWindow? + private var mainWindow: UIWindow? + private var passcodeLockWindow: UIWindow? public init(mainWindow window: UIWindow?) { self.mainWindow = window @@ -27,7 +26,7 @@ open class PasscodeLockPresenter { // new window mainWindow?.endEditing(true) - passcodeLockWindow = UIWindow(frame: self.mainWindow!.frame) + passcodeLockWindow = UIWindow(frame: mainWindow!.frame) moveWindowsToFront(windowLevel: windowLevel) passcodeLockWindow?.isHidden = false @@ -46,9 +45,9 @@ open class PasscodeLockPresenter { passcodeLockWindow?.rootViewController = nil } - fileprivate func moveWindowsToFront(windowLevel: CGFloat?) { + private func moveWindowsToFront(windowLevel: CGFloat?) { let windowLevel = windowLevel ?? UIWindow.Level.normal.rawValue let maxWinLevel = max(windowLevel, UIWindow.Level.normal.rawValue) - passcodeLockWindow?.windowLevel = UIWindow.Level(rawValue: maxWinLevel + 1) + passcodeLockWindow?.windowLevel = UIWindow.Level(rawValue: maxWinLevel + 1) } } diff --git a/passKit/Controllers/PasscodeLockViewController.swift b/passKit/Controllers/PasscodeLockViewController.swift index a1cee8b..68b5118 100644 --- a/passKit/Controllers/PasscodeLockViewController.swift +++ b/passKit/Controllers/PasscodeLockViewController.swift @@ -8,14 +8,13 @@ // Inspired by SwiftPasscodeLock created by Yanko Dimitrov. // -import UIKit import LocalAuthentication +import UIKit open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { - - open var dismissCompletionCallback: (()->Void)? - open var successCallback: (()->Void)? - open var cancelCallback: (()->Void)? + open var dismissCompletionCallback: (() -> Void)? + open var successCallback: (() -> Void)? + open var cancelCallback: (() -> Void)? weak var passcodeTextField: UITextField? weak var biometryAuthButton: UIButton? @@ -23,21 +22,21 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { open weak var cancelButton: UIButton? var isCancellable: Bool = false - + private let passwordStore = PasswordStore.shared - open override func loadView() { + override open func loadView() { super.loadView() - let passcodeTextField = UITextField() + let passcodeTextField = UITextField() passcodeTextField.borderStyle = UITextField.BorderStyle.roundedRect passcodeTextField.placeholder = "EnterPasscode".localize() passcodeTextField.isSecureTextEntry = true passcodeTextField.clearButtonMode = UITextField.ViewMode.whileEditing passcodeTextField.delegate = self - passcodeTextField.addTarget(self, action: #selector(self.passcodeTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) + passcodeTextField.addTarget(self, action: #selector(passcodeTextFieldDidChange(_:)), for: UIControl.Event.editingChanged) passcodeTextField.translatesAutoresizingMaskIntoConstraints = false - self.view.addSubview(passcodeTextField) + view.addSubview(passcodeTextField) self.passcodeTextField = passcodeTextField view.backgroundColor = Colors.systemBackground @@ -50,7 +49,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { biometryAuthButton.addTarget(self, action: #selector(bioButtonPressedAction(_:)), for: .touchUpInside) biometryAuthButton.isHidden = true biometryAuthButton.translatesAutoresizingMaskIntoConstraints = false - self.view.addSubview(biometryAuthButton) + view.addSubview(biometryAuthButton) self.biometryAuthButton = biometryAuthButton let myContext = LAContext() @@ -71,21 +70,21 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { forgotPasscodeButton.setTitleColor(Colors.systemBlue, for: .normal) forgotPasscodeButton.addTarget(self, action: #selector(forgotPasscodeButtonPressedAction(_:)), for: .touchUpInside) // hide the forgotPasscodeButton if the native app is running - forgotPasscodeButton.isHidden = self.isCancellable + forgotPasscodeButton.isHidden = isCancellable forgotPasscodeButton.translatesAutoresizingMaskIntoConstraints = false - self.view.addSubview(forgotPasscodeButton) + view.addSubview(forgotPasscodeButton) self.forgotPasscodeButton = forgotPasscodeButton let cancelButton = UIButton(type: .custom) cancelButton.setTitle("Cancel".localize(), for: .normal) cancelButton.setTitleColor(Colors.systemBlue, for: .normal) cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside) - cancelButton.isHidden = !self.isCancellable + cancelButton.isHidden = !isCancellable cancelButton.translatesAutoresizingMaskIntoConstraints = false cancelButton.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left - self.view.addSubview(cancelButton) + view.addSubview(cancelButton) self.cancelButton = cancelButton - + // Display the Pass icon in the middle of the screen let bundle = Bundle(for: PasscodeLockViewController.self) let appIcon = UIImage(named: "PasscodeLockViewIcon", in: bundle, compatibleWith: nil) @@ -94,49 +93,48 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { appIconView.translatesAutoresizingMaskIntoConstraints = false appIconView.layer.cornerRadius = appIconSize / 5 appIconView.layer.masksToBounds = true - self.view?.addSubview(appIconView) + view?.addSubview(appIconView) NSLayoutConstraint.activate([ passcodeTextField.widthAnchor.constraint(equalToConstant: 250), passcodeTextField.heightAnchor.constraint(equalToConstant: 40), - passcodeTextField.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), - passcodeTextField.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: -20), + passcodeTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor), + passcodeTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -20), // above passocde appIconView.widthAnchor.constraint(equalToConstant: appIconSize), appIconView.heightAnchor.constraint(equalToConstant: appIconSize), - appIconView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), + appIconView.centerXAnchor.constraint(equalTo: view.centerXAnchor), appIconView.bottomAnchor.constraint(equalTo: passcodeTextField.topAnchor, constant: -appIconSize), // below passcode biometryAuthButton.widthAnchor.constraint(equalToConstant: 250), biometryAuthButton.heightAnchor.constraint(equalToConstant: 40), - biometryAuthButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), + biometryAuthButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), biometryAuthButton.topAnchor.constraint(equalTo: passcodeTextField.bottomAnchor), // cancel (top-left of the screen) cancelButton.widthAnchor.constraint(equalToConstant: 150), cancelButton.heightAnchor.constraint(equalToConstant: 40), - cancelButton.topAnchor.constraint(equalTo: self.view.safeTopAnchor), - cancelButton.leftAnchor.constraint(equalTo: self.view.safeLeftAnchor, constant: 20), + cancelButton.topAnchor.constraint(equalTo: view.safeTopAnchor), + cancelButton.leftAnchor.constraint(equalTo: view.safeLeftAnchor, constant: 20), // bottom of the screen forgotPasscodeButton.widthAnchor.constraint(equalToConstant: 250), forgotPasscodeButton.heightAnchor.constraint(equalToConstant: 40), - forgotPasscodeButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), - forgotPasscodeButton.bottomAnchor.constraint(equalTo: self.view.safeBottomAnchor, constant: -40) + forgotPasscodeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + forgotPasscodeButton.bottomAnchor.constraint(equalTo: view.safeBottomAnchor, constant: -40), ]) // dismiss keyboard when tapping anywhere - let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing)) + let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing)) view.addGestureRecognizer(tap) - } - open override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() } - open override func viewDidAppear(_ animated: Bool) { + override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let biometryAuthButton = biometryAuthButton { - self.bioButtonPressedAction(biometryAuthButton) + bioButtonPressedAction(biometryAuthButton) } } @@ -167,16 +165,18 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { dismissPasscodeLock(completionHandler: successCallback) } - @objc func passcodeLockDidCancel() { + @objc + func passcodeLockDidCancel() { dismissPasscodeLock(completionHandler: cancelCallback) } - @objc func bioButtonPressedAction(_ uiButton: UIButton) { + @objc + func bioButtonPressedAction(_: UIButton) { let myContext = LAContext() let myLocalizedReasonString = "AuthenticationNeeded.".localize() var authError: NSError? if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) { - myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, evaluateError in + myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, _ in if success { DispatchQueue.main.async { // user authenticated successfully, take appropriate action @@ -187,9 +187,10 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { } } - @objc func forgotPasscodeButtonPressedAction(_ uiButton: UIButton) { + @objc + func forgotPasscodeButtonPressedAction(_: UIButton) { let alert = UIAlertController(title: "ResetPass".localize(), message: "ResetPassExplanation.".localize(), preferredStyle: UIAlertController.Style.alert) - alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in + alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in let myContext = LAContext() var error: NSError? // If the device passcode is not set, reset the app. @@ -199,7 +200,7 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { return } // If the device passcode is set, authentication is required. - myContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "ErasePasswordStoreData".localize()) { (success, error) in + myContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "ErasePasswordStoreData".localize()) { success, error in if success { DispatchQueue.main.async { // User authenticated successfully, take appropriate action @@ -214,25 +215,26 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate { } })) alert.addAction(UIAlertAction.dismiss()) - self.present(alert, animated: true, completion: nil) + present(alert, animated: true, completion: nil) } - public override func textFieldShouldReturn(_ textField: UITextField) -> Bool { + override public func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == passcodeTextField { if !PasscodeLock.shared.check(passcode: textField.text ?? "") { - self.passcodeTextField?.placeholder = + passcodeTextField?.placeholder = "TryAgain".localize() - self.passcodeTextField?.text = "" - self.passcodeTextField?.shake() + passcodeTextField?.text = "" + passcodeTextField?.shake() } } textField.resignFirstResponder() return true } - @objc func passcodeTextFieldDidChange(_ textField: UITextField) { + @objc + func passcodeTextFieldDidChange(_ textField: UITextField) { if PasscodeLock.shared.check(passcode: textField.text ?? "") { - self.passcodeLockDidSucceed() + passcodeLockDidSucceed() } } diff --git a/passKit/Extensions/Array+Slices.swift b/passKit/Extensions/Array+Slices.swift index 25cb44f..f8d12f1 100644 --- a/passKit/Extensions/Array+Slices.swift +++ b/passKit/Extensions/Array+Slices.swift @@ -7,7 +7,6 @@ // extension Array { - func slices(count: UInt) -> [ArraySlice] { guard count != 0 else { return [] diff --git a/passKit/Extensions/String+Localization.swift b/passKit/Extensions/String+Localization.swift index 121d863..64e4665 100644 --- a/passKit/Extensions/String+Localization.swift +++ b/passKit/Extensions/String+Localization.swift @@ -8,18 +8,18 @@ extension String { public func localize() -> String { - return NSLocalizedString(self, value: "#\(self)#", comment: "") + NSLocalizedString(self, value: "#\(self)#", comment: "") } public func localize(_ firstValue: CVarArg) -> String { - return String(format: localize(), firstValue) + String(format: localize(), firstValue) } public func localize(_ firstValue: CVarArg, _ secondValue: CVarArg) -> String { - return String(format: localize(), firstValue, secondValue) + String(format: localize(), firstValue, secondValue) } public func localize(_ error: Error) -> String { - return localize(error.localizedDescription) + localize(error.localizedDescription) } } diff --git a/passKit/Extensions/String+Utilities.swift b/passKit/Extensions/String+Utilities.swift index dc375ba..e976abb 100644 --- a/passKit/Extensions/String+Utilities.swift +++ b/passKit/Extensions/String+Utilities.swift @@ -8,7 +8,7 @@ extension String { public var trimmed: String { - return trimmingCharacters(in: .whitespacesAndNewlines) + trimmingCharacters(in: .whitespacesAndNewlines) } public func stringByAddingPercentEncodingForRFC3986() -> String? { @@ -19,12 +19,12 @@ extension String { } public func splitByNewline() -> [String] { - return split(omittingEmptySubsequences: false) { $0 == "\n" || $0 == "\r\n" }.map(String.init) + split(omittingEmptySubsequences: false) { $0 == "\n" || $0 == "\r\n" }.map(String.init) } } extension String { public static func | (left: String, right: String) -> String { - return right.isEmpty ? left : left + "\n" + right + right.isEmpty ? left : left + "\n" + right } } diff --git a/passKit/Extensions/UIAlertActionExtension.swift b/passKit/Extensions/UIAlertActionExtension.swift index 53f97d5..3928f4a 100644 --- a/passKit/Extensions/UIAlertActionExtension.swift +++ b/passKit/Extensions/UIAlertActionExtension.swift @@ -6,12 +6,12 @@ // Copyright © 2020 Bob Sun. All rights reserved. // -import UIKit import Foundation +import UIKit extension UIAlertAction { public static func cancelAndPopView(controller: UIViewController) -> UIAlertAction { - return cancel() { _ in + cancel { _ in controller.navigationController?.popViewController(animated: true) } } @@ -24,7 +24,7 @@ extension UIAlertAction { cancel(with: "Dismiss", handler: handler) } - public static func cancel(with title: String, handler: ((UIAlertAction) -> Void)? = nil) -> UIAlertAction { + public static func cancel(with _: String, handler: ((UIAlertAction) -> Void)? = nil) -> UIAlertAction { UIAlertAction(title: "Cancel".localize(), style: .cancel, handler: handler) } @@ -33,7 +33,7 @@ extension UIAlertAction { } public static func okAndPopView(controller: UIViewController) -> UIAlertAction { - return ok() { _ in + ok { _ in controller.navigationController?.popViewController(animated: true) } } @@ -41,13 +41,12 @@ extension UIAlertAction { public static func selectKey(controller: UIViewController, handler: ((UIAlertAction) -> Void)?) -> UIAlertAction { UIAlertAction(title: "Select Key", style: .default) { _ in let selectKeyAlert = UIAlertController(title: "Select from imported keys", message: nil, preferredStyle: .actionSheet) - try? PGPAgent.shared.getShortKeyID().forEach({ k in + try? PGPAgent.shared.getShortKeyID().forEach { k in let action = UIAlertAction(title: k, style: .default, handler: handler) selectKeyAlert.addAction(action) - }) + } selectKeyAlert.addAction(UIAlertAction.cancelAndPopView(controller: controller)) controller.present(selectKeyAlert, animated: true, completion: nil) } } - } diff --git a/passKit/Extensions/UITextFieldExtension.swift b/passKit/Extensions/UITextFieldExtension.swift index 67df2f2..9ab6630 100644 --- a/passKit/Extensions/UITextFieldExtension.swift +++ b/passKit/Extensions/UITextFieldExtension.swift @@ -14,18 +14,18 @@ private var kAssociationKeyNextField: UInt8 = 0 extension UITextField { @IBOutlet var nextField: UITextField? { get { - return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField + objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField } set(newField) { objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN) } } - + func shake() { let animation = CAKeyframeAnimation(keyPath: "transform.translation.x") animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) animation.repeatCount = 3 - animation.duration = 0.2/TimeInterval(animation.repeatCount) + animation.duration = 0.2 / TimeInterval(animation.repeatCount) animation.autoreverses = true animation.values = [3, -3] layer.add(animation, forKey: "shake") diff --git a/passKit/Extensions/UIViewControllerExtension.swift b/passKit/Extensions/UIViewControllerExtension.swift index 461ca38..1a74b96 100644 --- a/passKit/Extensions/UIViewControllerExtension.swift +++ b/passKit/Extensions/UIViewControllerExtension.swift @@ -7,7 +7,8 @@ // extension UIViewController { - @objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool { + @objc + public func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField.nextField != nil { textField.nextField?.becomeFirstResponder() } else { diff --git a/passKit/Extensions/UIViewExtension.swift b/passKit/Extensions/UIViewExtension.swift index 51d0757..9763700 100644 --- a/passKit/Extensions/UIViewExtension.swift +++ b/passKit/Extensions/UIViewExtension.swift @@ -9,29 +9,28 @@ import Foundation extension UIView { - // Save anchors: https://stackoverflow.com/questions/46317061/use-safe-area-layout-programmatically var safeTopAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.topAnchor } else { - return self.topAnchor + return topAnchor } } var safeLeftAnchor: NSLayoutXAxisAnchor { - if #available(iOS 11.0, *){ + if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.leftAnchor } else { - return self.leftAnchor + return leftAnchor } } var safeRightAnchor: NSLayoutXAxisAnchor { - if #available(iOS 11.0, *){ + if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.rightAnchor } else { - return self.rightAnchor + return rightAnchor } } @@ -39,7 +38,7 @@ extension UIView { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.bottomAnchor } else { - return self.bottomAnchor + return bottomAnchor } } } diff --git a/passKit/Helpers/AppKeychain.swift b/passKit/Helpers/AppKeychain.swift index a71c3c0..298ab5a 100644 --- a/passKit/Helpers/AppKeychain.swift +++ b/passKit/Helpers/AppKeychain.swift @@ -9,9 +9,8 @@ import KeychainAccess public class AppKeychain: KeyStore { - public static let shared = AppKeychain() - + private let keychain = Keychain(service: Globals.bundleIdentifier, accessGroup: Globals.groupIdentifier) .accessibility(.whenUnlockedThisDeviceOnly) .synchronizable(false) @@ -25,15 +24,15 @@ public class AppKeychain: KeyStore { } public func contains(key: String) -> Bool { - return (try? keychain.contains(key)) ?? false + (try? keychain.contains(key)) ?? false } public func get(for key: String) -> Data? { - return try? keychain.getData(key) + try? keychain.getData(key) } public func get(for key: String) -> String? { - return try? keychain.getString(key) + try? keychain.getString(key) } public func removeContent(for key: String) { diff --git a/passKit/Helpers/FileManagerExtension.swift b/passKit/Helpers/FileManagerExtension.swift index 74373d5..a1aec6f 100644 --- a/passKit/Helpers/FileManagerExtension.swift +++ b/passKit/Helpers/FileManagerExtension.swift @@ -10,7 +10,6 @@ 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, @@ -19,8 +18,7 @@ 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 { - + func allocatedSizeOfDirectoryAtURL(directoryURL: URL) throws -> UInt64 { // We'll sum up content size here: var accumulatedSize = UInt64(0) @@ -29,7 +27,7 @@ public extension FileManager { URLResourceKey.isRegularFileKey, URLResourceKey.fileAllocatedSizeKey, URLResourceKey.totalFileAllocatedSizeKey, - ] + ] // The error handler simply signals errors to outside code. var errorDidOccur: Error? @@ -38,7 +36,6 @@ public extension FileManager { return false } - // We have to enumerate all directory contents, including subdirectories. let enumerator = self.enumerator(at: directoryURL, includingPropertiesForKeys: prefetchedProperties, @@ -91,4 +88,3 @@ public extension FileManager { return accumulatedSize } } - diff --git a/passKit/Helpers/Globals.swift b/passKit/Helpers/Globals.swift index 3a92c23..ab3db71 100644 --- a/passKit/Helpers/Globals.swift +++ b/passKit/Helpers/Globals.swift @@ -32,7 +32,7 @@ public final class Globals { public static let gitPassword = "gitPassword" public static let gitSSHPrivateKeyPassphrase = "gitSSHPrivateKeyPassphrase" public static let pgpKeyPassphrase = "pgpKeyPassphrase" - + public static let gitSignatureDefaultName = "Pass for iOS" public static let gitSignatureDefaultEmail = "user@passforios" @@ -43,14 +43,15 @@ public final class Globals { // UI related public static let tableCellButtonSize = CGFloat(20.0) - private init() { } + private init() {} } public extension Bundle { var releaseVersionNumber: String? { - return infoDictionary?["CFBundleShortVersionString"] as? String + infoDictionary?["CFBundleShortVersionString"] as? String } + var buildVersionNumber: String? { - return infoDictionary?["CFBundleVersion"] as? String + infoDictionary?["CFBundleVersion"] as? String } } diff --git a/passKit/Helpers/KeyFileManager.swift b/passKit/Helpers/KeyFileManager.swift index c01788c..77df162 100644 --- a/passKit/Helpers/KeyFileManager.swift +++ b/passKit/Helpers/KeyFileManager.swift @@ -45,6 +45,6 @@ public class KeyFileManager { } public func doesKeyFileExist() -> Bool { - return FileManager.default.fileExists(atPath: keyPath) + FileManager.default.fileExists(atPath: keyPath) } } diff --git a/passKit/Helpers/Utils.swift b/passKit/Helpers/Utils.swift index be8f0c6..4317695 100644 --- a/passKit/Helpers/Utils.swift +++ b/passKit/Helpers/Utils.swift @@ -7,7 +7,6 @@ // public class Utils { - public static func copyToPasteboard(textToCopy: String?) { guard textToCopy != nil else { return @@ -15,8 +14,8 @@ public class Utils { UIPasteboard.general.string = textToCopy } - public static func attributedPassword(plainPassword: String) -> NSAttributedString{ - let attributedPassword = NSMutableAttributedString.init(string: plainPassword) + public static func attributedPassword(plainPassword: String) -> NSAttributedString { + let attributedPassword = NSMutableAttributedString(string: plainPassword) // draw all digits in the password into red // draw all punctuation characters in the password into blue for (index, element) in plainPassword.unicodeScalars.enumerated() { @@ -40,24 +39,24 @@ public class Utils { } public static func createRequestPGPKeyPassphraseHandler(controller: UIViewController) -> (String) -> String { - return { keyID in + { keyID in let sem = DispatchSemaphore(value: 0) var passphrase = "" DispatchQueue.main.async { let title = "Passphrase".localize() + " (\(keyID.suffix(8)))" let message = "FillInPgpPassphrase.".localize() let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction.ok() { _ in + alert.addAction(UIAlertAction.ok { _ in passphrase = alert.textFields?.first?.text ?? "" sem.signal() }) - alert.addTextField() { textField in + alert.addTextField { textField in textField.text = AppKeychain.shared.get(for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) ?? "" textField.isSecureTextEntry = true } controller.present(alert, animated: true) } - let _ = sem.wait(timeout: DispatchTime.distantFuture) + _ = sem.wait(timeout: DispatchTime.distantFuture) if Defaults.isRememberPGPPassphraseOn { AppKeychain.shared.add(string: passphrase, for: AppKeychain.getPGPKeyPassphraseKey(keyID: keyID)) } @@ -65,4 +64,3 @@ public class Utils { } } } - diff --git a/passKit/Models/GitCredential.swift b/passKit/Models/GitCredential.swift index 7a04c1e..53aa5d3 100644 --- a/passKit/Models/GitCredential.swift +++ b/passKit/Models/GitCredential.swift @@ -25,7 +25,7 @@ public struct GitCredential { public func credentialProvider(requestCredentialPassword: @escaping (Credential, String?) -> String?) throws -> GTCredentialProvider { var attempts = 0 return GTCredentialProvider { (_, _, _) -> (GTCredential?) in - var credential: GTCredential? = nil + var credential: GTCredential? switch self.credential { case let .http(userName): @@ -52,7 +52,7 @@ public struct GitCredential { return nil } var lastPassword = self.passwordStore.gitSSHPrivateKeyPassphrase - if lastPassword == nil || attempts != 0 { + if lastPassword == nil || attempts != 0 { if let requestedPassword = requestCredentialPassword(self.credential, lastPassword) { if Defaults.isRememberGitCredentialPassphraseOn { self.passwordStore.gitSSHPrivateKeyPassphrase = requestedPassword @@ -72,10 +72,9 @@ public struct GitCredential { public func delete() { switch credential { case .http: - self.passwordStore.gitPassword = nil + passwordStore.gitPassword = nil case .ssh: - self.passwordStore.gitSSHPrivateKeyPassphrase = nil + passwordStore.gitSSHPrivateKeyPassphrase = nil } } } - diff --git a/passKit/Models/PasscodeLock.swift b/passKit/Models/PasscodeLock.swift index 0420a4d..c0d58bf 100644 --- a/passKit/Models/PasscodeLock.swift +++ b/passKit/Models/PasscodeLock.swift @@ -23,7 +23,7 @@ public class PasscodeLock { } public var hasPasscode: Bool { - return passcode != nil + passcode != nil } public func save(passcode: String) { @@ -32,7 +32,7 @@ public class PasscodeLock { } public func check(passcode: String) -> Bool { - return self.passcode == passcode + self.passcode == passcode } public func delete() { diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift index 351b025..aa306f3 100644 --- a/passKit/Models/Password.swift +++ b/passKit/Models/Password.swift @@ -6,11 +6,10 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import OneTimePassword import Base32 +import OneTimePassword public class Password { - public var name: String public var url: URL public var plainText: String @@ -29,47 +28,47 @@ public class Password { } public var namePath: String { - return url.deletingPathExtension().path + url.deletingPathExtension().path } public var nameFromPath: String? { - return url.deletingPathExtension().path.split(separator: "/").last.map { String($0) } + url.deletingPathExtension().path.split(separator: "/").last.map { String($0) } } public var password: String { - return parser.firstLine + parser.firstLine } public var plainData: Data { - return plainText.data(using: .utf8)! + plainText.data(using: .utf8)! } public var additionsPlainText: String { - return parser.additionsSection + parser.additionsSection } public var username: String? { - return getAdditionValue(withKey: Constants.USERNAME_KEYWORD) + getAdditionValue(withKey: Constants.USERNAME_KEYWORD) } public var login: String? { - return getAdditionValue(withKey: Constants.LOGIN_KEYWORD) + getAdditionValue(withKey: Constants.LOGIN_KEYWORD) } public var urlString: String? { - return getAdditionValue(withKey: Constants.URL_KEYWORD) + getAdditionValue(withKey: Constants.URL_KEYWORD) } public var currentOtp: String? { - return otpToken?.currentPassword + otpToken?.currentPassword } public var numberOfUnknowns: Int { - return additions.map { $0.title }.filter(Constants.isUnknown).count + additions.map(\.title).filter(Constants.isUnknown).count } public var numberOfOtpRelated: Int { - return additions.map { $0.title }.filter(Constants.isOtpKeyword).count - (firstLineIsOTPField ? 1 : 0) + additions.map(\.title).filter(Constants.isOtpKeyword).count - (firstLineIsOTPField ? 1 : 0) } public init(name: String, url: URL, plainText: String) { @@ -119,7 +118,7 @@ public class Password { } public func getFilteredAdditions() -> [AdditionField] { - return additions.filter { field in + additions.filter { field in let title = field.title.lowercased() return title != Constants.USERNAME_KEYWORD && title != Constants.LOGIN_KEYWORD @@ -194,12 +193,12 @@ public class Password { newOtpauth?.append("&secret=") newOtpauth?.append(MF_Base32Codec.base32String(from: otpToken?.generator.secret)) - var lines : [String] = [] - self.plainText.enumerateLines() { line, _ in + var lines: [String] = [] + plainText.enumerateLines { line, _ in let (key, _) = Parser.getKeyValuePair(from: line) if !Constants.OTP_KEYWORDS.contains(key ?? "") { lines.append(line) - } else if key == Constants.OTPAUTH && newOtpauth != nil { + } else if key == Constants.OTPAUTH, newOtpauth != nil { lines.append(newOtpauth!) // set to nil to prevent duplication newOtpauth = nil @@ -208,10 +207,10 @@ public class Password { if newOtpauth != nil { lines.append(newOtpauth!) } - self.updatePassword(name: self.name, url: self.url, plainText: lines.joined(separator: "\n")) + updatePassword(name: name, url: url, plainText: lines.joined(separator: "\n")) // get and return the password - return self.otpToken?.currentPassword + return otpToken?.currentPassword } public func getUsernameForCompletion() -> String { diff --git a/passKit/Models/PasswordEntity.swift b/passKit/Models/PasswordEntity.swift index e1ec0f7..058776e 100644 --- a/passKit/Models/PasswordEntity.swift +++ b/passKit/Models/PasswordEntity.swift @@ -10,7 +10,6 @@ import Foundation import SwiftyUserDefaults extension PasswordEntity { - public var nameWithCategory: String { if let p = path, p.hasSuffix(".gpg") { return String(p.prefix(upTo: p.index(p.endIndex, offsetBy: -4))) @@ -19,7 +18,7 @@ extension PasswordEntity { } public func getCategoryText() -> String { - return getCategoryArray().joined(separator: " > ") + getCategoryArray().joined(separator: " > ") } public func getCategoryArray() -> [String] { @@ -44,17 +43,16 @@ extension PasswordEntity { // manually write models instead auto generation. public func getImage() -> Data? { - return image + image } public func getName() -> String { // unwrap non-optional core data - return name ?? "" + name ?? "" } public func getPath() -> String { // unwrap non-optional core data - return path ?? "" + path ?? "" } - } diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 7897772..6491d4a 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -6,12 +6,12 @@ // Copyright © 2017 Bob Sun. All rights reserved. // -import Foundation import CoreData -import UIKit -import SwiftyUserDefaults -import ObjectiveGit +import Foundation import KeychainAccess +import ObjectiveGit +import SwiftyUserDefaults +import UIKit public class PasswordStore { public static let shared = PasswordStore() @@ -21,43 +21,40 @@ public class PasswordStore { dateFormatter.timeStyle = .short return dateFormatter }() + public var storeURL: URL public var tempStoreURL: URL { - get { - URL(fileURLWithPath: "\(storeURL.path)-temp") - } + URL(fileURLWithPath: "\(storeURL.path)-temp") } public var storeRepository: GTRepository? - + public var gitSignatureForNow: GTSignature? { - get { - let gitSignatureName = Defaults.gitSignatureName ?? Globals.gitSignatureDefaultName - let gitSignatureEmail = Defaults.gitSignatureEmail ?? Globals.gitSignatureDefaultEmail - return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date()) - } + let gitSignatureName = Defaults.gitSignatureName ?? Globals.gitSignatureDefaultName + let gitSignatureEmail = Defaults.gitSignatureEmail ?? Globals.gitSignatureDefaultEmail + return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date()) } - + public var gitPassword: String? { set { AppKeychain.shared.add(string: newValue, for: Globals.gitPassword) } get { - return AppKeychain.shared.get(for: Globals.gitPassword) + AppKeychain.shared.get(for: Globals.gitPassword) } } - + public var gitSSHPrivateKeyPassphrase: String? { set { AppKeychain.shared.add(string: newValue, for: Globals.gitSSHPrivateKeyPassphrase) } get { - return AppKeychain.shared.get(for: Globals.gitSSHPrivateKeyPassphrase) + AppKeychain.shared.get(for: Globals.gitSSHPrivateKeyPassphrase) } } - + private let fm = FileManager.default - lazy private var context: NSManagedObjectContext = { + private lazy var context: NSManagedObjectContext = { let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")! let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL) let container = NSPersistentContainer(name: "pass", managedObjectModel: managedObjectModel!) @@ -65,11 +62,11 @@ public class PasswordStore { try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) } container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))] - container.loadPersistentStores(completionHandler: { (storeDescription, error) in + container.loadPersistentStores(completionHandler: { _, error in 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. @@ -83,36 +80,36 @@ public class PasswordStore { }) return container.viewContext }() - - public var numberOfPasswords : Int { - return self.fetchPasswordEntityCoreData(withDir: false).count + + public var numberOfPasswords: Int { + fetchPasswordEntityCoreData(withDir: false).count } - - public var sizeOfRepositoryByteCount : UInt64 { - return (try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.storeURL)) ?? 0 + + public var sizeOfRepositoryByteCount: UInt64 { + (try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: storeURL)) ?? 0 } - + public var numberOfLocalCommits: Int { - return (try? getLocalCommits())?.flatMap { $0.count } ?? 0 + (try? getLocalCommits()).map(\.count) ?? 0 } - + public var lastSyncedTime: Date? { - return Defaults.lastSyncedTime + Defaults.lastSyncedTime } - + public var numberOfCommits: UInt? { - return storeRepository?.numberOfCommits(inCurrentBranch: nil) + storeRepository?.numberOfCommits(inCurrentBranch: nil) } init(url: URL = URL(fileURLWithPath: "\(Globals.repositoryPath)")) { - storeURL = url + self.storeURL = url // Migration importExistingKeysIntoKeychain() do { if fm.fileExists(atPath: storeURL.path) { - try storeRepository = GTRepository.init(url: storeURL) + try self.storeRepository = GTRepository(url: storeURL) } } catch { print(error) @@ -128,12 +125,12 @@ public class PasswordStore { Defaults.remove(\.pgpPrivateKeyArmor) Defaults.remove(\.gitSSHPrivateKeyArmor) } - + public func repositoryExists() -> Bool { let fm = FileManager() return fm.fileExists(atPath: Globals.repositoryPath) } - + public func passwordExisted(password: Password) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -148,7 +145,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswordEntities".localize(error)) } } - + public func passwordEntityExisted(path: String) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -163,7 +160,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswordEntities".localize(error)) } } - + public func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -173,7 +170,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswordEntities".localize(error)) } } - + public func cloneRepository(remoteRepoURL: URL, credential: GitCredential, branchName: String, @@ -183,23 +180,23 @@ public class PasswordStore { do { let credentialProvider = try credential.credentialProvider(requestCredentialPassword: requestCredentialPassword) let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider] - try self.cloneRepository(remoteRepoURL: remoteRepoURL, options: options, branchName: branchName, transferProgressBlock: transferProgressBlock, checkoutProgressBlock: checkoutProgressBlock) + try cloneRepository(remoteRepoURL: remoteRepoURL, options: options, branchName: branchName, transferProgressBlock: transferProgressBlock, checkoutProgressBlock: checkoutProgressBlock) } catch { credential.delete() - throw(error) + throw (error) } } public func cloneRepository(remoteRepoURL: URL, - options: [AnyHashable : Any]? = nil, + options: [AnyHashable: Any]? = nil, branchName: String, transferProgressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void, checkoutProgressBlock: @escaping (String, UInt, UInt) -> Void, completion: @escaping () -> Void = {}) throws { try? fm.removeItem(at: storeURL) try? fm.removeItem(at: tempStoreURL) - self.gitPassword = nil - self.gitSSHPrivateKeyPassphrase = nil + gitPassword = nil + gitSSHPrivateKeyPassphrase = nil do { storeRepository = try GTRepository.clone(from: remoteRepoURL, toWorkingDirectory: tempStoreURL, @@ -216,7 +213,7 @@ public class PasswordStore { self.deleteCoreData(entityName: "PasswordEntity") NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } - throw(error) + throw (error) } Defaults.lastSyncedTime = Date() DispatchQueue.main.async { @@ -225,7 +222,7 @@ public class PasswordStore { completion() } } - + private func checkoutAndChangeBranch(withName localBranchName: String, progressBlock: @escaping (String, UInt, UInt) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -241,7 +238,7 @@ public class PasswordStore { try storeRepository.checkoutReference(localBranch.reference, options: checkoutOptions) try storeRepository.moveHEAD(to: localBranch.reference) } - + public func pullRepository(credential: GitCredential, requestCredentialPassword: @escaping (GitCredential.Credential, String?) -> String?, progressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void) throws { @@ -253,30 +250,30 @@ public class PasswordStore { let remote = try GTRemote(name: "origin", in: storeRepository) try storeRepository.pull(storeRepository.currentBranch(), from: remote, withOptions: options, progress: progressBlock) Defaults.lastSyncedTime = Date() - self.setAllSynced() + setAllSynced() DispatchQueue.main.async { self.updatePasswordEntityCoreData() NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } } - + private func updatePasswordEntityCoreData() { deleteCoreData(entityName: "PasswordEntity") do { - var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter { + var q = try fm.contentsOfDirectory(atPath: storeURL.path).filter { !$0.hasPrefix(".") - }.map { (filename) -> PasswordEntity in - let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity - if filename.hasSuffix(".gpg") { - passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4))) - } else { - passwordEntity.name = filename - } - passwordEntity.path = filename - passwordEntity.parent = nil - return passwordEntity + }.map { (filename) -> PasswordEntity in + let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity + if filename.hasSuffix(".gpg") { + passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4))) + } else { + passwordEntity.name = filename + } + passwordEntity.path = filename + passwordEntity.parent = nil + return passwordEntity } - while q.count > 0 { + while !q.isEmpty { let e = q.first! q.remove(at: 0) guard !e.name!.hasPrefix(".") else { @@ -309,9 +306,9 @@ public class PasswordStore { } catch { print(error) } - self.saveUpdatedContext() + saveUpdatedContext() } - + public func getRecentCommits(count: Int) throws -> [GTCommit] { guard let storeRepository = storeRepository else { return [] @@ -328,7 +325,7 @@ public class PasswordStore { } return commits } - + public func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -339,7 +336,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - + public func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -352,8 +349,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - - + public func fetchUnsyncedPasswords() -> [PasswordEntity] { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0) @@ -364,17 +360,17 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - + public func setAllSynced() { let passwordEntities = fetchUnsyncedPasswords() - if passwordEntities.count > 0 { + if !passwordEntities.isEmpty { for passwordEntity in passwordEntities { passwordEntity.synced = true } - self.saveUpdatedContext() + saveUpdatedContext() } } - + public func getLatestUpdateInfo(filename: String) -> String { guard let storeRepository = storeRepository else { return "Unknown".localize() @@ -383,7 +379,7 @@ public class PasswordStore { let latestCommitTime = blameHunks.map({ $0.finalSignature?.time?.timeIntervalSince1970 ?? 0 }).max() else { - return "Unknown".localize() + return "Unknown".localize() } let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime) if Date().timeIntervalSince(lastCommitDate) <= 60 { @@ -391,10 +387,9 @@ public class PasswordStore { } return PasswordStore.dateFormatter.string(from: lastCommitDate) } - - public func updateRemoteRepo() { - } - + + public func updateRemoteRepo() {} + private func gitAdd(path: String) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -402,7 +397,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.RepositoryNotSet @@ -414,7 +409,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 @@ -424,12 +419,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) @@ -437,7 +432,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.RepositoryNotSet @@ -453,7 +448,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.RepositoryNotSet @@ -462,7 +457,7 @@ public class PasswordStore { let branches = try storeRepository.branches(withPrefix: reference) return branches.first } - + public func pushRepository(credential: GitCredential, requestCredentialPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -477,12 +472,12 @@ public class PasswordStore { throw AppError.GitPushNotSuccessful } } - + private func addPasswordEntities(password: Password) throws -> PasswordEntity? { guard !passwordExisted(password: password) else { throw AppError.PasswordDuplicated } - + var passwordURL = password.url var previousPathLength = Int.max var paths: [String] = [] @@ -490,20 +485,20 @@ public class PasswordStore { paths.append(passwordURL.path) passwordURL = passwordURL.deletingLastPathComponent() // better identify errors before saving a new password - if passwordURL.path != "." && passwordURL.path.count >= previousPathLength { + if passwordURL.path != ".", passwordURL.path.count >= previousPathLength { throw AppError.WrongPasswordFilename } previousPathLength = passwordURL.path.count } paths.reverse() - var parentPasswordEntity: PasswordEntity? = nil + var parentPasswordEntity: PasswordEntity? for path in paths { let isDir = !path.hasSuffix(".gpg") if let passwordEntity = getPasswordEntity(by: path, isDir: isDir) { passwordEntity.synced = false parentPasswordEntity = passwordEntity } else { - let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as! PasswordEntity + let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity let pathURL = URL(string: path.stringByAddingPercentEncodingForRFC3986()!)! if isDir { passwordEntity.name = pathURL.lastPathComponent @@ -518,72 +513,73 @@ public class PasswordStore { } } - self.saveUpdatedContext() + saveUpdatedContext() return parentPasswordEntity } - + public func add(password: Password, keyID: String? = nil) throws -> PasswordEntity? { try createDirectoryTree(at: password.url) let saveURL = storeURL.appendingPathComponent(password.url.path) - try self.encrypt(password: password, keyID: keyID).write(to: saveURL) + try encrypt(password: password, keyID: keyID).write(to: saveURL) try gitAdd(path: password.url.path) - let _ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path)) + _ = try gitCommit(message: "AddPassword.".localize(password.url.deletingPathExtension().path)) let newPasswordEntity = try addPasswordEntities(password: password) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } - + public func delete(passwordEntity: PasswordEntity) throws { let deletedFileURL = try passwordEntity.getURL() try gitRm(path: deletedFileURL.path) try deletePasswordEntities(passwordEntity: passwordEntity) try deleteDirectoryTree(at: deletedFileURL) - let _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!)) + _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!)) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } - + public func edit(passwordEntity: PasswordEntity, password: Password, keyID: String? = nil) throws -> PasswordEntity? { var newPasswordEntity: PasswordEntity? = passwordEntity let url = try passwordEntity.getURL() - - if password.changed&PasswordChange.content.rawValue != 0 { + + if password.changed & PasswordChange.content.rawValue != 0 { let saveURL = storeURL.appendingPathComponent(url.path) - try self.encrypt(password: password, keyID: keyID).write(to: saveURL) + try encrypt(password: password, keyID: keyID).write(to: saveURL) try gitAdd(path: url.path) - let _ = try gitCommit(message: "EditPassword.".localize(url.deletingPathExtension().path.removingPercentEncoding!)) + _ = try gitCommit(message: "EditPassword.".localize(url.deletingPathExtension().path.removingPercentEncoding!)) newPasswordEntity = passwordEntity newPasswordEntity?.synced = false - self.saveUpdatedContext() + saveUpdatedContext() } - - if password.changed&PasswordChange.path.rawValue != 0 { + + if password.changed & PasswordChange.path.rawValue != 0 { let deletedFileURL = url // 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) - let _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!)) + _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!)) } 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) { + // swiftformat:disable:next isEmpty + while current != nil, current!.children!.count == 0 || !current!.isDir { let parent = current!.parent - self.context.delete(current!) + context.delete(current!) current = parent } - self.saveUpdatedContext() + saveUpdatedContext() } - + public func saveUpdatedContext() { do { if context.hasChanges { @@ -593,11 +589,11 @@ public class PasswordStore { fatalError("FailureToSaveContext".localize(error)) } } - + public func deleteCoreData(entityName: String) { let deleteFetchRequest = NSFetchRequest(entityName: entityName) let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest) - + do { try context.execute(deleteRequest) try context.save() @@ -606,7 +602,7 @@ public class PasswordStore { print(error) } } - + public func updateImage(passwordEntity: PasswordEntity, image: Data?) { guard let image = image else { return @@ -625,33 +621,33 @@ public class PasswordStore { } } } - + public func erase() { // Delete files. try? fm.removeItem(at: storeURL) try? fm.removeItem(at: tempStoreURL) - + // Delete PGP key, SSH key and other secrets from the keychain. AppKeychain.shared.removeAllContent() // Delete core data. deleteCoreData(entityName: "PasswordEntity") - + // Delete default settings. Defaults.removeAll() - + // Clean up variables inside PasswordStore. storeRepository = nil - + // Delete cache explicitly. PasscodeLock.shared.delete() PGPAgent.shared.uninitKeys() - + // Broadcast. NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreErased, object: nil) } - + // return the number of discarded commits public func reset() throws -> Int { guard let storeRepository = storeRepository else { @@ -659,26 +655,25 @@ public class PasswordStore { } // get a list of local commits if let localCommits = try getLocalCommits(), - localCommits.count > 0 { + !localCommits.isEmpty { // get the oldest local commit guard let firstLocalCommit = localCommits.last, firstLocalCommit.parents.count == 1, let newHead = firstLocalCommit.parents.first else { - throw AppError.GitReset + throw AppError.GitReset } try storeRepository.reset(to: newHead, resetType: .hard) - self.setAllSynced() - self.updatePasswordEntityCoreData() - + setAllSynced() + updatePasswordEntityCoreData() + NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil) return localCommits.count } else { - return 0 // no new commit + return 0 // no new commit } } - - + private func getLocalCommits() throws -> [GTCommit]? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -692,7 +687,7 @@ public class PasswordStore { guard remoteBranch.oid != nil else { throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName) } - + // get a list of local commits return try storeRepository.localCommitsRelative(toRemoteBranch: remoteBranch) } @@ -708,13 +703,13 @@ public class PasswordStore { let url = try passwordEntity.getURL() return Password(name: passwordEntity.getName(), url: url, plainText: plainText) } - + public func encrypt(password: Password, keyID: String? = nil) throws -> Data { let encryptedDataPath = storeURL.appendingPathComponent(password.url.path) let keyID = keyID ?? findGPGID(from: encryptedDataPath) return try PGPAgent.shared.encrypt(plainData: password.plainData, keyID: keyID) } - + public func removeGitSSHKeys() { try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) Defaults.remove(\.gitSSHKeySource) @@ -727,8 +722,8 @@ public class PasswordStore { public func findGPGID(from url: URL) -> String { var path = url - while !FileManager.default.fileExists(atPath: path.appendingPathComponent(".gpg-id").path) - && path.path != "file:///" { + while !FileManager.default.fileExists(atPath: path.appendingPathComponent(".gpg-id").path), + path.path != "file:///" { path = path.deletingLastPathComponent() } path = path.appendingPathComponent(".gpg-id") diff --git a/passKit/Models/PasswordTableEntry.swift b/passKit/Models/PasswordTableEntry.swift index d934991..047f3ba 100644 --- a/passKit/Models/PasswordTableEntry.swift +++ b/passKit/Models/PasswordTableEntry.swift @@ -14,7 +14,7 @@ public class PasswordTableEntry: NSObject { public let isDir: Bool public let synced: Bool public let categoryText: String - + public init(_ entity: PasswordEntity) { self.passwordEntity = entity self.title = entity.name! @@ -22,23 +22,22 @@ public class PasswordTableEntry: NSObject { self.synced = entity.synced self.categoryText = entity.getCategoryText() } - + public func match(_ searchText: String) -> Bool { - return PasswordTableEntry.match(nameWithCategory: passwordEntity.nameWithCategory, searchText: searchText) + PasswordTableEntry.match(nameWithCategory: passwordEntity.nameWithCategory, searchText: searchText) } - + public static func match(nameWithCategory: String, searchText: String) -> Bool { - let titleSplit = nameWithCategory.split{ !($0.isLetter || $0.isNumber || $0 == ".") } + let titleSplit = nameWithCategory.split { !($0.isLetter || $0.isNumber || $0 == ".") } for str in titleSplit { - if (str.localizedCaseInsensitiveContains(searchText)) { + if str.localizedCaseInsensitiveContains(searchText) { return true } - if (searchText.localizedCaseInsensitiveContains(str)) { + if searchText.localizedCaseInsensitiveContains(str) { return true } } - + return false } } - diff --git a/passKit/Parser/AdditionField.swift b/passKit/Parser/AdditionField.swift index b061ab9..be80ce6 100644 --- a/passKit/Parser/AdditionField.swift +++ b/passKit/Parser/AdditionField.swift @@ -7,7 +7,6 @@ // public struct AdditionField: Hashable { - public let title: String, content: String public init(title: String = "", content: String = "") { @@ -16,7 +15,7 @@ public struct AdditionField: Hashable { } var asString: String { - return title.isEmpty ? content : title + ": " + content + title.isEmpty ? content : title + ": " + content } var asTuple: (String, String) { @@ -25,21 +24,20 @@ public struct AdditionField: Hashable { } extension AdditionField { - static func | (left: String, right: AdditionField) -> String { - return left | right.asString + left | right.asString } static func | (left: AdditionField, right: String) -> String { - return left.asString | right + left.asString | right } static func | (left: AdditionField, right: AdditionField) -> String { - return left.asString | right + left.asString | right } } infix operator =>: MultiplicationPrecedence public func => (key: String, value: String) -> AdditionField { - return AdditionField(title: key, content: value) + AdditionField(title: key, content: value) } diff --git a/passKit/Parser/Constants.swift b/passKit/Parser/Constants.swift index c10f4f6..065ba4e 100644 --- a/passKit/Parser/Constants.swift +++ b/passKit/Parser/Constants.swift @@ -7,7 +7,6 @@ // public struct Constants { - static let OTP_SECRET = "otp_secret" static let OTP_TYPE = "otp_type" static let OTP_ALGORITHM = "otp_algorithm" @@ -54,7 +53,7 @@ public struct Constants { } static func isOtpKeyword(_ keyword: String) -> Bool { - return OTP_KEYWORDS.contains(keyword.lowercased()) + OTP_KEYWORDS.contains(keyword.lowercased()) } static func isUnknown(_ string: String) -> Bool { @@ -63,10 +62,10 @@ public struct Constants { } static func unknown(_ number: UInt) -> String { - return "\(UNKNOWN) \(number)" + "\(UNKNOWN) \(number)" } static func getSeparator(breakingLines: Bool) -> String { - return breakingLines ? MULTILINE_WITH_LINE_BREAK_SEPARATOR : MULTILINE_WITHOUT_LINE_BREAK_SEPARATOR + breakingLines ? MULTILINE_WITH_LINE_BREAK_SEPARATOR : MULTILINE_WITHOUT_LINE_BREAK_SEPARATOR } } diff --git a/passKit/Parser/OTPType.swift b/passKit/Parser/OTPType.swift index 80b8cf3..458ec93 100644 --- a/passKit/Parser/OTPType.swift +++ b/passKit/Parser/OTPType.swift @@ -14,7 +14,7 @@ public enum OTPType: String { case none = "None" var description: String { - return rawValue.localize() + rawValue.localize() } init(token: Token?) { diff --git a/passKit/Parser/Parser.swift b/passKit/Parser/Parser.swift index 9181a97..40f8d1c 100644 --- a/passKit/Parser/Parser.swift +++ b/passKit/Parser/Parser.swift @@ -7,7 +7,6 @@ // class Parser { - let firstLine: String let additionsSection: String let purgedAdditionalLines: [String] @@ -19,8 +18,8 @@ class Parser { let splittedPlainText = plainText.splitByNewline() firstLine = splittedPlainText.first! - additionsSection = splittedPlainText[1...].joined(separator: "\n") - purgedAdditionalLines = splittedPlainText[1...].filter { !$0.isEmpty } + self.additionsSection = splittedPlainText[1...].joined(separator: "\n") + self.purgedAdditionalLines = splittedPlainText[1...].filter { !$0.isEmpty } } private func getAdditionFields() -> [AdditionField] { @@ -57,7 +56,7 @@ class Parser { } let initialBlanks = String(repeating: Constants.BLANK, count: numberInitialBlanks) - while i < purgedAdditionalLines.count && purgedAdditionalLines[i].starts(with: initialBlanks) { + while i < purgedAdditionalLines.count, purgedAdditionalLines[i].starts(with: initialBlanks) { result.append(String(purgedAdditionalLines[i].dropFirst(numberInitialBlanks))) result.append(Constants.getSeparator(breakingLines: !removingLineBreaks)) i += 1 diff --git a/passKit/Parser/TokenBuilder.swift b/passKit/Parser/TokenBuilder.swift index 737087d..1201f96 100644 --- a/passKit/Parser/TokenBuilder.swift +++ b/passKit/Parser/TokenBuilder.swift @@ -27,7 +27,6 @@ import OneTimePassword /// * digits: `6` (default: `6`, optional) /// class TokenBuilder { - private var name: String = "" private var secret: Data? private var type: OTPType = .totp @@ -80,7 +79,6 @@ class TokenBuilder { return self } - func build() -> Token? { guard secret != nil, digits != nil else { return nil diff --git a/passKit/Passwords/PasswordGenerator.swift b/passKit/Passwords/PasswordGenerator.swift index e53e704..51b4d7e 100644 --- a/passKit/Passwords/PasswordGenerator.swift +++ b/passKit/Passwords/PasswordGenerator.swift @@ -7,7 +7,6 @@ // public struct PasswordGenerator: Codable { - private static let digits = "0123456789" private static let letters = "abcdefghijklmnopqrstuvwxyz" private static let capitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -114,7 +113,7 @@ public struct PasswordGenerator: Codable { } private func selectRandomly(count: Int, from string: String) -> [Character] { - return (0 ..< count).map { _ in string.randomElement()! } + (0 ..< count).map { _ in string.randomElement()! } } } diff --git a/passKit/Passwords/PasswordGeneratorFlavor.swift b/passKit/Passwords/PasswordGeneratorFlavor.swift index bd0843b..62f247e 100644 --- a/passKit/Passwords/PasswordGeneratorFlavor.swift +++ b/passKit/Passwords/PasswordGeneratorFlavor.swift @@ -13,7 +13,7 @@ public enum PasswordGeneratorFlavor: String { case xkcd = "XKCD" public var localized: String { - return rawValue.localize() + rawValue.localize() } public var longNameLocalized: String { diff --git a/passKitTests/Crypto/CryptoFrameworkTest.swift b/passKitTests/Crypto/CryptoFrameworkTest.swift index a7c22d4..fa66202 100644 --- a/passKitTests/Crypto/CryptoFrameworkTest.swift +++ b/passKitTests/Crypto/CryptoFrameworkTest.swift @@ -8,11 +8,11 @@ import XCTest +// swiftformat:disable:next sortedImports @testable import passKit @testable import Crypto class CryptoFrameworkTest: XCTestCase { - typealias MessageConverter = (CryptoPGPMessage, NSErrorPointer) -> CryptoPGPMessage? private let testText = "Hello World!" @@ -47,7 +47,7 @@ class CryptoFrameworkTest: XCTestCase { ].forEach { testKeyInfo in var error: NSError? guard let publicKey = CryptoNewKeyFromArmored(testKeyInfo.publicKey, &error), - let privateKey = CryptoNewKeyFromArmored(testKeyInfo.privateKey, &error) else { + let privateKey = CryptoNewKeyFromArmored(testKeyInfo.privateKey, &error) else { XCTFail("Keys cannot be initialized.") return } diff --git a/passKitTests/Crypto/PGPAgentTest.swift b/passKitTests/Crypto/PGPAgentTest.swift index 5e26720..866b98d 100644 --- a/passKitTests/Crypto/PGPAgentTest.swift +++ b/passKitTests/Crypto/PGPAgentTest.swift @@ -6,8 +6,8 @@ // Copyright © 2019 Bob Sun. All rights reserved. // -import XCTest import SwiftyUserDefaults +import XCTest @testable import passKit @@ -144,17 +144,17 @@ class PGPAgentTest: XCTestCase { passphraseRequestCalledCount += 1 return "incorrect passphrase" } - + // Provide the correct passphrase. XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData) XCTAssertEqual(passphraseRequestCalledCount, 1) - + // Provide the wrong passphrase. XCTAssertThrowsError(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideIncorrectPassphrase)) { XCTAssertEqual($0 as! AppError, AppError.WrongPassphrase) } XCTAssertEqual(passphraseRequestCalledCount, 2) - + // Ask for the passphrase because the previous decryption has failed. XCTAssertEqual(try basicEncryptDecrypt(using: pgpAgent, keyID: RSA2048.fingerprint, requestPassphrase: provideCorrectPassphrase), testData) XCTAssertEqual(passphraseRequestCalledCount, 3) @@ -165,4 +165,3 @@ class PGPAgentTest: XCTestCase { try KeyFileManager(keyType: PgpKey.PRIVATE, keyPath: "", keyHandler: keychain.add).importKey(from: privateKey) } } - diff --git a/passKitTests/Extensions/Array+SlicesTest.swift b/passKitTests/Extensions/Array+SlicesTest.swift index f0aa4e8..9c85c1f 100644 --- a/passKitTests/Extensions/Array+SlicesTest.swift +++ b/passKitTests/Extensions/Array+SlicesTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class ArraySlicesTest: XCTestCase { - func testZeroCount() { XCTAssertEqual([1, 2, 3].slices(count: 0), []) } diff --git a/passKitTests/Extensions/String+UtilitiesTest.swift b/passKitTests/Extensions/String+UtilitiesTest.swift index c112e44..44c8f5d 100644 --- a/passKitTests/Extensions/String+UtilitiesTest.swift +++ b/passKitTests/Extensions/String+UtilitiesTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class StringUtilitiesTest: XCTestCase { - func testTrimmed() { [ (" ", ""), diff --git a/passKitTests/Models/PasswordStoreTest.swift b/passKitTests/Models/PasswordStoreTest.swift index 9bdc6ce..dbff5a4 100644 --- a/passKitTests/Models/PasswordStoreTest.swift +++ b/passKitTests/Models/PasswordStoreTest.swift @@ -6,20 +6,20 @@ // import Foundation -import XCTest import ObjectiveGit +import XCTest @testable import passKit class PasswordStoreTest: XCTestCase { - let cloneOptions: [String : GTCredentialProvider] = { - let credentialProvider = GTCredentialProvider { (_, _, _) -> (GTCredential?) in - try? GTCredential(userName: "", password: "") - } - return [GTRepositoryCloneOptionsCredentialProvider: credentialProvider] - }() - let remoteRepoURL = URL(string: "https://github.com/mssun/passforios-password-store.git")! + let cloneOptions: [String: GTCredentialProvider] = { + let credentialProvider = GTCredentialProvider { (_, _, _) -> (GTCredential?) in + try? GTCredential(userName: "", password: "") + } + return [GTRepositoryCloneOptionsCredentialProvider: credentialProvider] + }() + let remoteRepoURL = URL(string: "https://github.com/mssun/passforios-password-store.git")! func testCloneAndDecryptMultiKeys() throws { let url = URL(fileURLWithPath: "\(Globals.repositoryPath)-test") @@ -38,8 +38,8 @@ class PasswordStoreTest: XCTestCase { [ ("work/github.com", "4712286271220DB299883EA7062E678DA1024DAE"), - ("personal/github.com", "787EAE1A5FA3E749AA34CC6AA0645EBED862027E") - ].forEach {(path, id) in + ("personal/github.com", "787EAE1A5FA3E749AA34CC6AA0645EBED862027E"), + ].forEach { path, id in let keyID = findGPGID(from: url.appendingPathComponent(path)) XCTAssertEqual(keyID, id) } @@ -57,17 +57,14 @@ class PasswordStoreTest: XCTestCase { let testPassword = Password(name: "test", url: URL(string: "test.gpg")!, plainText: "testpassword") let testPasswordEntity = try passwordStore.add(password: testPassword)! - let testPasswordPlain = try passwordStore.decrypt(passwordEntity: testPasswordEntity, requestPGPKeyPassphrase: requestPGPKeyPassphrase ) + let testPasswordPlain = try passwordStore.decrypt(passwordEntity: testPasswordEntity, requestPGPKeyPassphrase: requestPGPKeyPassphrase) XCTAssertEqual(testPasswordPlain.plainText, "testpassword") passwordStore.erase() } - private func decrypt(passwordStore: PasswordStore, path: String, passphrase: String) throws -> Password { + private func decrypt(passwordStore: PasswordStore, path: String, passphrase _: String) throws -> Password { let entity = passwordStore.getPasswordEntity(by: path, isDir: false)! - return try passwordStore.decrypt(passwordEntity: entity, requestPGPKeyPassphrase: requestPGPKeyPassphrase ) - + return try passwordStore.decrypt(passwordEntity: entity, requestPGPKeyPassphrase: requestPGPKeyPassphrase) } - } - diff --git a/passKitTests/Models/PasswordTableEntryTest.swift b/passKitTests/Models/PasswordTableEntryTest.swift index 91dd03f..a7da507 100644 --- a/passKitTests/Models/PasswordTableEntryTest.swift +++ b/passKitTests/Models/PasswordTableEntryTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class PasswordTableEntryTest: XCTestCase { - func testExample() { let nameWithCategoryList = [ "github", @@ -27,13 +26,13 @@ class PasswordTableEntryTest: XCTestCase { ] let searchTextList1 = [ "github.com", - "www.github.com" + "www.github.com", ] let searchTextList2 = [ "xx.com", - "www.xx.com" + "www.xx.com", ] - + for nameWithCategory in nameWithCategoryList { for searchText in searchTextList1 { XCTAssertTrue(PasswordTableEntry.match(nameWithCategory: nameWithCategory, searchText: searchText)) @@ -43,5 +42,4 @@ class PasswordTableEntryTest: XCTestCase { } } } - } diff --git a/passKitTests/Models/PasswordTest.swift b/passKitTests/Models/PasswordTest.swift index 875372e..60a503d 100644 --- a/passKitTests/Models/PasswordTest.swift +++ b/passKitTests/Models/PasswordTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class PasswordTest: XCTestCase { - func testUrl() { let password = getPasswordObjectWith(content: "") @@ -245,7 +244,6 @@ class PasswordTest: XCTestCase { XCTAssertEqual(password.nameFromPath, "exampleusername") } - func testMultilineValues() { let lineBreakField = "with line breaks" => "|\n This is \n text spread over \n multiple lines! " let noLineBreakField = "without line breaks" => " > \n This is \n text spread over\n multiple lines!" diff --git a/passKitTests/Parser/AdditionFieldTest.swift b/passKitTests/Parser/AdditionFieldTest.swift index 4bceaef..42d408c 100644 --- a/passKitTests/Parser/AdditionFieldTest.swift +++ b/passKitTests/Parser/AdditionFieldTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class AdditionFieldTest: XCTestCase { - func testAdditionField() { let field1 = AdditionField(title: "key", content: "value") let field2 = AdditionField(title: "no content") diff --git a/passKitTests/Parser/ConstantsTest.swift b/passKitTests/Parser/ConstantsTest.swift index 1ff1771..b1b3d3f 100644 --- a/passKitTests/Parser/ConstantsTest.swift +++ b/passKitTests/Parser/ConstantsTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class ConstantsTest: XCTestCase { - func testIsOtpRelated() { XCTAssert(Constants.isOtpRelated(line: "otpauth://something")) XCTAssert(Constants.isOtpRelated(line: "otp_algorithm: algorithm")) diff --git a/passKitTests/Parser/OTPTypeTest.swift b/passKitTests/Parser/OTPTypeTest.swift index 64b6d3b..8c69bba 100644 --- a/passKitTests/Parser/OTPTypeTest.swift +++ b/passKitTests/Parser/OTPTypeTest.swift @@ -12,7 +12,6 @@ import XCTest @testable import passKit class OTPTypeTest: XCTestCase { - func testInitFromToken() { let secret = "secret".data(using: .utf8)! diff --git a/passKitTests/Parser/ParserTest.swift b/passKitTests/Parser/ParserTest.swift index ee0ba5a..1e4f867 100644 --- a/passKitTests/Parser/ParserTest.swift +++ b/passKitTests/Parser/ParserTest.swift @@ -6,11 +6,10 @@ // Copyright © 2018 Bob Sun. All rights reserved. // -@testable import passKit import XCTest +@testable import passKit class ParserTest: XCTestCase { - func testInit() { [ ("", "", "", []), diff --git a/passKitTests/Parser/TokenBuilderTest.swift b/passKitTests/Parser/TokenBuilderTest.swift index d072641..d65da40 100644 --- a/passKitTests/Parser/TokenBuilderTest.swift +++ b/passKitTests/Parser/TokenBuilderTest.swift @@ -13,7 +13,6 @@ import XCTest @testable import passKit class TokenBuilderTest: XCTestCase { - private let SECRET = "secret" private let DIGITS = Constants.DEFAULT_DIGITS private let TIMER = Generator.Factor.timer(period: Constants.DEFAULT_PERIOD) diff --git a/passKitTests/Passwords/PasswordGeneratorFlavorTest.swift b/passKitTests/Passwords/PasswordGeneratorFlavorTest.swift index 2289db0..f2f7f28 100644 --- a/passKitTests/Passwords/PasswordGeneratorFlavorTest.swift +++ b/passKitTests/Passwords/PasswordGeneratorFlavorTest.swift @@ -11,10 +11,9 @@ import XCTest @testable import passKit class PasswordGeneratorFlavorTest: XCTestCase { - func testLengthLimits() { // Ensure properly chosen length limits. So this check no longer needs to be performed in the code. - PasswordGeneratorFlavor.allCases.map { $0.lengthLimits }.forEach { + PasswordGeneratorFlavor.allCases.map(\.lengthLimits).forEach { XCTAssertLessThanOrEqual($0.min, $0.max) } } diff --git a/passKitTests/Passwords/PasswordGeneratorTest.swift b/passKitTests/Passwords/PasswordGeneratorTest.swift index 6b22bb0..05e66e4 100644 --- a/passKitTests/Passwords/PasswordGeneratorTest.swift +++ b/passKitTests/Passwords/PasswordGeneratorTest.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit class PasswordGeneratorTest: XCTestCase { - func testLimitedLength() { [ PasswordGenerator(length: 15), diff --git a/passKitTests/Testbase/DictBasedKeychain.swift b/passKitTests/Testbase/DictBasedKeychain.swift index cf3e7d4..94bc44d 100644 --- a/passKitTests/Testbase/DictBasedKeychain.swift +++ b/passKitTests/Testbase/DictBasedKeychain.swift @@ -21,15 +21,15 @@ class DictBasedKeychain: KeyStore { } public func contains(key: String) -> Bool { - return store[key] != nil + store[key] != nil } public func get(for key: String) -> Data? { - return store[key] as? Data + store[key] as? Data } public func get(for key: String) -> String? { - return store[key] as? String + store[key] as? String } public func removeContent(for key: String) { diff --git a/passKitTests/Testbase/TestBase.swift b/passKitTests/Testbase/TestBase.swift index fa21995..1483fdd 100644 --- a/passKitTests/Testbase/TestBase.swift +++ b/passKitTests/Testbase/TestBase.swift @@ -29,7 +29,7 @@ let MULTILINE_BLOCK_START = "multiline block" => "|" let MULTILINE_LINE_START = "multiline line" => ">" func getPasswordObjectWith(content: String, url: URL? = nil) -> Password { - return Password(name: "password", url: url ?? PASSWORD_URL, plainText: content) + Password(name: "password", url: url ?? PASSWORD_URL, plainText: content) } func assertDefaults(in password: Password, with passwordString: String, and additions: String, @@ -44,11 +44,11 @@ func assertDefaults(in password: Password, with passwordString: String, and addi } infix operator ∈: AdditionPrecedence -func ∈(field: AdditionField, password: Password) -> Bool { - return password.getFilteredAdditions().contains(field) +func ∈ (field: AdditionField, password: Password) -> Bool { + password.getFilteredAdditions().contains(field) } infix operator ∉: AdditionPrecedence -func ∉(field: AdditionField, password: Password) -> Bool { - return !(field ∈ password) +func ∉ (field: AdditionField, password: Password) -> Bool { + !(field ∈ password) } diff --git a/passKitTests/Testbase/TestPGPKeys.swift b/passKitTests/Testbase/TestPGPKeys.swift index 44ff586..bdee134 100644 --- a/passKitTests/Testbase/TestPGPKeys.swift +++ b/passKitTests/Testbase/TestPGPKeys.swift @@ -11,7 +11,6 @@ import XCTest @testable import passKit struct PGPTestSet { - fileprivate static var ALL_TEST_SETS: [String: PGPTestSet] = [:] let publicKey: String @@ -81,14 +80,14 @@ let NISTP384 = PGPTestSet( passphrase: "soirofssap" ).collect() -let RSA2048_RSA4096 = MultiKeyPGPTestSet( +let RSA2048_RSA4096 = MultiKeyPGPTestSet( publicKeys: PGP_RSA2048_PUBLIC_KEY | PGP_RSA4096_PUBLIC_KEY, privateKeys: PGP_RSA2048_PRIVATE_KEY | PGP_RSA4096_PRIVATE_KEY, fingerprints: ["a1024dae", "d862027e"], passphrases: ["passforios", "passforios"] ) -let ED25519_NISTP384 = MultiKeyPGPTestSet( +let ED25519_NISTP384 = MultiKeyPGPTestSet( publicKeys: PGP_ED25519_PUBLIC_KEY | PGP_NISTP384_PUBLIC_KEY, privateKeys: PGP_ED25519_PRIVATE_KEY | PGP_NISTP384_PRIVATE_KEY, fingerprints: ["e9444483", "5af3c085"], diff --git a/passKitTests/passKitTests.swift b/passKitTests/passKitTests.swift index 1ab8ed3..0832660 100644 --- a/passKitTests/passKitTests.swift +++ b/passKitTests/passKitTests.swift @@ -10,7 +10,6 @@ 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. @@ -28,9 +27,8 @@ class passKitTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measure { + measure { // Put the code you want to measure the time of here. } } - } diff --git a/passShortcuts/IntentHandler.swift b/passShortcuts/IntentHandler.swift index 294acd6..9c9b1a2 100644 --- a/passShortcuts/IntentHandler.swift +++ b/passShortcuts/IntentHandler.swift @@ -10,7 +10,6 @@ import Intents import passKit class IntentHandler: INExtension { - override func handler(for intent: INIntent) -> Any { guard intent is SyncRepositoryIntent else { fatalError("Unhandled intent type \(intent).") diff --git a/passShortcuts/SyncRepositoryIntentHandler.swift b/passShortcuts/SyncRepositoryIntentHandler.swift index 4e4b1e0..74dd026 100644 --- a/passShortcuts/SyncRepositoryIntentHandler.swift +++ b/passShortcuts/SyncRepositoryIntentHandler.swift @@ -10,7 +10,6 @@ import Intents import passKit public class SyncRepositoryIntentHandler: NSObject, SyncRepositoryIntentHandling { - private let passwordStore = PasswordStore.shared private let keychain = AppKeychain.shared @@ -24,7 +23,7 @@ public class SyncRepositoryIntentHandler: NSObject, SyncRepositoryIntentHandling } } - public func handle(intent: SyncRepositoryIntent, completion: @escaping (SyncRepositoryIntentResponse) -> Void) { + public func handle(intent _: SyncRepositoryIntent, completion: @escaping (SyncRepositoryIntentResponse) -> Void) { guard passwordStore.repositoryExists() else { completion(SyncRepositoryIntentResponse(code: .noRepository, userActivity: nil)) return diff --git a/passTests/passTests.swift b/passTests/passTests.swift index ae19270..d18d8d3 100644 --- a/passTests/passTests.swift +++ b/passTests/passTests.swift @@ -9,7 +9,6 @@ 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. @@ -27,9 +26,8 @@ class passTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measure { + measure { // Put the code you want to measure the time of here. } } - }