From fb5f689540e7afdfa4ea94d90fb9f2cb6bcbf2eb Mon Sep 17 00:00:00 2001 From: Yishi Lin Date: Wed, 14 Jun 2017 19:14:56 +0800 Subject: [PATCH] Add passcode lock for extension --- pass.xcodeproj/project.pbxproj | 4 ++ passextension/ExtensionViewController.swift | 11 +++- passextension/PasscodeExtensionDisplay.swift | 67 ++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 passextension/PasscodeExtensionDisplay.swift diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 1e089d6..b61f9b8 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2802BF81E70813A00879216 /* SliderTableViewCell.xib */; }; A28C66651EF109D600A398A1 /* PasscodeLockConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A28C66631EF109D600A398A1 /* PasscodeLockConfiguration.swift */; }; A28C66661EF109D600A398A1 /* PasscodeLockRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A28C66641EF109D600A398A1 /* PasscodeLockRepository.swift */; }; + A28C66681EF10EC900A398A1 /* PasscodeExtensionDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */; }; A2A61C121EEF8E4600CFE063 /* libObjectivePGP.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A2227D541EEE5E78002A69A9 /* libObjectivePGP.a */; }; A2A61C131EEF90CB00CFE063 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; }; A2A61C151EEF90CB00CFE063 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA742D91E599ED400D54E16 /* KeychainAccess.framework */; }; @@ -189,6 +190,7 @@ A2802BF81E70813A00879216 /* SliderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SliderTableViewCell.xib; sourceTree = ""; }; A28C66631EF109D600A398A1 /* PasscodeLockConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockConfiguration.swift; path = Models/PasscodeLockConfiguration.swift; sourceTree = ""; }; A28C66641EF109D600A398A1 /* PasscodeLockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockRepository.swift; path = Models/PasscodeLockRepository.swift; sourceTree = ""; }; + A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeExtensionDisplay.swift; sourceTree = ""; }; A2A61C0C1EEF8DFE00CFE063 /* libPods-passextension.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-passextension.a"; path = "../../Library/Developer/Xcode/DerivedData/pass-fwlmfsjroyvbfhdyqmglrwfhvjli/Build/Products/Debug-iphonesimulator/libPods-passextension.a"; sourceTree = ""; }; A2A61C101EEF8E3500CFE063 /* libPods-passKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-passKit.a"; path = "Pods/../build/Debug-iphoneos/libPods-passKit.a"; sourceTree = ""; }; A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilsExtension.swift; sourceTree = ""; }; @@ -343,6 +345,7 @@ A267002B1EEC466A00176B8A /* Info.plist */, A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */, A2367B9A1EEFE1B300C8FE8B /* UtilsExtension.swift */, + A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */, ); path = passextension; sourceTree = ""; @@ -941,6 +944,7 @@ buildActionMask = 2147483647; files = ( A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */, + A28C66681EF10EC900A398A1 /* PasscodeExtensionDisplay.swift in Sources */, A2367B9B1EEFE1B300C8FE8B /* UtilsExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/passextension/ExtensionViewController.swift b/passextension/ExtensionViewController.swift index 35b6611..17e55af 100644 --- a/passextension/ExtensionViewController.swift +++ b/passextension/ExtensionViewController.swift @@ -33,6 +33,11 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV private var passwordsTableEntries: [PasswordsTableEntry] = [] private var filteredPasswordsTableEntries: [PasswordsTableEntry] = [] + private lazy var passcodelock: PasscodeExtensionDisplay = { + let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext) + return passcodelock + }() + private func initPasswordsTableEntries() { passwordsTableEntries.removeAll() filteredPasswordsTableEntries.removeAll() @@ -43,9 +48,13 @@ class ExtensionViewController: UIViewController, UITableViewDataSource, UITableV } } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + passcodelock.presentPasscodeLockIfNeeded(self) + } + override func viewDidLoad() { super.viewDidLoad() - // prepare searchBar.delegate = self tableView.delegate = self diff --git a/passextension/PasscodeExtensionDisplay.swift b/passextension/PasscodeExtensionDisplay.swift new file mode 100644 index 0000000..d6c4fd9 --- /dev/null +++ b/passextension/PasscodeExtensionDisplay.swift @@ -0,0 +1,67 @@ +// +// PasscodeLockDisplay.swift +// pass +// +// Created by Yishi Lin on 14/6/17. +// Copyright © 2017 Bob Sun. All rights reserved. +// + +import Foundation +import PasscodeLock +import passKit + +// add a cancel button in the passcode lock view +struct CancelableEnterPasscodeState: PasscodeLockStateType { + let title: String = "Enter passcode" + let description: String = "Enter passcode" + let isCancellableAction = true + var isTouchIDAllowed = true + mutating func accept(passcode: String, from lock: PasscodeLockType) { + if lock.repository.check(passcode: passcode) { + lock.delegate?.passcodeLockDidSucceed(lock) + } + } +} + +// cancel means cancel the extension +class PasscodeLockViewControllerForExtension: PasscodeLockViewController { + var originalExtensionContest: NSExtensionContext? + public convenience init(extensionContext: NSExtensionContext?, state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) { + self.init(state: state, configuration: configuration, animateOnDismiss: animateOnDismiss) + originalExtensionContest = extensionContext + } + override func viewDidLoad() { + super.viewDidLoad() + cancelButton?.removeTarget(nil, action: nil, for: .allEvents) + cancelButton?.addTarget(self, action: #selector(cancelExtension), for: .touchUpInside) + } + func cancelExtension() { + originalExtensionContest?.completeRequest(returningItems: [], completionHandler: nil) + } +} + +class PasscodeExtensionDisplay { + private var isPasscodePresented = false + private let passcodeLockVC: PasscodeLockViewControllerForExtension + + init(extensionContext: NSExtensionContext?) { + let cancelableEnter = CancelableEnterPasscodeState() + passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext, state: cancelableEnter, configuration: PasscodeLockConfiguration.shared) + passcodeLockVC.dismissCompletionCallback = { [weak self] in + self?.dismiss() + } + } + + // present the passcode lock view if passcode is set and the view controller is not presented + func presentPasscodeLockIfNeeded(_ extensionVC: ExtensionViewController) { + guard PasscodeLockConfiguration.shared.repository.hasPasscode && !isPasscodePresented == true else { + return + } + isPasscodePresented = true + extensionVC.present(passcodeLockVC, animated: true, completion: nil) + } + + func dismiss(animated: Bool = true) { + isPasscodePresented = false + } +}