Merge branch 'release/0.3.1'
This commit is contained in:
commit
620e11be46
27 changed files with 584 additions and 260 deletions
5
Cartfile
5
Cartfile
|
|
@ -1,8 +1,7 @@
|
||||||
github "SVProgressHUD/SVProgressHUD"
|
github "SVProgressHUD/SVProgressHUD"
|
||||||
github "radex/SwiftyUserDefaults"
|
github "radex/SwiftyUserDefaults"
|
||||||
github "libgit2/objective-git"
|
github "libgit2/objective-git"
|
||||||
# github "zahlz/SwiftPasscodeLock" "master"
|
github "leonbreedt/FavIcon"
|
||||||
github "yishilin14/SwiftPasscodeLock" "app-extension-support"
|
|
||||||
github "bitserf/FavIcon"
|
|
||||||
github "kishikawakatsumi/KeychainAccess"
|
github "kishikawakatsumi/KeychainAccess"
|
||||||
github "mattrubin/OneTimePassword"
|
github "mattrubin/OneTimePassword"
|
||||||
|
github "jpsim/Yams"
|
||||||
|
|
|
||||||
2
Podfile
2
Podfile
|
|
@ -2,7 +2,7 @@ platform :ios, '10.2'
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
target 'passKit' do
|
target 'passKit' do
|
||||||
pod 'ObjectivePGP', :git => 'https://github.com/krzyzanowskim/ObjectivePGP.git', :tag => '0.10.0-beta2'
|
pod 'ObjectivePGP', :git => 'https://github.com/krzyzanowskim/ObjectivePGP.git', :tag => '0.10.0'
|
||||||
target 'pass' do
|
target 'pass' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<img src="icon/icon_round.png" width="76"/>
|
<img src="icon/icon_round.png" width="76"/>
|
||||||
|
|
||||||
# Pass
|
# Pass
|
||||||
[](https://github.com/mssun/pass-ios/releases)
|
[](https://github.com/mssun/passforios/releases)
|
||||||

|

|
||||||
[](https://gitter.im/passforios/passforios)
|
[](https://gitter.im/passforios/passforios)
|
||||||
[](https://travis-ci.org/mssun/passforios)
|
[](https://travis-ci.org/mssun/passforios)
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ platform :ios do
|
||||||
)
|
)
|
||||||
# ensure_git_status_clean
|
# ensure_git_status_clean
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number(version: get_version_number, initial_build_number: 0) + 1,
|
build_number: latest_testflight_build_number(version: get_version_number(target: "pass"), initial_build_number: 0) + 1,
|
||||||
xcodeproj: "pass.xcodeproj"
|
xcodeproj: "pass.xcodeproj"
|
||||||
)
|
)
|
||||||
# commit_version_bump(xcodeproj: "pass.xcodeproj")
|
# commit_version_bump(xcodeproj: "pass.xcodeproj")
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */; };
|
18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */; };
|
||||||
23B82F0228254275DBA609E7 /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B975797E0F0B7476CADD6A7D /* Pods_passExtension.framework */; };
|
23B82F0228254275DBA609E7 /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B975797E0F0B7476CADD6A7D /* Pods_passExtension.framework */; };
|
||||||
|
3012B06D2039D6E400BE1793 /* Yams.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3012B06C2039D6E400BE1793 /* Yams.framework */; };
|
||||||
61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; };
|
61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; };
|
||||||
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; };
|
||||||
A2168A7F1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */; };
|
A2168A7F1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */; };
|
||||||
|
|
@ -29,8 +30,6 @@
|
||||||
A26700371EEC475600176B8A /* passProcessor.js in Resources */ = {isa = PBXBuildFile; fileRef = A26700351EEC475600176B8A /* passProcessor.js */; };
|
A26700371EEC475600176B8A /* passProcessor.js in Resources */ = {isa = PBXBuildFile; fileRef = A26700351EEC475600176B8A /* passProcessor.js */; };
|
||||||
A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2802BF71E70813A00879216 /* SliderTableViewCell.swift */; };
|
A2802BF91E70813A00879216 /* SliderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2802BF71E70813A00879216 /* SliderTableViewCell.swift */; };
|
||||||
A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2802BF81E70813A00879216 /* SliderTableViewCell.xib */; };
|
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 */; };
|
A28C66681EF10EC900A398A1 /* PasscodeExtensionDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A28C66671EF10EC900A398A1 /* PasscodeExtensionDisplay.swift */; };
|
||||||
A2A61C131EEF90CB00CFE063 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
|
A2A61C131EEF90CB00CFE063 /* Base32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A262A58C1E68749C006B0890 /* Base32.framework */; };
|
||||||
A2A61C151EEF90CB00CFE063 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA742D91E599ED400D54E16 /* KeychainAccess.framework */; };
|
A2A61C151EEF90CB00CFE063 /* KeychainAccess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA742D91E599ED400D54E16 /* KeychainAccess.framework */; };
|
||||||
|
|
@ -39,6 +38,10 @@
|
||||||
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */; };
|
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */; };
|
||||||
A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */; };
|
A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */; };
|
||||||
A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */; };
|
A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */; };
|
||||||
|
A2BEC1BB207D2EFE00F3051C /* UIViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2BEC1BA207D2EFE00F3051C /* UIViewExtension.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 */; };
|
A2F4E2141EED800F0011986E /* GitCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2101EED800F0011986E /* GitCredential.swift */; };
|
||||||
A2F4E2151EED800F0011986E /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2111EED800F0011986E /* Password.swift */; };
|
A2F4E2151EED800F0011986E /* Password.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2111EED800F0011986E /* Password.swift */; };
|
||||||
A2F4E2161EED800F0011986E /* PasswordEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2121EED800F0011986E /* PasswordEntity.swift */; };
|
A2F4E2161EED800F0011986E /* PasswordEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2F4E2121EED800F0011986E /* PasswordEntity.swift */; };
|
||||||
|
|
@ -61,7 +64,6 @@
|
||||||
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
|
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
|
||||||
DC13B1511E8640810097803F /* passTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13B1501E8640810097803F /* passTests.swift */; };
|
DC13B1511E8640810097803F /* passTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13B1501E8640810097803F /* passTests.swift */; };
|
||||||
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.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 */; };
|
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */; };
|
||||||
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; };
|
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; };
|
||||||
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */; };
|
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */; };
|
||||||
|
|
@ -157,6 +159,7 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
3012B06C2039D6E400BE1793 /* Yams.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Yams.framework; path = Carthage/Build/iOS/Yams.framework; sourceTree = "<group>"; };
|
||||||
31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
666769E0B255666D02945C15 /* Pods-passKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-passKitTests/Pods-passKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
666769E0B255666D02945C15 /* Pods-passKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-passKitTests/Pods-passKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
|
@ -191,8 +194,6 @@
|
||||||
A26700351EEC475600176B8A /* passProcessor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = passProcessor.js; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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 +201,10 @@
|
||||||
A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionViewController.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
A2BC54C71EEE5669001FAFBD /* Objective-CBridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Objective-CBridgingHeader.h"; sourceTree = "<group>"; };
|
||||||
|
A2BEC1BA207D2EFE00F3051C /* UIViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIViewExtension.swift; path = Helpers/UIViewExtension.swift; 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>"; };
|
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>"; };
|
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>"; };
|
A2F4E2121EED800F0011986E /* PasswordEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasswordEntity.swift; path = Models/PasswordEntity.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -315,8 +320,8 @@
|
||||||
files = (
|
files = (
|
||||||
A260758D1EEC6F34005DB03E /* passKit.framework in Frameworks */,
|
A260758D1EEC6F34005DB03E /* passKit.framework in Frameworks */,
|
||||||
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */,
|
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */,
|
||||||
DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */,
|
|
||||||
18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */,
|
18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */,
|
||||||
|
3012B06D2039D6E400BE1793 /* Yams.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -344,11 +349,12 @@
|
||||||
A26075791EEC6F34005DB03E /* passKit */ = {
|
A26075791EEC6F34005DB03E /* passKit */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A2C532B9201DD07500DB9F53 /* Controllers */,
|
||||||
|
A2F4E20F1EED7F0A0011986E /* Helpers */,
|
||||||
|
A260757B1EEC6F34005DB03E /* Info.plist */,
|
||||||
A2F4E20E1EED7F040011986E /* Models */,
|
A2F4E20E1EED7F040011986E /* Models */,
|
||||||
A26075A51EEC7125005DB03E /* pass.xcdatamodeld */,
|
A26075A51EEC7125005DB03E /* pass.xcdatamodeld */,
|
||||||
A2F4E20F1EED7F0A0011986E /* Helpers */,
|
|
||||||
A260757A1EEC6F34005DB03E /* passKit.h */,
|
A260757A1EEC6F34005DB03E /* passKit.h */,
|
||||||
A260757B1EEC6F34005DB03E /* Info.plist */,
|
|
||||||
);
|
);
|
||||||
path = passKit;
|
path = passKit;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -376,11 +382,19 @@
|
||||||
path = passExtension;
|
path = passExtension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A2C532B9201DD07500DB9F53 /* Controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */,
|
||||||
|
A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */,
|
||||||
|
);
|
||||||
|
name = Controllers;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A2F4E20E1EED7F040011986E /* Models */ = {
|
A2F4E20E1EED7F040011986E /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A28C66631EF109D600A398A1 /* PasscodeLockConfiguration.swift */,
|
A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */,
|
||||||
A28C66641EF109D600A398A1 /* PasscodeLockRepository.swift */,
|
|
||||||
A2F4E2101EED800F0011986E /* GitCredential.swift */,
|
A2F4E2101EED800F0011986E /* GitCredential.swift */,
|
||||||
A2F4E2111EED800F0011986E /* Password.swift */,
|
A2F4E2111EED800F0011986E /* Password.swift */,
|
||||||
A2F4E2121EED800F0011986E /* PasswordEntity.swift */,
|
A2F4E2121EED800F0011986E /* PasswordEntity.swift */,
|
||||||
|
|
@ -398,6 +412,7 @@
|
||||||
A2F4E21B1EED80160011986E /* NotificationNames.swift */,
|
A2F4E21B1EED80160011986E /* NotificationNames.swift */,
|
||||||
A2F4E21C1EED80160011986E /* UITextFieldExtension.swift */,
|
A2F4E21C1EED80160011986E /* UITextFieldExtension.swift */,
|
||||||
A2F4E21D1EED80160011986E /* Utils.swift */,
|
A2F4E21D1EED80160011986E /* Utils.swift */,
|
||||||
|
A2BEC1BA207D2EFE00F3051C /* UIViewExtension.swift */,
|
||||||
);
|
);
|
||||||
name = Helpers;
|
name = Helpers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -429,30 +444,30 @@
|
||||||
DC19400C1E4B39400077E0A3 /* Controllers */ = {
|
DC19400C1E4B39400077E0A3 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */,
|
|
||||||
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */,
|
|
||||||
DC5F385A1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift */,
|
|
||||||
DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */,
|
DC037CB11E4CAB1700609409 /* AboutRepositoryTableViewController.swift */,
|
||||||
DC962CDE1E4B62C10033B5D8 /* AboutTableViewController.swift */,
|
DC962CDE1E4B62C10033B5D8 /* AboutTableViewController.swift */,
|
||||||
DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */,
|
DC037CB71E4DD1A500609409 /* AddPasswordTableViewController.swift */,
|
||||||
DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */,
|
DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */,
|
||||||
DC037CA71E4B898100609409 /* BasicStaticTableViewController.swift */,
|
DC037CA71E4B898100609409 /* BasicStaticTableViewController.swift */,
|
||||||
|
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */,
|
||||||
DCFB77A61E502DF9008DE471 /* EditPasswordTableViewController.swift */,
|
DCFB77A61E502DF9008DE471 /* EditPasswordTableViewController.swift */,
|
||||||
DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */,
|
DC037CAF1E4CA51F00609409 /* GeneralSettingsTableViewController.swift */,
|
||||||
|
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */,
|
||||||
DCA049991E335CC800522E8F /* GitServerSettingTableViewController.swift */,
|
DCA049991E335CC800522E8F /* GitServerSettingTableViewController.swift */,
|
||||||
|
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
|
||||||
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */,
|
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */,
|
||||||
|
A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */,
|
||||||
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */,
|
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */,
|
||||||
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */,
|
|
||||||
DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */,
|
DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */,
|
||||||
DC5734AD1E439AD400D09270 /* PasswordsViewController.swift */,
|
DC5734AD1E439AD400D09270 /* PasswordsViewController.swift */,
|
||||||
|
DC5F385A1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift */,
|
||||||
DCA0499B1E3362F400522E8F /* PGPKeySettingTableViewController.swift */,
|
DCA0499B1E3362F400522E8F /* PGPKeySettingTableViewController.swift */,
|
||||||
|
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */,
|
||||||
|
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */,
|
||||||
|
DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */,
|
||||||
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
|
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
|
||||||
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
|
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
|
||||||
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
|
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
|
||||||
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
|
|
||||||
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */,
|
|
||||||
A217ACE11E9AB17C00A1A6CF /* OTPScannerController.swift */,
|
|
||||||
A217ACE31E9BBBBD00A1A6CF /* GitConfigSettingTableViewController.swift */,
|
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -477,21 +492,21 @@
|
||||||
DC19400F1E4B3A9E0077E0A3 /* Views */ = {
|
DC19400F1E4B3A9E0077E0A3 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */,
|
DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */,
|
||||||
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */,
|
|
||||||
DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */,
|
DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */,
|
||||||
DCFB779D1E4F40C7008DE471 /* FillPasswordTableViewCell.xib */,
|
DCFB779D1E4F40C7008DE471 /* FillPasswordTableViewCell.xib */,
|
||||||
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */,
|
|
||||||
DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */,
|
|
||||||
DC4914941E434301007FF592 /* LabelTableViewCell.swift */,
|
DC4914941E434301007FF592 /* LabelTableViewCell.swift */,
|
||||||
DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */,
|
DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */,
|
||||||
DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */,
|
|
||||||
DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */,
|
|
||||||
DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */,
|
DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */,
|
||||||
DCFB77A21E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib */,
|
DCFB77A21E500D9C008DE471 /* PasswordDetailTitleTableViewCell.xib */,
|
||||||
|
A2802BF71E70813A00879216 /* SliderTableViewCell.swift */,
|
||||||
|
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */,
|
||||||
|
DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */,
|
||||||
|
DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */,
|
||||||
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */,
|
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */,
|
||||||
DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */,
|
DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */,
|
||||||
DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */,
|
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */,
|
||||||
|
DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -542,6 +557,7 @@
|
||||||
DC917BED1E2F38C4000FDF54 /* Frameworks */ = {
|
DC917BED1E2F38C4000FDF54 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3012B06C2039D6E400BE1793 /* Yams.framework */,
|
||||||
A2A61C101EEF8E3500CFE063 /* libPods-passKit.a */,
|
A2A61C101EEF8E3500CFE063 /* libPods-passKit.a */,
|
||||||
A2A61C0C1EEF8DFE00CFE063 /* libPods-passExtension.a */,
|
A2A61C0C1EEF8DFE00CFE063 /* libPods-passExtension.a */,
|
||||||
A2227D541EEE5E78002A69A9 /* libObjectivePGP.a */,
|
A2227D541EEE5E78002A69A9 /* libObjectivePGP.a */,
|
||||||
|
|
@ -693,7 +709,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0830;
|
LastSwiftUpdateCheck = 0830;
|
||||||
LastUpgradeCheck = 0900;
|
LastUpgradeCheck = 0930;
|
||||||
ORGANIZATIONNAME = "Bob Sun";
|
ORGANIZATIONNAME = "Bob Sun";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
A26075771EEC6F34005DB03E = {
|
A26075771EEC6F34005DB03E = {
|
||||||
|
|
@ -984,11 +1000,11 @@
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/SVProgressHUD.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/SVProgressHUD.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/SwiftyUserDefaults.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/SwiftyUserDefaults.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/PasscodeLock.framework",
|
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/FavIcon.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/FavIcon.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/KeychainAccess.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/KeychainAccess.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/OneTimePassword.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/OneTimePassword.framework",
|
||||||
"$(SRCROOT)/Carthage/Build/iOS/Base32.framework",
|
"$(SRCROOT)/Carthage/Build/iOS/Base32.framework",
|
||||||
|
"$(SRCROOT)/Carthage/Build/iOS/Yams.framework",
|
||||||
);
|
);
|
||||||
name = "Run Script";
|
name = "Run Script";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
|
|
@ -1019,14 +1035,16 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A28C66661EF109D600A398A1 /* PasscodeLockRepository.swift in Sources */,
|
A2BEC1BB207D2EFE00F3051C /* UIViewExtension.swift in Sources */,
|
||||||
|
A2C532BB201E5A9600DB9F53 /* PasscodeLock.swift in Sources */,
|
||||||
A2F4E2151EED800F0011986E /* Password.swift in Sources */,
|
A2F4E2151EED800F0011986E /* Password.swift in Sources */,
|
||||||
A28C66651EF109D600A398A1 /* PasscodeLockConfiguration.swift in Sources */,
|
|
||||||
A26075AD1EEC7125005DB03E /* pass.xcdatamodeld in Sources */,
|
A26075AD1EEC7125005DB03E /* pass.xcdatamodeld in Sources */,
|
||||||
A2F4E21E1EED80160011986E /* AppError.swift in Sources */,
|
A2F4E21E1EED80160011986E /* AppError.swift in Sources */,
|
||||||
A2F4E2171EED800F0011986E /* PasswordStore.swift in Sources */,
|
A2F4E2171EED800F0011986E /* PasswordStore.swift in Sources */,
|
||||||
A2F4E2211EED80160011986E /* NotificationNames.swift in Sources */,
|
A2F4E2211EED80160011986E /* NotificationNames.swift in Sources */,
|
||||||
A2F4E2221EED80160011986E /* UITextFieldExtension.swift in Sources */,
|
A2F4E2221EED80160011986E /* UITextFieldExtension.swift in Sources */,
|
||||||
|
A2C532BF201E5AA100DB9F53 /* PasscodeLockPresenter.swift in Sources */,
|
||||||
|
A2C532BE201E5AA100DB9F53 /* PasscodeLockViewController.swift in Sources */,
|
||||||
A2F4E2201EED80160011986E /* Globals.swift in Sources */,
|
A2F4E2201EED80160011986E /* Globals.swift in Sources */,
|
||||||
A2F4E2231EED80160011986E /* Utils.swift in Sources */,
|
A2F4E2231EED80160011986E /* Utils.swift in Sources */,
|
||||||
A2F4E21F1EED80160011986E /* DefaultsKeys.swift in Sources */,
|
A2F4E21F1EED80160011986E /* DefaultsKeys.swift in Sources */,
|
||||||
|
|
@ -1325,6 +1343,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 4.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -1358,6 +1377,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 4.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
@ -1408,6 +1428,7 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
|
@ -1415,6 +1436,7 @@
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -1441,6 +1463,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
|
@ -1465,6 +1488,7 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
|
@ -1472,6 +1496,7 @@
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -1492,6 +1517,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
|
||||||
|
|
@ -1530,7 +1556,7 @@
|
||||||
OTHER_LDFLAGS = "${inherited}";
|
OTHER_LDFLAGS = "${inherited}";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "2e72f4af-b935-4970-9cd3-44d4cc24b646";
|
PROVISIONING_PROFILE = "3c4f599a-ce77-4184-b4c4-edebf09cba3b";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "pass/Helpers/Objective-CBridgingHeader.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "pass/Helpers/Objective-CBridgingHeader.h";
|
||||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0910"
|
LastUpgradeVersion = "0930"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
|
|
@ -66,7 +65,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import CoreData
|
import CoreData
|
||||||
import PasscodeLock
|
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import passKit
|
import passKit
|
||||||
|
|
||||||
|
|
@ -21,7 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var passcodeLockPresenter: PasscodeLockPresenter = {
|
lazy var passcodeLockPresenter: PasscodeLockPresenter = {
|
||||||
let presenter = PasscodeLockPresenter(mainWindow: self.window, configuration: PasscodeLockConfiguration.shared)
|
let presenter = PasscodeLockPresenter(mainWindow: self.window)
|
||||||
return presenter
|
return presenter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -92,7 +91,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
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.
|
// 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)
|
passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,29 +195,12 @@
|
||||||
</subviews>
|
</subviews>
|
||||||
</tableViewCellContentView>
|
</tableViewCellContentView>
|
||||||
</tableViewCell>
|
</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>
|
</cells>
|
||||||
</tableViewSection>
|
</tableViewSection>
|
||||||
<tableViewSection id="6U8-ue-MhL">
|
<tableViewSection id="6U8-ue-MhL">
|
||||||
<cells>
|
<cells>
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="advancedTableViewCell" textLabel="MKj-d0-8q3" style="IBUITableViewCellStyleDefault" id="tQN-gu-iRe">
|
<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"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tQN-gu-iRe" id="Xs0-LN-r43">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="376" height="43.666666666666664"/>
|
||||||
|
|
@ -241,7 +224,7 @@
|
||||||
<tableViewSection id="T7L-rR-R9W">
|
<tableViewSection id="T7L-rR-R9W">
|
||||||
<cells>
|
<cells>
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="aboutTableViewCell" textLabel="oqz-Hr-RAl" style="IBUITableViewCellStyleDefault" id="osS-xk-WRP">
|
<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"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="osS-xk-WRP" id="G6j-ij-rNr">
|
<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"/>
|
<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="passcodeTableViewCell" destination="6Y0-mj-qhA" id="vkI-h5-GRo"/>
|
||||||
<outlet property="passwordRepositoryTableViewCell" destination="2rc-ZW-XKd" id="aFq-K7-eIj"/>
|
<outlet property="passwordRepositoryTableViewCell" destination="2rc-ZW-XKd" id="aFq-K7-eIj"/>
|
||||||
<outlet property="pgpKeyTableViewCell" destination="1ze-MS-Xbj" id="hXe-eD-0R4"/>
|
<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="ZUt-x1-TJu" kind="showDetail" identifier="setPGPKeyByURLSegue" id="qRF-S1-bqF"/>
|
||||||
<segue destination="ffY-rC-jhq" kind="showDetail" identifier="setPGPKeyByASCIISegue" id="mgi-Oe-i2X"/>
|
<segue destination="ffY-rC-jhq" kind="showDetail" identifier="setPGPKeyByASCIISegue" id="mgi-Oe-i2X"/>
|
||||||
</connections>
|
</connections>
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,6 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
||||||
["KeychainAccess",
|
["KeychainAccess",
|
||||||
"https://github.com/kishikawakatsumi/KeychainAccess",
|
"https://github.com/kishikawakatsumi/KeychainAccess",
|
||||||
"https://github.com/kishikawakatsumi/KeychainAccess/blob/master/LICENSE"],
|
"https://github.com/kishikawakatsumi/KeychainAccess/blob/master/LICENSE"],
|
||||||
["PasscodeLock",
|
|
||||||
"https://github.com/zahlz/SwiftPasscodeLock",
|
|
||||||
"https://github.com/zahlz/SwiftPasscodeLock/blob/master/LICENSE.txt"],
|
|
||||||
["ObjectiveGit",
|
["ObjectiveGit",
|
||||||
"https://github.com/libgit2/objective-git",
|
"https://github.com/libgit2/objective-git",
|
||||||
"https://github.com/libgit2/objective-git/blob/master/LICENSE"],
|
"https://github.com/libgit2/objective-git/blob/master/LICENSE"],
|
||||||
|
|
@ -35,6 +32,9 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
||||||
["SVProgressHUD",
|
["SVProgressHUD",
|
||||||
"https://github.com/SVProgressHUD/SVProgressHUD",
|
"https://github.com/SVProgressHUD/SVProgressHUD",
|
||||||
"https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE.txt"],
|
"https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE.txt"],
|
||||||
|
["Yams",
|
||||||
|
"https://github.com/jpsim/Yams",
|
||||||
|
"https://github.com/jpsim/Yams/blob/master/LICENSE"],
|
||||||
]
|
]
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
private var navigationItemTitle: String?
|
private var navigationItemTitle: String?
|
||||||
|
|
||||||
private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()}
|
private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()}
|
||||||
private var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""]
|
private var sectionFooterTitles = ["", "", "Use YAML format for additional fields.", ""]
|
||||||
private let nameSection = 0
|
private let nameSection = 0
|
||||||
private let passwordSection = 1
|
private let passwordSection = 1
|
||||||
private let additionsSection = 2
|
private let additionsSection = 2
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
// reset the data table if the disaply settings have been changed
|
// reset the data table if the disaply settings have been changed
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordDisplaySettingChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordDisplaySettingChanged, object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil)
|
||||||
|
|
||||||
|
// listen to the swipe back guesture
|
||||||
|
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
|
||||||
|
swipeRight.direction = UISwipeGestureRecognizerDirection.right
|
||||||
|
self.view.addGestureRecognizer(swipeRight)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
|
@ -314,6 +319,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
|
||||||
|
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
|
||||||
|
// swipe right -> swipe back
|
||||||
|
if swipeGesture.direction == .right && parentPasswordEntity != nil {
|
||||||
|
self.backAction(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func backAction(_ sender: Any?) {
|
@objc func backAction(_ sender: Any?) {
|
||||||
guard SharedDefaults[.isShowFolderOn] else { return }
|
guard SharedDefaults[.isShowFolderOn] else { return }
|
||||||
var anim: CATransition? = transitionFromLeft
|
var anim: CATransition? = transitionFromLeft
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,16 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import CoreData
|
import CoreData
|
||||||
import PasscodeLock
|
|
||||||
import LocalAuthentication
|
|
||||||
import passKit
|
import passKit
|
||||||
|
|
||||||
class SettingsTableViewController: UITableViewController, UITabBarControllerDelegate {
|
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 pgpKeyTableViewCell: UITableViewCell!
|
||||||
@IBOutlet weak var touchIDTableViewCell: UITableViewCell!
|
|
||||||
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
||||||
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
||||||
|
var setPasscodeLockAlert: UIAlertController?
|
||||||
|
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
var passcodeLockConfig = PasscodeLockConfiguration.shared
|
var passcodeLock = PasscodeLock.shared
|
||||||
|
|
||||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||||
navigationController?.popViewController(animated: true)
|
navigationController?.popViewController(animated: true)
|
||||||
|
|
@ -77,8 +68,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.initPGPKey(with: controller.armorPublicKeyTextView.text, keyType: .public)
|
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .public)
|
||||||
try self.passwordStore.initPGPKey(with: controller.armorPrivateKeyTextView.text, keyType: .secret)
|
try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .secret)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
SVProgressHUD.showSuccess(withStatus: "Success")
|
||||||
|
|
@ -123,14 +114,6 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
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)
|
return super.tableView(tableView, numberOfRowsInSection: section)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,10 +121,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
||||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
|
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
|
||||||
touchIDTableViewCell.accessoryView = touchIDSwitch
|
|
||||||
setPGPKeyTableViewCellDetailText()
|
setPGPKeyTableViewCellDetailText()
|
||||||
setPasswordRepositoryTableViewCellDetailText()
|
setPasswordRepositoryTableViewCellDetailText()
|
||||||
setPasscodeLockTouchIDCells()
|
setPasscodeLockCell()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
|
@ -149,38 +131,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
tabBarController!.delegate = self
|
tabBarController!.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
private func hasTouchID() -> Bool {
|
private func setPasscodeLockCell() {
|
||||||
let context = LAContext()
|
if passcodeLock.hasPasscode {
|
||||||
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 {
|
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
||||||
passcodeLockConfig.isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
|
|
||||||
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
|
|
||||||
} else {
|
} else {
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
||||||
SharedDefaults[.isTouchIDOn] = false
|
|
||||||
passcodeLockConfig.isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
|
|
||||||
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,10 +158,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
@objc func actOnPasswordStoreErasedNotification() {
|
@objc func actOnPasswordStoreErasedNotification() {
|
||||||
setPGPKeyTableViewCellDetailText()
|
setPGPKeyTableViewCellDetailText()
|
||||||
setPasswordRepositoryTableViewCellDetailText()
|
setPasswordRepositoryTableViewCellDetailText()
|
||||||
setPasscodeLockTouchIDCells()
|
setPasscodeLockCell()
|
||||||
|
|
||||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
|
||||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: passcodeLockConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
|
@ -221,22 +173,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
}
|
}
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
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() {
|
func showPGPKeyActionSheet() {
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
var urlActionTitle = "Download from URL"
|
var urlActionTitle = "Download from URL"
|
||||||
|
|
@ -314,21 +251,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
func showPasscodeActionSheet() {
|
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 optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
|
let passcodeRemoveViewController = PasscodeLockViewController()
|
||||||
|
|
||||||
|
|
||||||
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
||||||
passcodeRemoveViewController.successCallback = { _ in
|
passcodeRemoveViewController.successCallback = {
|
||||||
self?.setPasscodeLockTouchIDCells()
|
self?.passcodeLock.delete()
|
||||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
self?.setPasscodeLockCell()
|
||||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: (self?.passcodeLockConfig)!)
|
|
||||||
}
|
}
|
||||||
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in
|
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)
|
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||||
|
|
@ -339,12 +275,50 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
||||||
optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds
|
optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds
|
||||||
self.present(optionMenu, animated: true, completion: nil)
|
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() {
|
func setPasscodeLock() {
|
||||||
let passcodeSetViewController = PasscodeLockViewController(state: .set, configuration: passcodeLockConfig)
|
// prepare the alert for setting the passcode
|
||||||
passcodeSetViewController.successCallback = { _ in
|
setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert)
|
||||||
self.setPasscodeLockTouchIDCells()
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.3.0</string>
|
<string>0.3.1</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait">
|
<device id="retina4_7" orientation="portrait">
|
||||||
<adaptation id="fullscreen"/>
|
<adaptation id="fullscreen"/>
|
||||||
</device>
|
</device>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
@ -20,19 +20,19 @@
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="19l-R0-gP1">
|
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="19l-R0-gP1">
|
||||||
<rect key="frame" x="8" y="11" width="304" height="68"/>
|
<rect key="frame" x="16" y="11" width="288" height="68"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX" userLabel="Password">
|
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX" userLabel="Password">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="244" height="68"/>
|
<rect key="frame" x="0.0" y="0.0" width="228" height="68"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" textContentType="password"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/>
|
<action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam" userLabel="Generate">
|
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam" userLabel="Generate">
|
||||||
<rect key="frame" x="244" y="0.0" width="30" height="68"/>
|
<rect key="frame" x="228" y="0.0" width="30" height="68"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="30" id="l0l-7B-Tws"/>
|
<constraint firstAttribute="width" constant="30" id="l0l-7B-Tws"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SZJ-aY-45Y" userLabel="Setting">
|
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SZJ-aY-45Y" userLabel="Setting">
|
||||||
<rect key="frame" x="274" y="0.0" width="30" height="68"/>
|
<rect key="frame" x="258" y="0.0" width="30" height="68"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="30" id="D9D-FC-ANz"/>
|
<constraint firstAttribute="width" constant="30" id="D9D-FC-ANz"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@ class LabelTableViewCell: UITableViewCell {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
titleLabel.text = title
|
titleLabel.text = title
|
||||||
switch title.lowercased() {
|
if title.caseInsensitiveCompare("password") == .orderedSame {
|
||||||
case "password":
|
|
||||||
type = .password
|
type = .password
|
||||||
if isReveal {
|
if isReveal {
|
||||||
contentLabel.attributedText = Utils.attributedPassword(plainPassword: content)
|
contentLabel.attributedText = Utils.attributedPassword(plainPassword: content)
|
||||||
|
|
@ -52,7 +51,7 @@ class LabelTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentLabel.font = Globals.passwordFont
|
contentLabel.font = Globals.passwordFont
|
||||||
case "hmac-based":
|
} else if title.caseInsensitiveCompare("hmac-based") == .orderedSame {
|
||||||
type = .HOTP
|
type = .HOTP
|
||||||
if isReveal {
|
if isReveal {
|
||||||
contentLabel.text = content
|
contentLabel.text = content
|
||||||
|
|
@ -60,11 +59,12 @@ class LabelTableViewCell: UITableViewCell {
|
||||||
contentLabel.text = Globals.oneTimePasswordDots
|
contentLabel.text = Globals.oneTimePasswordDots
|
||||||
}
|
}
|
||||||
contentLabel.font = Globals.passwordFont
|
contentLabel.font = Globals.passwordFont
|
||||||
case "url":
|
} else if title.lowercased().range(of: "url") != nil || verifyUrl(content) {
|
||||||
type = .URL
|
type = .URL
|
||||||
contentLabel.text = content
|
contentLabel.text = content
|
||||||
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
||||||
default:
|
} else {
|
||||||
|
// default
|
||||||
type = .other
|
type = .other
|
||||||
contentLabel.text = content
|
contentLabel.text = content
|
||||||
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
|
||||||
|
|
@ -198,4 +198,12 @@ class LabelTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
self.accessoryView = buttons
|
self.accessoryView = buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func verifyUrl(_ urlString: String?) -> Bool {
|
||||||
|
guard let urlString = urlString,
|
||||||
|
let _ = URL(string: urlString) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>XPC!</string>
|
<string>XPC!</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.3.0</string>
|
<string>0.3.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
|
|
@ -25,14 +25,17 @@
|
||||||
<key>NSExtensionAttributes</key>
|
<key>NSExtensionAttributes</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationRule</key>
|
<key>NSExtensionActivationRule</key>
|
||||||
<dict>
|
<string>SUBQUERY (
|
||||||
<key>NSExtensionActivationSupportsText</key>
|
extensionItems,
|
||||||
<true/>
|
$extensionItem,
|
||||||
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
|
SUBQUERY (
|
||||||
<integer>1</integer>
|
$extensionItem.attachments,
|
||||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
$attachment,
|
||||||
<integer>1</integer>
|
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.find-login-action" ||
|
||||||
</dict>
|
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ||
|
||||||
|
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text"
|
||||||
|
).@count == $extensionItem.attachments.@count
|
||||||
|
).@count == 1</string>
|
||||||
<key>NSExtensionJavaScriptPreprocessingFile</key>
|
<key>NSExtensionJavaScriptPreprocessingFile</key>
|
||||||
<string>passProcessor</string>
|
<string>passProcessor</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|
|
||||||
|
|
@ -7,27 +7,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import PasscodeLock
|
|
||||||
import passKit
|
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
|
// cancel means cancel the extension
|
||||||
class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
||||||
var originalExtensionContest: NSExtensionContext?
|
var originalExtensionContest: NSExtensionContext?
|
||||||
public convenience init(extensionContext: NSExtensionContext?, state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) {
|
public convenience init(extensionContext: NSExtensionContext?) {
|
||||||
self.init(state: state, configuration: configuration, animateOnDismiss: animateOnDismiss)
|
self.init()
|
||||||
originalExtensionContest = extensionContext
|
originalExtensionContest = extensionContext
|
||||||
}
|
}
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
|
@ -43,18 +29,20 @@ class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
||||||
class PasscodeExtensionDisplay {
|
class PasscodeExtensionDisplay {
|
||||||
private var isPasscodePresented = false
|
private var isPasscodePresented = false
|
||||||
private let passcodeLockVC: PasscodeLockViewControllerForExtension
|
private let passcodeLockVC: PasscodeLockViewControllerForExtension
|
||||||
|
private let extensionContext: NSExtensionContext?
|
||||||
|
|
||||||
init(extensionContext: NSExtensionContext?) {
|
init(extensionContext: NSExtensionContext?) {
|
||||||
let cancelableEnter = CancelableEnterPasscodeState()
|
self.extensionContext = extensionContext
|
||||||
passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext, state: cancelableEnter, configuration: PasscodeLockConfiguration.shared)
|
passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext)
|
||||||
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
}
|
}
|
||||||
|
passcodeLockVC.setCancellable(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// present the passcode lock view if passcode is set and the view controller is not presented
|
// present the passcode lock view if passcode is set and the view controller is not presented
|
||||||
func presentPasscodeLockIfNeeded(_ extensionVC: ExtensionViewController) {
|
func presentPasscodeLockIfNeeded(_ extensionVC: ExtensionViewController) {
|
||||||
guard PasscodeLockConfiguration.shared.repository.hasPasscode && !isPasscodePresented == true else {
|
guard PasscodeLock.shared.hasPasscode && !isPasscodePresented == true else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isPasscodePresented = true
|
isPasscodePresented = true
|
||||||
|
|
|
||||||
54
passKit/Controllers/PasscodeLockPresenter.swift
Normal file
54
passKit/Controllers/PasscodeLockPresenter.swift
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
//
|
||||||
|
// PasscodeLockPresenter.swift
|
||||||
|
// PasscodeLock
|
||||||
|
//
|
||||||
|
// Created by Yishi Lin on 10/04/2018.
|
||||||
|
// Copyright © 2018 Yishi Lin. All rights reserved.
|
||||||
|
//
|
||||||
|
// Inspired by SwiftPasscodeLock created by Yanko Dimitrov.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
open class PasscodeLockPresenter {
|
||||||
|
|
||||||
|
fileprivate var mainWindow: UIWindow?
|
||||||
|
fileprivate var passcodeLockWindow: UIWindow?
|
||||||
|
|
||||||
|
public init(mainWindow window: UIWindow?) {
|
||||||
|
self.mainWindow = window
|
||||||
|
}
|
||||||
|
|
||||||
|
open func present(windowLevel: CGFloat?) {
|
||||||
|
guard PasscodeLock.shared.hasPasscode else { return }
|
||||||
|
|
||||||
|
// dismiss the original window
|
||||||
|
dismiss()
|
||||||
|
|
||||||
|
// new window
|
||||||
|
mainWindow?.endEditing(true)
|
||||||
|
passcodeLockWindow = UIWindow(frame: self.mainWindow!.frame)
|
||||||
|
moveWindowsToFront(windowLevel: windowLevel)
|
||||||
|
passcodeLockWindow?.isHidden = false
|
||||||
|
|
||||||
|
// new vc
|
||||||
|
let passcodeLockVC = PasscodeLockViewController()
|
||||||
|
let userDismissCompletionCallback = passcodeLockVC.dismissCompletionCallback
|
||||||
|
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
||||||
|
userDismissCompletionCallback?()
|
||||||
|
self?.dismiss()
|
||||||
|
}
|
||||||
|
passcodeLockWindow?.rootViewController = passcodeLockVC
|
||||||
|
}
|
||||||
|
|
||||||
|
open func dismiss() {
|
||||||
|
passcodeLockWindow?.isHidden = true
|
||||||
|
passcodeLockWindow?.rootViewController = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func moveWindowsToFront(windowLevel: CGFloat?) {
|
||||||
|
let windowLevel = windowLevel ?? UIWindowLevelNormal
|
||||||
|
let maxWinLevel = max(windowLevel, UIWindowLevelNormal)
|
||||||
|
passcodeLockWindow?.windowLevel = maxWinLevel + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
212
passKit/Controllers/PasscodeLockViewController.swift
Normal file
212
passKit/Controllers/PasscodeLockViewController.swift
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
//
|
||||||
|
// PasscodeLockPresenter.swift
|
||||||
|
// PasscodeLock
|
||||||
|
//
|
||||||
|
// Created by Yishi Lin on 10/04/2018.
|
||||||
|
// Copyright © 2018 Yishi Lin. All rights reserved.
|
||||||
|
//
|
||||||
|
// Inspired by SwiftPasscodeLock created by Yanko Dimitrov.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import LocalAuthentication
|
||||||
|
|
||||||
|
open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
||||||
|
|
||||||
|
open var dismissCompletionCallback: (()->Void)?
|
||||||
|
open var successCallback: (()->Void)?
|
||||||
|
open var cancelCallback: (()->Void)?
|
||||||
|
|
||||||
|
weak var passcodeLabel: UILabel?
|
||||||
|
weak var passcodeWrongAttemptsLabel: UILabel?
|
||||||
|
weak var passcodeTextField: UITextField?
|
||||||
|
weak var biometryAuthButton: UIButton?
|
||||||
|
open weak var cancelButton: UIButton?
|
||||||
|
|
||||||
|
var passcodeFailedAttempts = 0
|
||||||
|
var isCancellable: Bool = false
|
||||||
|
|
||||||
|
open override func loadView() {
|
||||||
|
super.loadView()
|
||||||
|
|
||||||
|
let passcodeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
||||||
|
passcodeLabel.text = "Enter passcode for Pass"
|
||||||
|
passcodeLabel.font = UIFont.boldSystemFont(ofSize: 18)
|
||||||
|
passcodeLabel.textColor = UIColor.black
|
||||||
|
passcodeLabel.textAlignment = .center
|
||||||
|
passcodeLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.view.addSubview(passcodeLabel)
|
||||||
|
self.passcodeLabel = passcodeLabel
|
||||||
|
|
||||||
|
let passcodeWrongAttemptsLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
||||||
|
passcodeWrongAttemptsLabel.text = ""
|
||||||
|
passcodeWrongAttemptsLabel.textColor = UIColor.red
|
||||||
|
passcodeWrongAttemptsLabel.textAlignment = .center
|
||||||
|
passcodeWrongAttemptsLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.view.addSubview(passcodeWrongAttemptsLabel)
|
||||||
|
self.passcodeWrongAttemptsLabel = passcodeWrongAttemptsLabel
|
||||||
|
|
||||||
|
let passcodeTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
|
||||||
|
passcodeTextField.borderStyle = UITextBorderStyle.roundedRect
|
||||||
|
passcodeTextField.placeholder = "passcode"
|
||||||
|
passcodeTextField.isSecureTextEntry = true
|
||||||
|
passcodeTextField.clearButtonMode = UITextFieldViewMode.whileEditing
|
||||||
|
passcodeTextField.delegate = self
|
||||||
|
passcodeTextField.addTarget(self, action: #selector(self.passcodeTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
||||||
|
self.view.backgroundColor = UIColor.white
|
||||||
|
passcodeTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.view.addSubview(passcodeTextField)
|
||||||
|
self.passcodeTextField = passcodeTextField
|
||||||
|
|
||||||
|
let biometryAuthButton = UIButton(type: .custom)
|
||||||
|
biometryAuthButton.setTitle("", for: .normal)
|
||||||
|
biometryAuthButton.setTitleColor(Globals.blue, for: .normal)
|
||||||
|
biometryAuthButton.addTarget(self, action: #selector(bioButtonPressedAction(_:)), for: .touchUpInside)
|
||||||
|
biometryAuthButton.isHidden = true
|
||||||
|
biometryAuthButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.view.addSubview(biometryAuthButton)
|
||||||
|
self.biometryAuthButton = biometryAuthButton
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
biometryAuthButton.setTitle(biometryType, for: .normal)
|
||||||
|
biometryAuthButton.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelButton = UIButton(type: .custom)
|
||||||
|
cancelButton.setTitle("Cancel", for: .normal)
|
||||||
|
cancelButton.setTitleColor(Globals.blue, for: .normal)
|
||||||
|
cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside)
|
||||||
|
cancelButton.isHidden = !self.isCancellable
|
||||||
|
cancelButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
cancelButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
|
||||||
|
self.view.addSubview(cancelButton)
|
||||||
|
self.cancelButton = cancelButton
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
passcodeTextField.widthAnchor.constraint(equalToConstant: 300),
|
||||||
|
passcodeTextField.heightAnchor.constraint(equalToConstant: 40),
|
||||||
|
passcodeTextField.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
|
||||||
|
passcodeTextField.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: -20),
|
||||||
|
// above passocde
|
||||||
|
passcodeLabel.widthAnchor.constraint(equalToConstant: 300),
|
||||||
|
passcodeLabel.heightAnchor.constraint(equalToConstant: 40),
|
||||||
|
passcodeLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
|
||||||
|
passcodeLabel.bottomAnchor.constraint(equalTo: passcodeTextField.topAnchor),
|
||||||
|
// below passcode
|
||||||
|
passcodeWrongAttemptsLabel.widthAnchor.constraint(equalToConstant: 300),
|
||||||
|
passcodeWrongAttemptsLabel.heightAnchor.constraint(equalToConstant: 40),
|
||||||
|
passcodeWrongAttemptsLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
|
||||||
|
passcodeWrongAttemptsLabel.topAnchor.constraint(equalTo: passcodeTextField.bottomAnchor),
|
||||||
|
// bottom of the screen
|
||||||
|
biometryAuthButton.widthAnchor.constraint(equalToConstant: 150),
|
||||||
|
biometryAuthButton.heightAnchor.constraint(equalToConstant: 40),
|
||||||
|
biometryAuthButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
|
||||||
|
biometryAuthButton.bottomAnchor.constraint(equalTo: self.view.safeBottomAnchor, constant: -40),
|
||||||
|
// cancel (top-left of the screen)
|
||||||
|
cancelButton.widthAnchor.constraint(equalToConstant: 150),
|
||||||
|
cancelButton.heightAnchor.constraint(equalToConstant: 40),
|
||||||
|
cancelButton.topAnchor.constraint(equalTo: self.view.safeTopAnchor),
|
||||||
|
cancelButton.leftAnchor.constraint(equalTo: self.view.safeLeftAnchor, constant: 20)
|
||||||
|
])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
if let biometryAuthButton = biometryAuthButton {
|
||||||
|
self.bioButtonPressedAction(biometryAuthButton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func dismissPasscodeLock(completionHandler: (() -> Void)? = nil) {
|
||||||
|
// clean up the textfield
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.passcodeTextField?.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop
|
||||||
|
if presentingViewController?.presentedViewController == self {
|
||||||
|
// if presented as modal
|
||||||
|
dismiss(animated: true, completion: { [weak self] in
|
||||||
|
self?.dismissCompletionCallback?()
|
||||||
|
completionHandler?()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// if pushed in a navigation controller
|
||||||
|
_ = navigationController?.popViewController(animated: true)
|
||||||
|
dismissCompletionCallback?()
|
||||||
|
completionHandler?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - PasscodeLockDelegate
|
||||||
|
|
||||||
|
open func passcodeLockDidSucceed() {
|
||||||
|
passcodeFailedAttempts = 0
|
||||||
|
passcodeWrongAttemptsLabel?.text = ""
|
||||||
|
dismissPasscodeLock(completionHandler: successCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func passcodeLockDidCancel() {
|
||||||
|
dismissPasscodeLock(completionHandler: cancelCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func bioButtonPressedAction(_ uiButton: UIButton) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
if textField == passcodeTextField {
|
||||||
|
if !PasscodeLock.shared.check(passcode: textField.text ?? "") {
|
||||||
|
passcodeFailedAttempts = passcodeFailedAttempts + 1
|
||||||
|
if passcodeFailedAttempts == 1 {
|
||||||
|
passcodeWrongAttemptsLabel?.text = "1 wrong attempt"
|
||||||
|
} else {
|
||||||
|
passcodeWrongAttemptsLabel?.text = "\(passcodeFailedAttempts) wrong attempts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textField.resignFirstResponder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func passcodeTextFieldDidChange(_ textField: UITextField) {
|
||||||
|
if PasscodeLock.shared.check(passcode: textField.text ?? "") {
|
||||||
|
self.passcodeLockDidSucceed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setCancellable(_ isCancellable: Bool) {
|
||||||
|
self.isCancellable = isCancellable
|
||||||
|
cancelButton?.isHidden = !isCancellable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ public enum AppError: Error {
|
||||||
case GitResetError
|
case GitResetError
|
||||||
case PGPPublicKeyNotExistError
|
case PGPPublicKeyNotExistError
|
||||||
case WrongPasswordFilename
|
case WrongPasswordFilename
|
||||||
|
case YamlLoadError
|
||||||
case UnknownError
|
case UnknownError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +37,8 @@ extension AppError: LocalizedError {
|
||||||
return "PGP public key doesn't exist."
|
return "PGP public key doesn't exist."
|
||||||
case .WrongPasswordFilename:
|
case .WrongPasswordFilename:
|
||||||
return "Cannot write to the password file."
|
return "Cannot write to the password file."
|
||||||
|
case .YamlLoadError:
|
||||||
|
return "Cannot be parsed as a YAML file."
|
||||||
case .UnknownError:
|
case .UnknownError:
|
||||||
return "Unknown error."
|
return "Unknown error."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ extension UITextField {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UIViewController {
|
extension UIViewController {
|
||||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
if textField.nextField != nil {
|
if textField.nextField != nil {
|
||||||
textField.nextField?.becomeFirstResponder()
|
textField.nextField?.becomeFirstResponder()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
45
passKit/Helpers/UIViewExtension.swift
Normal file
45
passKit/Helpers/UIViewExtension.swift
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// UIViewExtension.swift
|
||||||
|
// passKit
|
||||||
|
//
|
||||||
|
// Created by Yishi Lin on 2018/4/11.
|
||||||
|
// Copyright © 2018 Yishi Lin. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
|
// Save anchors: https://stackoverflow.com/questions/46317061/use-safe-area-layout-programmatically
|
||||||
|
var safeTopAnchor: NSLayoutYAxisAnchor {
|
||||||
|
if #available(iOS 11.0, *) {
|
||||||
|
return self.safeAreaLayoutGuide.topAnchor
|
||||||
|
} else {
|
||||||
|
return self.topAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var safeLeftAnchor: NSLayoutXAxisAnchor {
|
||||||
|
if #available(iOS 11.0, *){
|
||||||
|
return self.safeAreaLayoutGuide.leftAnchor
|
||||||
|
} else {
|
||||||
|
return self.leftAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var safeRightAnchor: NSLayoutXAxisAnchor {
|
||||||
|
if #available(iOS 11.0, *){
|
||||||
|
return self.safeAreaLayoutGuide.rightAnchor
|
||||||
|
} else {
|
||||||
|
return self.rightAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var safeBottomAnchor: NSLayoutYAxisAnchor {
|
||||||
|
if #available(iOS 11.0, *) {
|
||||||
|
return self.safeAreaLayoutGuide.bottomAnchor
|
||||||
|
} else {
|
||||||
|
return self.bottomAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.3.0</string>
|
<string>0.3.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,24 @@
|
||||||
//
|
//
|
||||||
// PasscodeRepository.swift
|
// PasscodeLock.swift
|
||||||
// pass
|
// PassKit
|
||||||
//
|
//
|
||||||
// Created by Mingshen Sun on 7/2/2017.
|
// Created by Yishi Lin on 28/1/2018.
|
||||||
// Copyright © 2017 Bob Sun. All rights reserved.
|
// Copyright © 2017 Yishi Lin. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import PasscodeLock
|
import LocalAuthentication
|
||||||
|
|
||||||
public class PasscodeLockRepository: PasscodeRepositoryType {
|
open class PasscodeLock {
|
||||||
private let passcodeKey = "passcode.lock.passcode"
|
public static let shared = PasscodeLock()
|
||||||
|
|
||||||
public var hasPasscode: Bool {
|
fileprivate let passcodeKey = "passcode.lock.passcode"
|
||||||
|
fileprivate var passcode: String? {
|
||||||
if passcode != nil {
|
return SharedDefaults[.passcodeKey]
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var passcode: String? {
|
public var hasPasscode: Bool {
|
||||||
return SharedDefaults[.passcodeKey]
|
return passcode != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func save(passcode: String) {
|
public func save(passcode: String) {
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
import OneTimePassword
|
import OneTimePassword
|
||||||
import Base32
|
import Base32
|
||||||
|
import Yams
|
||||||
|
|
||||||
struct AdditionField {
|
struct AdditionField {
|
||||||
var title: String
|
var title: String
|
||||||
|
|
@ -24,6 +25,8 @@ enum PasswordChange: Int {
|
||||||
|
|
||||||
public class Password {
|
public class Password {
|
||||||
public static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"]
|
public static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"]
|
||||||
|
private static let OTPAUTH = "otpauth"
|
||||||
|
private static let OTPAUTH_URL_START = "\(OTPAUTH)://"
|
||||||
|
|
||||||
public var name = ""
|
public var name = ""
|
||||||
public var url: URL?
|
public var url: URL?
|
||||||
|
|
@ -84,29 +87,34 @@ public class Password {
|
||||||
additions.removeAll()
|
additions.removeAll()
|
||||||
|
|
||||||
// split the plain text
|
// split the plain text
|
||||||
let plainTextSplit = plainText.split(maxSplits: 1, omittingEmptySubsequences: false) {
|
let plainTextSplit = self.plainText.split(omittingEmptySubsequences: false) {
|
||||||
$0 == "\n" || $0 == "\r\n"
|
$0 == "\n" || $0 == "\r\n"
|
||||||
}.map(String.init)
|
}.map(String.init)
|
||||||
|
|
||||||
// get password
|
// get password
|
||||||
password = plainTextSplit.first ?? ""
|
password = plainTextSplit.first ?? ""
|
||||||
|
|
||||||
// get additonal fields
|
// get remaining lines (filter out empty lines)
|
||||||
if plainTextSplit.count == 2 {
|
let additionalLines = plainTextSplit[1...].filter { !$0.isEmpty }
|
||||||
var unknownIndex = 0
|
|
||||||
plainTextSplit[1].enumerateLines() { line, _ in
|
|
||||||
if !line.isEmpty {
|
|
||||||
var (key, value) = Password.getKeyValuePair(from: line)
|
|
||||||
if key == nil {
|
|
||||||
unknownIndex += 1
|
|
||||||
key = "unknown \(unknownIndex)"
|
|
||||||
}
|
|
||||||
self.additions.append((key!, value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether the first line of the plainText looks like an otp entry
|
// separate normal lines (no otp tokens)
|
||||||
|
let normalAdditionalLines = additionalLines.filter {
|
||||||
|
!$0.hasPrefix(Password.OTPAUTH_URL_START)
|
||||||
|
}.joined(separator: "\n")
|
||||||
|
|
||||||
|
// try to interpret the text format as YAML first
|
||||||
|
do {
|
||||||
|
try getAdditionalFields(fromYaml: normalAdditionalLines)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
getAdditionalFields(fromPlainText: normalAdditionalLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get and append otp tokens
|
||||||
|
let otpAdditionalLines = additionalLines.filter { $0.hasPrefix(Password.OTPAUTH_URL_START) }
|
||||||
|
otpAdditionalLines.forEach { self.additions.append((Password.OTPAUTH, $0)) }
|
||||||
|
|
||||||
|
// check whether the first line looks like an otp entry
|
||||||
let (key, value) = Password.getKeyValuePair(from: self.password)
|
let (key, value) = Password.getKeyValuePair(from: self.password)
|
||||||
if Password.otpKeywords.contains(key ?? "") {
|
if Password.otpKeywords.contains(key ?? "") {
|
||||||
firstLineIsOTPField = true
|
firstLineIsOTPField = true
|
||||||
|
|
@ -119,6 +127,48 @@ public class Password {
|
||||||
self.updateOtpToken()
|
self.updateOtpToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check whether the file has lines with duplicated field names
|
||||||
|
private func checkDuplicatedFields(lines: String) -> Bool {
|
||||||
|
var keys = Set<String>()
|
||||||
|
var hasDuplicatedFields = false
|
||||||
|
lines.enumerateLines { (line, stop) -> () in
|
||||||
|
let (key, _) = Password.getKeyValuePair(from: line)
|
||||||
|
if let key = key {
|
||||||
|
if keys.contains(key) {
|
||||||
|
hasDuplicatedFields = true
|
||||||
|
stop = true
|
||||||
|
}
|
||||||
|
keys.insert(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasDuplicatedFields
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getAdditionalFields(fromYaml: String) throws {
|
||||||
|
guard !fromYaml.isEmpty else { return }
|
||||||
|
if checkDuplicatedFields(lines: fromYaml) {
|
||||||
|
throw AppError.YamlLoadError
|
||||||
|
}
|
||||||
|
guard let yamlFile = try Yams.load(yaml: fromYaml) as? [String: Any] else {
|
||||||
|
throw AppError.YamlLoadError
|
||||||
|
}
|
||||||
|
additions.append(contentsOf: yamlFile.map { ($0, String(describing: $1)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getAdditionalFields(fromPlainText: String) {
|
||||||
|
var unknownIndex = 0
|
||||||
|
fromPlainText.enumerateLines() { line, _ in
|
||||||
|
if !line.isEmpty {
|
||||||
|
var (key, value) = Password.getKeyValuePair(from: line)
|
||||||
|
if key == nil {
|
||||||
|
unknownIndex += 1
|
||||||
|
key = "unknown \(unknownIndex)"
|
||||||
|
}
|
||||||
|
self.additions.append((key!, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func getFilteredAdditions() -> [(String, String)] {
|
public func getFilteredAdditions() -> [(String, String)] {
|
||||||
var filteredAdditions = [(String, String)]()
|
var filteredAdditions = [(String, String)]()
|
||||||
additions.forEach { (key: String, value: String) in
|
additions.forEach { (key: String, value: String) in
|
||||||
|
|
@ -153,8 +203,8 @@ public class Password {
|
||||||
// no ": " found, or empty on both sides of ": "
|
// no ": " found, or empty on both sides of ": "
|
||||||
value = line
|
value = line
|
||||||
// otpauth special case
|
// otpauth special case
|
||||||
if value.hasPrefix("otpauth://") {
|
if value.hasPrefix(Password.OTPAUTH_URL_START) {
|
||||||
key = "otpauth"
|
key = Password.OTPAUTH
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !items[0].isEmpty {
|
if !items[0].isEmpty {
|
||||||
|
|
@ -221,9 +271,9 @@ public class Password {
|
||||||
self.otpToken = nil
|
self.otpToken = nil
|
||||||
|
|
||||||
// get otpauth, if we are able to generate a token, return
|
// get otpauth, if we are able to generate a token, return
|
||||||
if var otpauthString = getAdditionValue(withKey: "otpauth") {
|
if var otpauthString = getAdditionValue(withKey: Password.OTPAUTH) {
|
||||||
if !otpauthString.hasPrefix("otpauth:") {
|
if !otpauthString.hasPrefix("\(Password.OTPAUTH):") {
|
||||||
otpauthString = "otpauth:\(otpauthString)"
|
otpauthString = "\(Password.OTPAUTH):\(otpauthString)"
|
||||||
}
|
}
|
||||||
if let otpauthUrl = URL(string: otpauthString),
|
if let otpauthUrl = URL(string: otpauthString),
|
||||||
let token = Token(url: otpauthUrl) {
|
let token = Token(url: otpauthUrl) {
|
||||||
|
|
@ -347,7 +397,7 @@ public class Password {
|
||||||
let (key, _) = Password.getKeyValuePair(from: line)
|
let (key, _) = Password.getKeyValuePair(from: line)
|
||||||
if !Password.otpKeywords.contains(key ?? "") {
|
if !Password.otpKeywords.contains(key ?? "") {
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
} else if key == "otpauth" && newOtpauth != nil {
|
} else if key == Password.OTPAUTH && newOtpauth != nil {
|
||||||
lines.append(newOtpauth!)
|
lines.append(newOtpauth!)
|
||||||
// set to nil to prevent duplication
|
// set to nil to prevent duplication
|
||||||
newOtpauth = nil
|
newOtpauth = nil
|
||||||
|
|
|
||||||
|
|
@ -654,9 +654,9 @@ public class PasswordStore {
|
||||||
|
|
||||||
public func delete(passwordEntity: PasswordEntity) throws {
|
public func delete(passwordEntity: PasswordEntity) throws {
|
||||||
let deletedFileURL = passwordEntity.getURL()!
|
let deletedFileURL = passwordEntity.getURL()!
|
||||||
try deleteDirectoryTree(at: passwordEntity.getURL()!)
|
|
||||||
try deletePasswordEntities(passwordEntity: passwordEntity)
|
|
||||||
try gitRm(path: deletedFileURL.path)
|
try gitRm(path: deletedFileURL.path)
|
||||||
|
try deletePasswordEntities(passwordEntity: passwordEntity)
|
||||||
|
try deleteDirectoryTree(at: deletedFileURL)
|
||||||
let _ = try gitCommit(message: "Remove \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) from store using Pass for iOS.")
|
let _ = try gitCommit(message: "Remove \(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!) from store using Pass for iOS.")
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue