From 776884e8949d6f4bd43e8b626eec3b758c067021 Mon Sep 17 00:00:00 2001 From: Mingshen Sun Date: Sun, 10 Jan 2021 13:40:17 -0800 Subject: [PATCH] Refactor and merge code of extensions --- pass.xcodeproj/project.pbxproj | 85 +++-- .../Base.lproj/MainInterface.storyboard | 71 +--- .../CredentialProviderViewController.swift | 6 + .../PasscodeExtensionDisplay.swift | 10 +- .../Controllers/PasswordsViewController.swift | 6 - passAutoFillExtension/Info.plist | 2 +- .../SearchPassword.storyboard | 70 ++++ .../Base.lproj/MainInterface.storyboard | 115 +++---- .../Controllers/ExtensionViewController.swift | 318 +++++++----------- .../PasscodeExtensionDisplay.swift | 59 ---- ...nstants.swift => ExtensionConstants.swift} | 21 +- passExtension/Info.plist | 8 +- .../Services/CredentialProvider.swift | 66 ++++ 13 files changed, 391 insertions(+), 446 deletions(-) create mode 100644 passAutoFillExtension/SearchPassword.storyboard delete mode 100644 passExtension/Controllers/PasscodeExtensionDisplay.swift rename passExtension/Helpers/{OnePasswordExtensionConstants.swift => ExtensionConstants.swift} (62%) create mode 100644 passExtension/Services/CredentialProvider.swift diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 1cb1943..e136d80 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -47,8 +47,7 @@ 30697C4721F63CAB0064FCAC /* PasscodeLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4221F63CAB0064FCAC /* PasscodeLock.swift */; }; 30697C4821F63CAB0064FCAC /* PasswordStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4321F63CAB0064FCAC /* PasswordStore.swift */; }; 30697C4B21F63D460064FCAC /* ExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4921F63D460064FCAC /* ExtensionViewController.swift */; }; - 30697C4C21F63D460064FCAC /* PasscodeExtensionDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4A21F63D460064FCAC /* PasscodeExtensionDisplay.swift */; }; - 30697C5021F63D7F0064FCAC /* OnePasswordExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4F21F63D7F0064FCAC /* OnePasswordExtensionConstants.swift */; }; + 30697C5021F63D7F0064FCAC /* ExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C4F21F63D7F0064FCAC /* ExtensionConstants.swift */; }; 30697C5321F63E0B0064FCAC /* PasscodeExtensionDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C5121F63E0B0064FCAC /* PasscodeExtensionDisplay.swift */; }; 30697C5421F63E0B0064FCAC /* CredentialProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C5221F63E0B0064FCAC /* CredentialProviderViewController.swift */; }; 30697C5F21F674800064FCAC /* String+UtilitiesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C5E21F674800064FCAC /* String+UtilitiesTest.swift */; }; @@ -104,6 +103,14 @@ 9A55C158259E785600FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; }; 9A55C15F259E785700FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; }; 9A55C185259E8C5600FA8FD9 /* PasswordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */; }; + 9A5865F025AA944B006719C2 /* SearchPassword.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */; }; + 9A58661425AAA4C1006719C2 /* PasscodeExtensionDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C5121F63E0B0064FCAC /* PasscodeExtensionDisplay.swift */; }; + 9A58661B25AAA946006719C2 /* PasswordsTableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */; }; + 9A58662225AAAA3A006719C2 /* PasswordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */; }; + 9A58662925AAAA79006719C2 /* PasswordSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */; }; + 9A58664825AAAB7E006719C2 /* SearchPassword.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */; }; + 9A58665125AADB76006719C2 /* CredentialProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58665025AADB76006719C2 /* CredentialProvider.swift */; }; + 9A58665825AADC49006719C2 /* PasswordDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EEF259EE01A0027CE15 /* PasswordDecryptor.swift */; }; 9A5D06EE25A56F0800FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; }; 9A5D06F525A56F0E00FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; }; 9A5D070225A5769A00FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; }; @@ -314,8 +321,7 @@ 30697C4221F63CAB0064FCAC /* PasscodeLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeLock.swift; sourceTree = ""; }; 30697C4321F63CAB0064FCAC /* PasswordStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordStore.swift; sourceTree = ""; }; 30697C4921F63D460064FCAC /* ExtensionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionViewController.swift; sourceTree = ""; }; - 30697C4A21F63D460064FCAC /* PasscodeExtensionDisplay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeExtensionDisplay.swift; sourceTree = ""; }; - 30697C4F21F63D7F0064FCAC /* OnePasswordExtensionConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnePasswordExtensionConstants.swift; sourceTree = ""; }; + 30697C4F21F63D7F0064FCAC /* ExtensionConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionConstants.swift; sourceTree = ""; }; 30697C5121F63E0B0064FCAC /* PasscodeExtensionDisplay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeExtensionDisplay.swift; sourceTree = ""; }; 30697C5221F63E0B0064FCAC /* CredentialProviderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialProviderViewController.swift; sourceTree = ""; }; 30697C5E21F674800064FCAC /* String+UtilitiesTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+UtilitiesTest.swift"; sourceTree = ""; }; @@ -374,6 +380,8 @@ 9A1EF0B524C50EE00074FEAC /* passBetaExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaExtension.entitlements; sourceTree = ""; }; 9A1EF0B624C50FEA0074FEAC /* passBetaShortcuts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaShortcuts.entitlements; sourceTree = ""; }; 9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsViewController.swift; sourceTree = ""; }; + 9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SearchPassword.storyboard; sourceTree = ""; }; + 9A58665025AADB76006719C2 /* CredentialProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProvider.swift; sourceTree = ""; }; 9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertActionExtension.swift; sourceTree = ""; }; 9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsTableDataSource.swift; sourceTree = ""; }; 9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordSelectionDelegate.swift; sourceTree = ""; }; @@ -705,6 +713,14 @@ path = Crypto; sourceTree = ""; }; + 9A58664F25AADB66006719C2 /* Services */ = { + isa = PBXGroup; + children = ( + 9A58665025AADB76006719C2 /* CredentialProvider.swift */, + ); + path = Services; + sourceTree = ""; + }; 9A8F9EBB259EA4A80027CE15 /* Services */ = { isa = PBXGroup; children = ( @@ -727,7 +743,6 @@ isa = PBXGroup; children = ( 30697C4921F63D460064FCAC /* ExtensionViewController.swift */, - 30697C4A21F63D460064FCAC /* PasscodeExtensionDisplay.swift */, ); path = Controllers; sourceTree = ""; @@ -735,7 +750,7 @@ A2168A811EFD4322005EA873 /* Helpers */ = { isa = PBXGroup; children = ( - 30697C4F21F63D7F0064FCAC /* OnePasswordExtensionConstants.swift */, + 30697C4F21F63D7F0064FCAC /* ExtensionConstants.swift */, ); path = Helpers; sourceTree = ""; @@ -749,6 +764,7 @@ A239F59E2158C08C00576CBF /* passAutoFillExtension.entitlements */, 9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */, A239F59A2158C08C00576CBF /* MainInterface.storyboard */, + 9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */, A239F59D2158C08C00576CBF /* Info.plist */, ); path = passAutoFillExtension; @@ -800,6 +816,7 @@ A26700251EEC466A00176B8A /* passExtension */ = { isa = PBXGroup; children = ( + 9A58664F25AADB66006719C2 /* Services */, A2168A801EFD431A005EA873 /* Controllers */, A2168A811EFD4322005EA873 /* Helpers */, A2367B9F1EF0387000C8FE8B /* Assets.xcassets */, @@ -1282,6 +1299,7 @@ 556EC3D422335C5F00934F9C /* Localizable.stringsdict in Resources */, A239F59C2158C08C00576CBF /* MainInterface.storyboard in Resources */, 9A55C158259E785600FA8FD9 /* Assets.xcassets in Resources */, + 9A5865F025AA944B006719C2 /* SearchPassword.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1313,6 +1331,7 @@ A26700371EEC475600176B8A /* passProcessor.js in Resources */, A2367BA01EF0387000C8FE8B /* Assets.xcassets in Resources */, A267002A1EEC466A00176B8A /* MainInterface.storyboard in Resources */, + 9A58664825AAAB7E006719C2 /* SearchPassword.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1638,9 +1657,14 @@ buildActionMask = 2147483647; files = ( 9A5D070225A5769A00FA59D4 /* PasswordTableViewCell.swift in Sources */, - 30697C4C21F63D460064FCAC /* PasscodeExtensionDisplay.swift in Sources */, - 30697C5021F63D7F0064FCAC /* OnePasswordExtensionConstants.swift in Sources */, + 9A58665825AADC49006719C2 /* PasswordDecryptor.swift in Sources */, + 9A58665125AADB76006719C2 /* CredentialProvider.swift in Sources */, + 9A58662225AAAA3A006719C2 /* PasswordsViewController.swift in Sources */, + 9A58662925AAAA79006719C2 /* PasswordSelectionDelegate.swift in Sources */, + 30697C5021F63D7F0064FCAC /* ExtensionConstants.swift in Sources */, + 9A58661425AAA4C1006719C2 /* PasscodeExtensionDisplay.swift in Sources */, 30697C4B21F63D460064FCAC /* ExtensionViewController.swift in Sources */, + 9A58661B25AAA946006719C2 /* PasswordsTableDataSource.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1967,7 +1991,7 @@ ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; @@ -1993,7 +2017,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2008,6 +2032,7 @@ baseConfigurationReference = C4C702DBCBA2374D32295603 /* Pods-passExtension.beta.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; + APP_DISPLAY_NAME = "Pass Beta"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -2018,13 +2043,13 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; OTHER_CFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passExtension; PROVISIONING_PROFILE = "cbd86628-6f3e-40f3-b518-20d2330db545"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforiosbeta.find-login-action-extension"; SKIP_INSTALL = YES; @@ -2057,7 +2082,7 @@ HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; @@ -2090,7 +2115,7 @@ "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/", ); INFOPLIST_FILE = passKitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKitTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2120,7 +2145,7 @@ MARKETING_VERSION = 0.11.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforiosbeta.auto-fill-credential-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passAutoFillExtension; PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforiosbeta.auto-fill-credential-extension"; SKIP_INSTALL = YES; STRIP_INSTALLED_PRODUCT = NO; @@ -2178,7 +2203,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.auto-fill-credential-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passAutoFillExtension; PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.auto-fill-credential-extension"; SKIP_INSTALL = YES; STRIP_INSTALLED_PRODUCT = NO; @@ -2207,7 +2232,7 @@ MARKETING_VERSION = 0.11.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.auto-fill-credential-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passAutoFillExtension; PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.auto-fill-credential-extension"; SKIP_INSTALL = YES; STRIP_INSTALLED_PRODUCT = NO; @@ -2239,7 +2264,7 @@ HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; @@ -2284,7 +2309,7 @@ HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; @@ -2317,7 +2342,7 @@ "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/", ); INFOPLIST_FILE = passKitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKitTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2339,7 +2364,7 @@ "$(SRCROOT)/Carthage/Build/iOS/ObjectiveGit.framework/Headers/", ); INFOPLIST_FILE = passKitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passKitTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2354,6 +2379,7 @@ baseConfigurationReference = DD224E7F8C867E6CD0BFE9D5 /* Pods-passExtension.debug.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; + APP_DISPLAY_NAME = Pass; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -2364,13 +2390,13 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; OTHER_CFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passExtension; PROVISIONING_PROFILE = "d25c9029-bca6-4b2d-b04e-4abc9d232740"; PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios.find-login-action-extension"; SKIP_INSTALL = YES; @@ -2385,6 +2411,7 @@ baseConfigurationReference = 62DEE9943E0F2B8C79E3FC5B /* Pods-passExtension.release.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; + APP_DISPLAY_NAME = Pass; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -2395,13 +2422,13 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; OTHER_CFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = passExtension; PROVISIONING_PROFILE = "cbd86628-6f3e-40f3-b518-20d2330db545"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios.find-login-action-extension"; SKIP_INSTALL = YES; @@ -2420,7 +2447,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2439,7 +2466,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).passTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2604,7 +2631,7 @@ ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; @@ -2641,7 +2668,7 @@ ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.11.0; diff --git a/passAutoFillExtension/Base.lproj/MainInterface.storyboard b/passAutoFillExtension/Base.lproj/MainInterface.storyboard index 9ea07a3..dad9add 100644 --- a/passAutoFillExtension/Base.lproj/MainInterface.storyboard +++ b/passAutoFillExtension/Base.lproj/MainInterface.storyboard @@ -9,63 +9,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -90,9 +33,20 @@ + + + + + + + + + + + @@ -102,10 +56,9 @@ - + - diff --git a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift index d15bcaa..098b320 100644 --- a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift +++ b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift @@ -32,6 +32,7 @@ class CredentialProviderViewController: ASCredentialProviderViewController { let dataSource = PasswordsTableDataSource(entries: passwordsTableEntries) passwordsViewController.dataSource = dataSource passwordsViewController.selectionDelegate = self + passwordsViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) } override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) { @@ -58,6 +59,11 @@ class CredentialProviderViewController: ASCredentialProviderViewController { passwordsViewController.navigationItem.prompt = identifier passwordsViewController.showPasswordsWithSuggstion(matching: identifier) } + + @objc + private func cancel(_: AnyObject?) { + self.extensionContext.cancelRequest(withError: NSError(domain: "PassExtension", code: 0)) + } } extension CredentialProviderViewController: PasswordSelectionDelegate { diff --git a/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift b/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift index ba58ffb..0f2a78f 100644 --- a/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift +++ b/passAutoFillExtension/Controllers/PasscodeExtensionDisplay.swift @@ -12,9 +12,9 @@ import passKit // cancel means cancel the extension class PasscodeLockViewControllerForExtension: PasscodeLockViewController { - var originalExtensionContext: ASCredentialProviderExtensionContext! + var originalExtensionContext: NSExtensionContext! - convenience init(extensionContext: ASCredentialProviderExtensionContext) { + convenience init(extensionContext: NSExtensionContext) { self.init() self.originalExtensionContext = extensionContext } @@ -27,15 +27,15 @@ class PasscodeLockViewControllerForExtension: PasscodeLockViewController { @objc func cancelExtension() { - originalExtensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) + originalExtensionContext.cancelRequest(withError: NSError(domain: "PassExtension", code: 0)) } } class PasscodeExtensionDisplay { private let passcodeLockVC: PasscodeLockViewControllerForExtension - private let extensionContext: ASCredentialProviderExtensionContext? + private let extensionContext: NSExtensionContext? - init(extensionContext: ASCredentialProviderExtensionContext) { + init(extensionContext: NSExtensionContext) { self.extensionContext = extensionContext self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) passcodeLockVC.setCancellable(true) diff --git a/passAutoFillExtension/Controllers/PasswordsViewController.swift b/passAutoFillExtension/Controllers/PasswordsViewController.swift index 8101234..9d92844 100644 --- a/passAutoFillExtension/Controllers/PasswordsViewController.swift +++ b/passAutoFillExtension/Controllers/PasswordsViewController.swift @@ -47,12 +47,6 @@ class PasswordsViewController: UIViewController { dataSource.showTableEntriesWithSuggestion(matching: text) tableView.reloadData() } - - @IBAction - private func cancel(_: AnyObject?) { - self.extensionContext?.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) - self.dismiss(animated: true) - } } extension PasswordsViewController: UISearchBarDelegate { diff --git a/passAutoFillExtension/Info.plist b/passAutoFillExtension/Info.plist index 08c1087..0e2bcf3 100644 --- a/passAutoFillExtension/Info.plist +++ b/passAutoFillExtension/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - $(PRODUCT_NAME) + Pass CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/passAutoFillExtension/SearchPassword.storyboard b/passAutoFillExtension/SearchPassword.storyboard new file mode 100644 index 0000000..d38c66c --- /dev/null +++ b/passAutoFillExtension/SearchPassword.storyboard @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/passExtension/Base.lproj/MainInterface.storyboard b/passExtension/Base.lproj/MainInterface.storyboard index 69199f4..b8f602d 100644 --- a/passExtension/Base.lproj/MainInterface.storyboard +++ b/passExtension/Base.lproj/MainInterface.storyboard @@ -1,85 +1,14 @@ - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -91,17 +20,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/passExtension/Controllers/ExtensionViewController.swift b/passExtension/Controllers/ExtensionViewController.swift index c2f7414..37ca552 100644 --- a/passExtension/Controllers/ExtensionViewController.swift +++ b/passExtension/Controllers/ExtensionViewController.swift @@ -10,220 +10,158 @@ import Foundation import MobileCoreServices import passKit -class ExtensionViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationBarDelegate { - @IBOutlet var searchBar: UISearchBar! - @IBOutlet var tableView: UITableView! +class ExtensionViewController: UIViewController { + var passcodelock: PasscodeExtensionDisplay { + PasscodeExtensionDisplay(extensionContext: self.extensionContext!) + } - private let passwordStore = PasswordStore.shared - private let keychain = AppKeychain.shared + var embeddedNavigationController: UINavigationController { + children.first as! UINavigationController + } - private var searchActive = false - private var passwordsTableEntries: [PasswordTableEntry] = [] - private var filteredPasswordsTableEntries: [PasswordTableEntry] = [] + var passwordsViewController: PasswordsViewController { + embeddedNavigationController.viewControllers.first as! PasswordsViewController + } enum Action { case findLogin, fillBrowser, unknown } - private var extensionAction = Action.unknown + private var action = Action.unknown - private lazy var passcodelock: PasscodeExtensionDisplay = { - let passcodelock = PasscodeExtensionDisplay(extensionContext: self.extensionContext) - return passcodelock - }() + lazy var credentialProvider = CredentialProvider(viewController: self, extensionContext: self.extensionContext!) - private func initPasswordsTableEntries() { - filteredPasswordsTableEntries.removeAll() + override func viewDidLoad() { + super.viewDidLoad() + passcodelock.presentPasscodeLockIfNeeded(self) - let passwordEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false) - passwordsTableEntries = passwordEntities.map { - PasswordTableEntry($0) - } + let passwordsTableEntries = PasswordStore.shared.fetchPasswordEntityCoreData(withDir: false).compactMap { PasswordTableEntry($0) } + let dataSource = PasswordsTableDataSource(entries: passwordsTableEntries) + passwordsViewController.dataSource = dataSource + passwordsViewController.selectionDelegate = self + passwordsViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - passcodelock.presentPasscodeLockIfNeeded(self) + prepareCredentialList() } - override func viewDidLoad() { - super.viewDidLoad() - // prepare - searchBar.delegate = self - tableView.delegate = self - tableView.dataSource = self - tableView.register(PasswordTableViewCell.self, forCellReuseIdentifier: "passwordTableViewCell") + @objc + private func cancel(_: AnyObject?) { + self.extensionContext?.completeRequest(returningItems: nil) + } - // initialize table entries - initPasswordsTableEntries() - - // get the provider - guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else { + func prepareCredentialList() { + guard let attachments = self.extensionContext?.attachments else { return } - for extensionItem in extensionItems { - guard let itemProviders = extensionItem.attachments else { - continue - } - for provider in itemProviders { - // search using the extensionContext inputs - if provider.hasItemConformingToTypeIdentifier(OnePasswordExtensionActions.findLogin) { - provider.loadItem(forTypeIdentifier: OnePasswordExtensionActions.findLogin, options: nil) { item, _ in - self.updateExtension(with: self.getUrl(from: item as! NSDictionary), action: .findLogin) - } - } else if provider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) { - provider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil) { item, _ in - if let dictionary = item as? NSDictionary, let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary { - self.updateExtension(with: self.getUrl(from: results)) - } - } - } else if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) { - provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { item, _ in - self.updateExtension(with: (item as? NSURL)!.host) - } - } + func completeTask(_ text: String?) { + DispatchQueue.main.async { + self.passwordsViewController.showPasswordsWithSuggstion(matching: text ?? "") + self.passwordsViewController.navigationItem.prompt = text } } - } - - private func getUrl(from dictionary: NSDictionary) -> String? { - if var urlString = dictionary[OnePasswordExtensionKey.URLStringKey] as? String { - if !urlString.hasPrefix("http://"), !urlString.hasPrefix("https://") { - urlString = "http://" + urlString - } - return URL(string: urlString)?.host - } - return nil - } - - private func updateExtension(with url: String?, action: Action = .fillBrowser) { - // Set text, set active, and force search. - DispatchQueue.main.async { [weak self] in - self?.extensionAction = action - self?.searchBar.text = url - self?.searchBar.becomeFirstResponder() - self?.searchBarSearchButtonClicked((self?.searchBar)!) - } - } - - // define cell contents, and set long press action - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) as! PasswordTableViewCell - let entry = getPasswordEntry(by: indexPath) - cell.configure(with: entry) - - return cell - } - - // select row -> extension returns (with username and password) - func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { - let entry = getPasswordEntry(by: indexPath) - - guard PGPAgent.shared.isPrepared else { - Utils.alert(title: "CannotCopyPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self, completion: nil) - return - } - - let passwordEntity = entry.passwordEntity - UIImpactFeedbackGenerator(style: .medium).impactOccurred() - decryptPassword(passwordEntity: passwordEntity) - } - - private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) { - DispatchQueue.global(qos: .userInteractive).async { - do { - let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self) - let decryptedPassword = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase) - - let username = decryptedPassword.getUsernameForCompletion() - let password = decryptedPassword.password - DispatchQueue.main.async { - // prepare a dictionary to return - switch self.extensionAction { - case .findLogin: - let extensionItem = NSExtensionItem() - var returnDictionary = [ - OnePasswordExtensionKey.usernameKey: username, - OnePasswordExtensionKey.passwordKey: password, - ] - if let totpPassword = decryptedPassword.currentOtp { - returnDictionary[OnePasswordExtensionKey.totpKey] = totpPassword - } - extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))] - self.extensionContext!.completeRequest(returningItems: [extensionItem], completionHandler: nil) - case .fillBrowser: - Utils.copyToPasteboard(textToCopy: decryptedPassword.password) - // return a dictionary for JavaScript for best-effor fill in - let extensionItem = NSExtensionItem() - let returnDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: ["username": username, "password": password]] - extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))] - self.extensionContext?.completeRequest(returningItems: [extensionItem], completionHandler: nil) - default: - self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) - } - } - } catch let AppError.pgpPrivateKeyNotFound(keyID: key) { - DispatchQueue.main.async { - // alert: cancel or try again - let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction.cancelAndPopView(controller: self)) - let selectKey = UIAlertAction.selectKey(controller: self) { action in - self.decryptPassword(passwordEntity: passwordEntity, keyID: action.title) - } - alert.addAction(selectKey) - - self.present(alert, animated: true, completion: nil) - } - } catch { - DispatchQueue.main.async { - Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self, completion: nil) + DispatchQueue.global(qos: .userInitiated).async { + for attachment in attachments { + if attachment.hasURL { + self.action = .fillBrowser + attachment.extractSearchText { completeTask($0) } + } else if attachment.hasFindLoginAction { + self.action = .findLogin + attachment.extractSearchText { completeTask($0) } + } else if attachment.hasPropertyList { + self.action = .fillBrowser + attachment.extractSearchText { completeTask($0) } + } else { + self.action = .unknown } } } } - - func numberOfSectionsInTableView(tableView _: UITableView) -> Int { - 1 - } - - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - if searchActive { - return filteredPasswordsTableEntries.count - } - return passwordsTableEntries.count - } - - @IBAction - private func cancelExtension(_: Any) { - extensionContext!.completeRequest(returningItems: [], completionHandler: nil) - } - - func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { - searchBar.text = "" - searchActive = false - tableView.reloadData() - } - - func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { - if let searchText = searchBar.text, searchText.isEmpty == false { - filteredPasswordsTableEntries = passwordsTableEntries.filter { $0.match(searchText) } - searchActive = true - } else { - searchActive = false - } - tableView.reloadData() - } - - func searchBar(_ searchBar: UISearchBar, textDidChange _: String) { - searchBarSearchButtonClicked(searchBar) - } - - private func getPasswordEntry(by indexPath: IndexPath) -> PasswordTableEntry { - if searchActive { - return filteredPasswordsTableEntries[indexPath.row] - } else { - return passwordsTableEntries[indexPath.row] - } - } +} + +extension ExtensionViewController: PasswordSelectionDelegate { + func selected(password: PasswordTableEntry) { + switch action { + case .findLogin: + credentialProvider.provideCredentialsFindLogin(with: password.passwordEntity.getPath()) + case .fillBrowser: + credentialProvider.provideCredentialsBrowser(with: password.passwordEntity.getPath()) + default: + self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) + } + } +} + +extension NSDictionary { + func extractSearchText() -> String? { + if let value = self[PassExtensionKey.URLStringKey] as? String { + if let host = URL(string: value)?.host { + return host + } else { + return value + } + } else if let value = self[NSExtensionJavaScriptPreprocessingResultsKey] as? String { + if let host = URL(string: value)?.host { + return host + } else { + return value + } + } + return nil + } +} + +extension NSItemProvider { + var hasFindLoginAction: Bool { + hasItemConformingToTypeIdentifier(PassExtensionActions.findLogin) + } + + var hasURL: Bool { + hasItemConformingToTypeIdentifier(kUTTypeURL as String) && registeredTypeIdentifiers.count == 1 + } + + var hasPropertyList: Bool { + hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) + } +} + +extension NSExtensionContext { + /// Get all the attachments to this post. + var attachments: [NSItemProvider] { + guard let items = inputItems as? [NSExtensionItem] else { + return [] + } + return items.flatMap { $0.attachments ?? [] } + } +} + +extension NSItemProvider { + /// Extracts the URL from the item provider + func extractSearchText(completion: @escaping (String?) -> Void) { + self.loadItem(forTypeIdentifier: kUTTypeURL as String) { item, _ in + if let url = item as? NSURL { + completion(url.host) + } else { + completion(nil) + } + } + + self.loadItem(forTypeIdentifier: kUTTypePropertyList as String) { item, _ in + if let dict = item as? NSDictionary { + if let result = dict[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary { + completion(result.extractSearchText()) + } + } + } + + self.loadItem(forTypeIdentifier: PassExtensionActions.findLogin) { item, _ in + if let dict = item as? NSDictionary { + let text = dict.extractSearchText() + completion(text) + } + } + } } diff --git a/passExtension/Controllers/PasscodeExtensionDisplay.swift b/passExtension/Controllers/PasscodeExtensionDisplay.swift deleted file mode 100644 index df530f0..0000000 --- a/passExtension/Controllers/PasscodeExtensionDisplay.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// PasscodeLockDisplay.swift -// pass -// -// Created by Yishi Lin on 14/6/17. -// Copyright © 2017 Bob Sun. All rights reserved. -// - -import Foundation -import passKit - -// cancel means cancel the extension -class PasscodeLockViewControllerForExtension: PasscodeLockViewController { - var originalExtensionContest: NSExtensionContext? - - convenience init(extensionContext: NSExtensionContext?) { - self.init() - self.originalExtensionContest = extensionContext - } - - override func viewDidLoad() { - super.viewDidLoad() - cancelButton?.removeTarget(nil, action: nil, for: .allEvents) - cancelButton?.addTarget(self, action: #selector(cancelExtension), for: .touchUpInside) - } - - @objc - func cancelExtension() { - originalExtensionContest?.completeRequest(returningItems: [], completionHandler: nil) - } -} - -class PasscodeExtensionDisplay { - private var isPasscodePresented = false - private let passcodeLockVC: PasscodeLockViewControllerForExtension - private let extensionContext: NSExtensionContext? - - init(extensionContext: NSExtensionContext?) { - self.extensionContext = extensionContext - self.passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext) - passcodeLockVC.dismissCompletionCallback = { [weak self] in - self?.dismiss() - } - passcodeLockVC.setCancellable(true) - } - - // present the passcode lock view if passcode is set and the view controller is not presented - func presentPasscodeLockIfNeeded(_ extensionVC: UIViewController) { - guard PasscodeLock.shared.hasPasscode, !isPasscodePresented == true else { - return - } - isPasscodePresented = true - extensionVC.present(passcodeLockVC, animated: true, completion: nil) - } - - func dismiss(animated _: Bool = true) { - isPasscodePresented = false - } -} diff --git a/passExtension/Helpers/OnePasswordExtensionConstants.swift b/passExtension/Helpers/ExtensionConstants.swift similarity index 62% rename from passExtension/Helpers/OnePasswordExtensionConstants.swift rename to passExtension/Helpers/ExtensionConstants.swift index d3b4fc7..8cde7b2 100644 --- a/passExtension/Helpers/OnePasswordExtensionConstants.swift +++ b/passExtension/Helpers/ExtensionConstants.swift @@ -7,7 +7,7 @@ // // This file contains constants from https://github.com/agilebits/onepassword-app-extension/ -enum OnePasswordExtensionActions { +enum PassExtensionActions { static let findLogin = "org.appextension.find-login-action" static let saveLogin = "org.appextension.save-login-action" static let changePassword = "org.appextension.change-password-action" @@ -15,8 +15,8 @@ enum OnePasswordExtensionActions { static let fillBrowser = "org.appextension.fill-browser-action" } -enum OnePasswordExtensionKey { - // Login Dictionary keys - Used to get or set the properties of a 1Password Login +enum PassExtensionKey { + // Login Dictionary keys static let URLStringKey = "url_string" static let usernameKey = "username" static let passwordKey = "password" @@ -29,23 +29,10 @@ enum OnePasswordExtensionKey { static let oldPasswordKey = "old_password" static let passwordGeneratorOptionsKey = "password_generator_options" - // Password Generator options - Used to set the 1Password Password Generator options when saving a new Login or when changing the password for for an existing Login + // Password Generator options static let generatedPasswordMinLengthKey = "password_min_length" static let generatedPasswordMaxLengthKey = "password_max_length" static let generatedPasswordRequireDigitsKey = "password_require_digits" static let generatedPasswordRequireSymbolsKey = "password_require_symbols" static let generatedPasswordForbiddenCharactersKey = "password_forbidden_characters" } - -// Errors codes -enum OnePasswordExtensionError { - static let errorDomain = "OnePasswordExtension" - static let errorCodeCancelledByUser = 0 - static let errorCodeAPINotAvailable = 1 - static let errorCodeFailedToContactExtension = 2 - static let errorCodeFailedToLoadItemProviderData = 3 - static let errorCodeCollectFieldsScriptFailed = 4 - static let errorCodeFillFieldsScriptFailed = 5 - static let errorCodeUnexpectedData = 6 - static let errorCodeFailedToObtainURLStringFromWebView = 7 // swiftlint:disable:this identifier_name -} diff --git a/passExtension/Info.plist b/passExtension/Info.plist index d4edf02..26c7861 100644 --- a/passExtension/Info.plist +++ b/passExtension/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Pass + $(APP_DISPLAY_NAME) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -31,9 +31,9 @@ SUBQUERY ( $extensionItem.attachments, $attachment, - ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.find-login-action" || - ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" || - ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text" + ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.find-login-action" || + ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" || + ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text" ).@count == $extensionItem.attachments.@count ).@count == 1 NSExtensionJavaScriptPreprocessingFile diff --git a/passExtension/Services/CredentialProvider.swift b/passExtension/Services/CredentialProvider.swift new file mode 100644 index 0000000..0a17207 --- /dev/null +++ b/passExtension/Services/CredentialProvider.swift @@ -0,0 +1,66 @@ +// +// CredentialProvider.swift +// passExtension +// +// Created by Sun, Mingshen on 1/9/21. +// Copyright © 2021 Bob Sun. All rights reserved. +// + +import UIKit +import MobileCoreServices +import passKit + +class CredentialProvider { + weak var extensionContext: NSExtensionContext? + weak var viewController: UIViewController? + + init(viewController: UIViewController, extensionContext: NSExtensionContext) { + self.viewController = viewController + self.extensionContext = extensionContext + } + + func provideCredentialsFindLogin(with passwordPath: String) { + guard let viewController = viewController else { + return + } + guard let extensionContext = extensionContext else { + return + } + + decryptPassword(in: viewController, with: passwordPath) { password in + let extensionItem = NSExtensionItem() + var returnDictionary = [ + PassExtensionKey.usernameKey: password.getUsernameForCompletion(), + PassExtensionKey.passwordKey: password.password, + ] + if let totpPassword = password.currentOtp { + returnDictionary[PassExtensionKey.totpKey] = totpPassword + } + extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))] + extensionContext.completeRequest(returningItems: [extensionItem]) + } + } + + func provideCredentialsBrowser(with passwordPath: String) { + guard let viewController = viewController else { + return + } + guard let extensionContext = extensionContext else { + return + } + + decryptPassword(in: viewController, with: passwordPath) { password in + Utils.copyToPasteboard(textToCopy: password.password) + // return a dictionary for JavaScript for best-effor fill in + let extensionItem = NSExtensionItem() + let returnDictionary = [ + NSExtensionJavaScriptFinalizeArgumentKey: [ + "username": password.getUsernameForCompletion(), + "password": password.password, + ], + ] + extensionItem.attachments = [NSItemProvider(item: returnDictionary as NSSecureCoding, typeIdentifier: String(kUTTypePropertyList))] + extensionContext.completeRequest(returningItems: [extensionItem]) + } + } +}