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

@ -1,8 +1,6 @@
github "SVProgressHUD/SVProgressHUD"
github "radex/SwiftyUserDefaults"
github "libgit2/objective-git"
# github "zahlz/SwiftPasscodeLock" "master"
github "yishilin14/SwiftPasscodeLock" "app-extension-support"
github "bitserf/FavIcon"
github "kishikawakatsumi/KeychainAccess"
github "mattrubin/OneTimePassword"

View file

@ -29,8 +29,6 @@
A26700371EEC475600176B8A /* passProcessor.js in Resources */ = {isa = PBXBuildFile; fileRef = A26700351EEC475600176B8A /* passProcessor.js */; };
A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2802BF71E70813A00879216 /* SliderTableViewCell.swift */; };
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 */; };
A2A61C131EEF90CB00CFE063 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
A2A61C151EEF90CB00CFE063 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA742D91E599ED400D54E16 /* KeychainAccess.framework */; };
@ -39,6 +37,9 @@
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */; };
A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */; };
A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */; };
A2C532BB201E5A9600DB9F53 /* PasscodeLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */; };
A2C532BE201E5AA100DB9F53 /* PasscodeLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */; };
A2C532BF201E5AA100DB9F53 /* PasscodeLockPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */; };
A2F4E2141EED800F0011986E /* GitCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2101EED800F0011986E /* GitCredential.swift */; };
A2F4E2151EED800F0011986E /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2111EED800F0011986E /* Password.swift */; };
A2F4E2161EED800F0011986E /* PasswordEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2121EED800F0011986E /* PasswordEntity.swift */; };
@ -61,7 +62,6 @@
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
DC13B1511E8640810097803F /* passTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13B1501E8640810097803F /* passTests.swift */; };
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; };
DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */; };
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */; };
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; };
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */; };
@ -191,8 +191,6 @@
A26700351EEC475600176B8A /* passProcessor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = passProcessor.js; sourceTree = "<group>"; };
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTableViewCell.swift; sourceTree = "<group>"; };
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SliderTableViewCell.xib; sourceTree = "<group>"; };
A28C66631EF109D600A398A1 /* PasscodeLockConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockConfiguration.swift; path = Models/PasscodeLockConfiguration.swift; sourceTree = "<group>"; };
A28C66641EF109D600A398A1 /* PasscodeLockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockRepository.swift; path = Models/PasscodeLockRepository.swift; sourceTree = "<group>"; };
A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeExtensionDisplay.swift; sourceTree = "<group>"; };
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 = "<group>"; };
A2A61C101EEF8E3500CFE063 /* libPods-passKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-passKit.a"; path = "Pods/../build/Debug-iphoneos/libPods-passKit.a"; sourceTree = "<group>"; };
@ -200,6 +198,9 @@
A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionViewController.swift; sourceTree = "<group>"; };
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = "<group>"; };
A2BC54C71EEE5669001FAFBD /* Objective-CBridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Objective-CBridgingHeader.h"; sourceTree = "<group>"; };
A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLock.swift; path = Models/PasscodeLock.swift; sourceTree = "<group>"; };
A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockViewController.swift; path = Controllers/PasscodeLockViewController.swift; sourceTree = "<group>"; };
A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockPresenter.swift; path = Controllers/PasscodeLockPresenter.swift; sourceTree = "<group>"; };
A2F4E2101EED800F0011986E /* GitCredential.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GitCredential.swift; path = Models/GitCredential.swift; sourceTree = "<group>"; };
A2F4E2111EED800F0011986E /* Password.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Password.swift; path = Models/Password.swift; sourceTree = "<group>"; };
A2F4E2121EED800F0011986E /* PasswordEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasswordEntity.swift; path = Models/PasswordEntity.swift; sourceTree = "<group>"; };
@ -315,7 +316,6 @@
files = (
A260758D1EEC6F34005DB03E /* passKit.framework in Frameworks */,
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */,
DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */,
18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -344,11 +344,12 @@
A26075791EEC6F34005DB03E /* passKit */ = {
isa = PBXGroup;
children = (
A2C532B9201DD07500DB9F53 /* Controllers */,
A2F4E20F1EED7F0A0011986E /* Helpers */,
A260757B1EEC6F34005DB03E /* Info.plist */,
A2F4E20E1EED7F040011986E /* Models */,
A26075A51EEC7125005DB03E /* pass.xcdatamodeld */,
A2F4E20F1EED7F0A0011986E /* Helpers */,
A260757A1EEC6F34005DB03E /* passKit.h */,
A260757B1EEC6F34005DB03E /* Info.plist */,
);
path = passKit;
sourceTree = "<group>";
@ -376,11 +377,19 @@
path = passExtension;
sourceTree = "<group>";
};
A2C532B9201DD07500DB9F53 /* Controllers */ = {
isa = PBXGroup;
children = (
A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */,
A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */,
);
name = Controllers;
sourceTree = "<group>";
};
A2F4E20E1EED7F040011986E /* Models */ = {
isa = PBXGroup;
children = (
A28C66631EF109D600A398A1 /* PasscodeLockConfiguration.swift */,
A28C66641EF109D600A398A1 /* PasscodeLockRepository.swift */,
A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */,
A2F4E2101EED800F0011986E /* GitCredential.swift */,
A2F4E2111EED800F0011986E /* Password.swift */,
A2F4E2121EED800F0011986E /* PasswordEntity.swift */,
@ -429,30 +438,30 @@
DC19400C1E4B39400077E0A3 /* Controllers */ = {
isa = PBXGroup;
children = (
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */,
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */,
DC5F385A1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift */,
DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */,
DC962CDE1E4B62C10033B5D8 /* AboutTableViewController.swift */,
DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */,
DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */,
DC037CA71E4B898100609409 /* BasicStaticTableViewController.swift */,
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */,
DCFB77A61E502DF9008DE471 /* EditPasswordTableViewController.swift */,
DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */,
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */,
DCA049991E335CC800522E8F /* GitServerSettingTableViewController.swift */,
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */,
A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */,
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */,
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */,
DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */,
DC5734AD1E439AD400D09270 /* PasswordsViewController.swift */,
DC5F385A1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift */,
DCA0499B1E3362F400522E8F /* PGPKeySettingTableViewController.swift */,
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */,
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */,
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */,
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */,
A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */,
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -477,21 +486,21 @@
DC19400F1E4B3A9E0077E0A3 /* Views */ = {
isa = PBXGroup;
children = (
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */,
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */,
DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */,
DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */,
DCFB779D1E4F40C7008DE471 /* FillPasswordTableViewCell.xib */,
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */,
DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */,
DC4914941E434301007FF592 /* LabelTableViewCell.swift */,
DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */,
DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */,
DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */,
DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */,
DCFB77A21E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib */,
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */,
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */,
DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */,
DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */,
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */,
DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */,
DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */,
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */,
DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */,
);
path = Views;
sourceTree = "<group>";
@ -984,7 +993,6 @@
"$(SRCROOT)/Carthage/Build/iOS/SVProgressHUD.framework",
"$(SRCROOT)/Carthage/Build/iOS/SwiftyUserDefaults.framework",
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework",
"$(SRCROOT)/Carthage/Build/iOS/PasscodeLock.framework",
"$(SRCROOT)/Carthage/Build/iOS/FavIcon.framework",
"$(SRCROOT)/Carthage/Build/iOS/KeychainAccess.framework",
"$(SRCROOT)/Carthage/Build/iOS/OneTimePassword.framework",
@ -1019,14 +1027,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A28C66661EF109D600A398A1 /* PasscodeLockRepository.swift in Sources */,
A2C532BB201E5A9600DB9F53 /* PasscodeLock.swift in Sources */,
A2F4E2151EED800F0011986E /* Password.swift in Sources */,
A28C66651EF109D600A398A1 /* PasscodeLockConfiguration.swift in Sources */,
A26075AD1EEC7125005DB03E /* pass.xcdatamodeld in Sources */,
A2F4E21E1EED80160011986E /* AppError.swift in Sources */,
A2F4E2171EED800F0011986E /* PasswordStore.swift in Sources */,
A2F4E2211EED80160011986E /* NotificationNames.swift in Sources */,
A2F4E2221EED80160011986E /* UITextFieldExtension.swift in Sources */,
A2C532BF201E5AA100DB9F53 /* PasscodeLockPresenter.swift in Sources */,
A2C532BE201E5AA100DB9F53 /* PasscodeLockViewController.swift in Sources */,
A2F4E2201EED80160011986E /* Globals.swift in Sources */,
A2F4E2231EED80160011986E /* Utils.swift in Sources */,
A2F4E21F1EED80160011986E /* DefaultsKeys.swift in Sources */,

View file

@ -8,7 +8,6 @@
import UIKit
import CoreData
import PasscodeLock
import SVProgressHUD
import passKit
@ -21,7 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
lazy var passcodeLockPresenter: PasscodeLockPresenter = {
let presenter = PasscodeLockPresenter(mainWindow: self.window, configuration: PasscodeLockConfiguration.shared)
let presenter = PasscodeLockPresenter(mainWindow: self.window)
return presenter
}()
@ -92,7 +91,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillEnterForeground(_ application: 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 = PasscodeLockPresenter(mainWindow: self.window, configuration: PasscodeLockConfiguration.shared)
passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel)
}

View file

@ -195,29 +195,12 @@
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="touchIDTableViewCell" textLabel="H2E-hP-Gyf" style="IBUITableViewCellStyleDefault" id="wB7-Km-Oel">
<rect key="frame" x="0.0" y="267" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wB7-Km-Oel" id="m90-X7-DbI">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Touch ID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="H2E-hP-Gyf">
<rect key="frame" x="20" y="0.0" width="374" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="6U8-ue-MhL">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="advancedTableViewCell" textLabel="MKj-d0-8q3" style="IBUITableViewCellStyleDefault" id="tQN-gu-iRe">
<rect key="frame" x="0.0" y="347" width="414" height="44"/>
<rect key="frame" x="0.0" y="303" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tQN-gu-iRe" id="Xs0-LN-r43">
<rect key="frame" x="0.0" y="0.0" width="376" height="43.666666666666664"/>
@ -241,7 +224,7 @@
<tableViewSection id="T7L-rR-R9W">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="aboutTableViewCell" textLabel="oqz-Hr-RAl" style="IBUITableViewCellStyleDefault" id="osS-xk-WRP">
<rect key="frame" x="0.0" y="427" width="414" height="44"/>
<rect key="frame" x="0.0" y="383" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="osS-xk-WRP" id="G6j-ij-rNr">
<rect key="frame" x="0.0" y="0.0" width="376" height="43.666666666666664"/>
@ -273,7 +256,6 @@
<outlet property="passcodeTableViewCell" destination="6Y0-mj-qhA" id="vkI-h5-GRo"/>
<outlet property="passwordRepositoryTableViewCell" destination="2rc-ZW-XKd" id="aFq-K7-eIj"/>
<outlet property="pgpKeyTableViewCell" destination="1ze-MS-Xbj" id="hXe-eD-0R4"/>
<outlet property="touchIDTableViewCell" destination="wB7-Km-Oel" id="0fi-Sb-qMa"/>
<segue destination="ZUt-x1-TJu" kind="showDetail" identifier="setPGPKeyByURLSegue" id="qRF-S1-bqF"/>
<segue destination="ffY-rC-jhq" kind="showDetail" identifier="setPGPKeyByASCIISegue" id="mgi-Oe-i2X"/>
</connections>

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

View file

@ -7,46 +7,14 @@
//
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)
}
@objc func cancelExtension() {
originalExtensionContest?.completeRequest(returningItems: [], completionHandler: nil)
}
}
class PasscodeExtensionDisplay {
private var isPasscodePresented = false
private let passcodeLockVC: PasscodeLockViewControllerForExtension
private let passcodeLockVC: PasscodeLockViewController
init(extensionContext: NSExtensionContext?) {
let cancelableEnter = CancelableEnterPasscodeState()
passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext, state: cancelableEnter, configuration: PasscodeLockConfiguration.shared)
passcodeLockVC = PasscodeLockViewController()
passcodeLockVC.dismissCompletionCallback = { [weak self] in
self?.dismiss()
}
@ -54,7 +22,7 @@ class PasscodeExtensionDisplay {
// 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 {
guard PasscodeLock.shared.hasPasscode && !isPasscodePresented == true else {
return
}
isPasscodePresented = true

View file

@ -0,0 +1,59 @@
//
// PasscodeLockPresenter.swift
// PasscodeLock
//
// Created by Yanko Dimitrov on 8/29/15.
// Copyright © 2015 Yanko Dimitrov. All rights reserved.
//
import UIKit
open class PasscodeLockPresenter {
fileprivate var mainWindow: UIWindow?
fileprivate lazy var passcodeLockWindow = UIWindow(frame: UIScreen.main.bounds)
open var isPasscodePresented = false
open let passcodeLockVC: PasscodeLockViewController
public init(mainWindow window: UIWindow?, viewController: PasscodeLockViewController) {
mainWindow = window
passcodeLockVC = viewController
}
public convenience init(mainWindow window: UIWindow?) {
let passcodeLockVC = PasscodeLockViewController()
self.init(mainWindow: window, viewController: passcodeLockVC)
}
open func present(windowLevel: CGFloat?) {
guard PasscodeLock.shared.hasPasscode else { return }
guard !isPasscodePresented else { return }
isPasscodePresented = true
mainWindow?.endEditing(true)
moveWindowsToFront(windowLevel: windowLevel)
passcodeLockWindow.isHidden = false
let userDismissCompletionCallback = passcodeLockVC.dismissCompletionCallback
passcodeLockVC.dismissCompletionCallback = { [weak self] in
userDismissCompletionCallback?()
self?.dismiss()
}
passcodeLockWindow.rootViewController = passcodeLockVC
}
open func dismiss() {
isPasscodePresented = false
passcodeLockWindow.isHidden = true
passcodeLockWindow.rootViewController = nil
}
fileprivate func moveWindowsToFront(windowLevel: CGFloat?) {
let windowLevel = windowLevel ?? UIWindowLevelNormal
let maxWinLevel = max(windowLevel, UIWindowLevelNormal)
passcodeLockWindow.windowLevel = maxWinLevel + 1
}
}

View file

@ -0,0 +1,125 @@
//
// PasscodeLockViewController.swift
// PasscodeLock
//
// Created by Yanko Dimitrov on 8/28/15.
// Copyright © 2015 Yanko Dimitrov. All rights reserved.
//
import UIKit
import LocalAuthentication
open class PasscodeLockViewController: UIViewController {
open var dismissCompletionCallback: (()->Void)?
open var successCallback: (()->Void)?
open var cancelCallback: (()->Void)?
lazy var enterPasscodeAlert: UIAlertController = {
let enterPasscodeAlert = UIAlertController(title: "Authenticate Pass", message: "Unlock with passcode for Pass", preferredStyle: .alert)
enterPasscodeAlert.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
textField.placeholder = "passcode"
textField.isSecureTextEntry = true
textField.addTarget(self, action: #selector(self.passcodeTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
textField.clearButtonMode = UITextFieldViewMode.whileEditing
textField.becomeFirstResponder()
})
let myContext = LAContext()
var authError: NSError?
if #available(iOS 8.0, macOS 10.12.1, *) {
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
var biometryType = "Touch ID"
if #available(iOS 11.0, *) {
if myContext.biometryType == LABiometryType.faceID {
biometryType = "Face ID"
}
}
let bioAction = UIAlertAction(title: "Use " + biometryType, style: .default) { (action:UIAlertAction) -> Void in
self.authenticate()
}
enterPasscodeAlert.addAction(bioAction)
}
}
return enterPasscodeAlert
}()
open override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
authenticate()
}
internal func dismissPasscodeLock(completionHandler: (() -> Void)? = nil) {
// clean up the textfield
enterPasscodeAlert.textFields?[0].text = ""
if presentingViewController?.presentedViewController == self {
// if presented as modal
dismiss(animated: true, completion: { [weak self] in
self?.dismissCompletionCallback?()
completionHandler?()
})
// if pushed in a navigation controller
} else {
_ = navigationController?.popViewController(animated: true)
dismissCompletionCallback?()
completionHandler?()
}
}
// MARK: - PasscodeLockDelegate
open func passcodeLockDidSucceed() {
dismissPasscodeLock(completionHandler: successCallback)
}
open func passcodeLockDidCancel() {
dismissPasscodeLock(completionHandler: cancelCallback)
}
public func authenticate() {
print(enterPasscodeAlert.isBeingPresented)
let myContext = LAContext()
let myLocalizedReasonString = "Authentication is needed to access Pass."
var authError: NSError?
if #available(iOS 8.0, *) {
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, evaluateError in
if success {
DispatchQueue.main.async {
// user authenticated successfully, take appropriate action
self.passcodeLockDidSucceed()
}
} else {
// User did not authenticate successfully
self.showPasswordAlert()
}
}
} else {
// could not evaluate policy; look at authError and present an appropriate message to user
self.showPasswordAlert()
}
} else {
// fallback on earlier versions
self.showPasswordAlert()
}
}
@objc func passcodeTextFieldDidChange(_ sender: UITextField) {
// check whether the passcode is correct
if PasscodeLock.shared.check(passcode: sender.text ?? "") {
self.passcodeLockDidSucceed()
}
}
func showPasswordAlert() {
self.present(enterPasscodeAlert, animated: true, completion: nil)
}
}

