Self-maintained passcode lock

- No cancel button anywhere in the passcode lock yet
- Poor UI
This commit is contained in:
Yishi Lin 2018-01-29 03:23:34 +08:00
parent 30ae08bed5
commit da3c4f0bc0
10 changed files with 298 additions and 210 deletions

View file

@ -9,25 +9,16 @@
import UIKit
import SVProgressHUD
import CoreData
import PasscodeLock
import LocalAuthentication
import passKit
class SettingsTableViewController: UITableViewController, UITabBarControllerDelegate {
lazy var touchIDSwitch: UISwitch = {
let uiSwitch = UISwitch(frame: CGRect.zero)
uiSwitch.onTintColor = Globals.blue
uiSwitch.addTarget(self, action: #selector(touchIDSwitchAction), for: UIControlEvents.valueChanged)
return uiSwitch
}()
@IBOutlet weak var pgpKeyTableViewCell: UITableViewCell!
@IBOutlet weak var touchIDTableViewCell: UITableViewCell!
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
var setPasscodeLockAlert: UIAlertController?
let passwordStore = PasswordStore.shared
var passcodeLockConfig = PasscodeLockConfiguration.shared
var passcodeLock = PasscodeLock.shared
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
navigationController?.popViewController(animated: true)
@ -123,14 +114,6 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Security section, hide TouchID if the device doesn't support
if section == 1 {
if hasTouchID() {
return 2
} else {
return 1
}
}
return super.tableView(tableView, numberOfRowsInSection: section)
}
@ -138,10 +121,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
touchIDTableViewCell.accessoryView = touchIDSwitch
setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText()
setPasscodeLockTouchIDCells()
setPasscodeLockCell()
}
override func viewWillAppear(_ animated: Bool) {
@ -149,38 +131,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
tabBarController!.delegate = self
}
private func hasTouchID() -> Bool {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) {
return true
} else {
switch error!.code {
case LAError.Code.touchIDNotEnrolled.rawValue:
return true
case LAError.Code.passcodeNotSet.rawValue:
return true
default:
return false
}
}
}
private func isTouchIDEnabled() -> Bool {
let context = LAContext()
return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
}
private func setPasscodeLockTouchIDCells() {
if passcodeLockConfig.repository.hasPasscode {
private func setPasscodeLockCell() {
if passcodeLock.hasPasscode {
self.passcodeTableViewCell.detailTextLabel?.text = "On"
passcodeLockConfig.isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
} else {
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
SharedDefaults[.isTouchIDOn] = false
passcodeLockConfig.isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
}
}
@ -203,10 +158,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
@objc func actOnPasswordStoreErasedNotification() {
setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText()
setPasscodeLockTouchIDCells()
setPasscodeLockCell()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: passcodeLockConfig)
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
@ -221,22 +176,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
}
tableView.deselectRow(at: indexPath, animated: true)
}
@objc func touchIDSwitchAction(uiSwitch: UISwitch) {
if !passcodeLockConfig.repository.hasPasscode || !isTouchIDEnabled() {
// switch off
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
uiSwitch.isOn = SharedDefaults[.isTouchIDOn] // SharedDefaults[.isTouchIDOn] should be false
Utils.alert(title: "Notice", message: "Please enable Touch ID of your phone and setup the passcode lock for Pass.", controller: self, completion: nil)
}
} else {
SharedDefaults[.isTouchIDOn] = uiSwitch.isOn
passcodeLockConfig.isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: passcodeLockConfig)
}
func showPGPKeyActionSheet() {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
var urlActionTitle = "Download from URL"
@ -314,21 +254,22 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
}
func showPasscodeActionSheet() {
let passcodeChangeViewController = PasscodeLockViewController(state: .change, configuration: passcodeLockConfig)
let passcodeRemoveViewController = PasscodeLockViewController(state: .remove, configuration: passcodeLockConfig)
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let passcodeRemoveViewController = PasscodeLockViewController()
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
passcodeRemoveViewController.successCallback = { _ in
self?.setPasscodeLockTouchIDCells()
passcodeRemoveViewController.successCallback = {
self?.passcodeLock.delete()
self?.setPasscodeLockCell()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: (self?.passcodeLockConfig)!)
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window)
}
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
}
let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in
self?.present(passcodeChangeViewController, animated: true, completion: nil)
self?.setPasscodeLock()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
@ -339,12 +280,50 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds
self.present(optionMenu, animated: true, completion: nil)
}
@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],
let setPasscodeLockAlertTextFields1 = setPasscodeLockAlert.textFields?[1] {
if sender == setPasscodeLockAlertTextFields0 || sender == setPasscodeLockAlertTextFields1 {
// two passwords should be the same, and length >= 4
let passcodeText = setPasscodeLockAlertTextFields0.text!
let passcodeConfirmationText = setPasscodeLockAlertTextFields1.text!
setPasscodeLockAlert.actions[0].isEnabled = passcodeText == passcodeConfirmationText && passcodeText.count >= 4
}
}
}
func setPasscodeLock() {
let passcodeSetViewController = PasscodeLockViewController(state: .set, configuration: passcodeLockConfig)
passcodeSetViewController.successCallback = { _ in
self.setPasscodeLockTouchIDCells()
// prepare the alert for setting the passcode
setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert)
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
textField.placeholder = "Password"
textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
})
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
textField.placeholder = "Password Confirmation"
textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
})
// save action
let saveAction = UIAlertAction(title: "Save", style: .default) { (action:UIAlertAction) -> Void in
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
self.passcodeLock.save(passcode: passcode)
// refresh the passcode lock cell ("On")
self.setPasscodeLockCell()
}
present(passcodeSetViewController, animated: true, completion: nil)
saveAction.isEnabled = false // disable the Save button by default
// cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
// present
setPasscodeLockAlert?.addAction(saveAction)
setPasscodeLockAlert?.addAction(cancelAction)
self.present(setPasscodeLockAlert!, animated: true, completion: nil)
}
}