Format code with SwiftFormat automatically in every build

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

View file

@ -6,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 {
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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) {

View file

@ -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?) {

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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?) {}

View file

@ -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()
}

View file

@ -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?) {

View file

@ -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?) {

View file

@ -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
}
}

View file

@ -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()