View file

@ -1,28 +1,24 @@
//
// PasscodeRepository.swift
// pass
// PasscodeLock.swift
// PassKit
//
// Created by Mingshen Sun on 7/2/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
// Created by Yishi Lin on 28/1/2018.
// Copyright © 2017 Yishi Lin. All rights reserved.
//
import Foundation
import PasscodeLock
import LocalAuthentication
public class PasscodeLockRepository: PasscodeRepositoryType {
private let passcodeKey = "passcode.lock.passcode"
open class PasscodeLock {
public static let shared = PasscodeLock()
public var hasPasscode: Bool {
if passcode != nil {
return true
}
return false
fileprivate let passcodeKey = "passcode.lock.passcode"
fileprivate var passcode: String? {
return SharedDefaults[.passcodeKey]
}
private var passcode: String? {
return SharedDefaults[.passcodeKey]
public var hasPasscode: Bool {
return passcode != nil
}
public func save(passcode: String) {

View file

@ -1,26 +0,0 @@
//
// PasscodeLockConfiguration.swift
// pass
//
// Created by Mingshen Sun on 7/2/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import Foundation
import PasscodeLock
public class PasscodeLockConfiguration: PasscodeLockConfigurationType {
public static let shared = PasscodeLockConfiguration()
public let repository: PasscodeRepositoryType
public let passcodeLength = 4
public var isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
public let shouldRequestTouchIDImmediately = true
public let maximumInccorectPasscodeAttempts = 3
init() {
self.repository = PasscodeLockRepository()
}
}