From b3bde9e0e0151e0c9bd2ec11cb356eaac5da98f3 Mon Sep 17 00:00:00 2001 From: Danny Moesch Date: Wed, 4 Mar 2020 20:27:23 +0100 Subject: [PATCH] Implement Siri shortcut to sync repository per automation task --- pass.xcodeproj/project.pbxproj | 184 +++++++++++++++++- ...epositorySettingsTableViewController.swift | 2 +- .../Controllers/PasswordsViewController.swift | 2 +- pass/Info.plist | 4 + pass/de.lproj/Intents.strings | 30 +++ pass/en.lproj/Intents.intentdefinition | 143 ++++++++++++++ pass/pass.entitlements | 2 + passKit/Models/PasswordStore.swift | 2 +- passShortcuts/Info.plist | 42 ++++ passShortcuts/IntentHandler.swift | 20 ++ .../SyncRepositoryIntentHandler.swift | 58 ++++++ passShortcuts/passShortcuts.entitlements | 14 ++ 12 files changed, 499 insertions(+), 4 deletions(-) create mode 100644 pass/de.lproj/Intents.strings create mode 100644 pass/en.lproj/Intents.intentdefinition create mode 100644 passShortcuts/Info.plist create mode 100644 passShortcuts/IntentHandler.swift create mode 100644 passShortcuts/SyncRepositoryIntentHandler.swift create mode 100644 passShortcuts/passShortcuts.entitlements diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 9d4969f..4c9c957 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032327322C7F710009EBD9C /* KeyFileManager.swift */; }; 3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */; }; 3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */; }; + 304E2125241550260047FB51 /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; }; 30650E7123F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7023F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift */; }; 30650E7323F847FC005CCD5E /* KeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7223F847FC005CCD5E /* KeyImporter.swift */; }; 306623332406F1A8000E2AD6 /* PasswordGeneratorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306623322406F1A7000E2AD6 /* PasswordGeneratorTest.swift */; }; @@ -59,6 +60,8 @@ 30A1D2A821B2D53200E2D1F7 /* PasswordChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A721B2D53200E2D1F7 /* PasswordChange.swift */; }; 30A1D2AA21B32A0100E2D1F7 /* OtpTypeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2A921B32A0100E2D1F7 /* OtpTypeTest.swift */; }; 30A1D2AC21B32C2A00E2D1F7 /* TokenBuilderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A1D2AB21B32C2A00E2D1F7 /* TokenBuilderTest.swift */; }; + 30A69948240EED5E00B7D967 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A69947240EED5E00B7D967 /* IntentHandler.swift */; }; + 30A6995D240EED5F00B7D967 /* PassShortcuts.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 30A69945240EED5E00B7D967 /* PassShortcuts.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 30A86F95230F237000F821A4 /* CryptoFrameworkTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A86F94230F237000F821A4 /* CryptoFrameworkTest.swift */; }; 30B04860209A5141001013CA /* PasswordTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0485F209A5141001013CA /* PasswordTest.swift */; }; 30B4C7BA24084AAA008B86F7 /* PasswordGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B4C7B924084AAA008B86F7 /* PasswordGenerator.swift */; }; @@ -77,6 +80,9 @@ 30CCA91A232591320048CA51 /* ObjectivePgp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCA919232591320048CA51 /* ObjectivePgp.swift */; }; 30DAFD4A240985A7002456E7 /* Array+Slices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DAFD49240985A7002456E7 /* Array+Slices.swift */; }; 30DAFD4C240985E3002456E7 /* Array+SlicesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DAFD4B240985E3002456E7 /* Array+SlicesTest.swift */; }; + 30EE3A14241AE6EC009FBB61 /* SyncRepositoryIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A69968240EF52E00B7D967 /* SyncRepositoryIntentHandler.swift */; }; + 30EE3A16241E98C1009FBB61 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 30EE3A19241E98C1009FBB61 /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; }; + 30EE3A17241E98C1009FBB61 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 30EE3A19241E98C1009FBB61 /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; 30FD2F78214D9E0E005E0A92 /* ParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */; }; 3EA2386CD0E9CE2A702A0B3E /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE627E8F3DACEDD8FA220081 /* Pods_pass.framework */; }; 556EC3D322335C5F00934F9C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */; }; @@ -165,6 +171,20 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 304E2127241550260047FB51 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DC917BCB1E2E8231000FDF54 /* Project object */; + proxyType = 1; + remoteGlobalIDString = A26075771EEC6F34005DB03E; + remoteInfo = passKit; + }; + 30A6995B240EED5F00B7D967 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DC917BCB1E2E8231000FDF54 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 30A69944240EED5E00B7D967; + remoteInfo = passShortcuts; + }; A239F59F2158C08C00576CBF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DC917BCB1E2E8231000FDF54 /* Project object */; @@ -228,6 +248,7 @@ dstSubfolderSpec = 13; files = ( A267002E1EEC466A00176B8A /* passExtension.appex in Embed App Extensions */, + 30A6995D240EED5F00B7D967 /* PassShortcuts.appex in Embed App Extensions */, A239F5A12158C08C00576CBF /* passAutoFillExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; @@ -251,6 +272,7 @@ 3032327322C7F710009EBD9C /* KeyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManager.swift; sourceTree = ""; }; 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManagerTest.swift; sourceTree = ""; }; 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptographicKeys.swift; sourceTree = ""; }; + 304E212C241AD0EB0047FB51 /* passShortcuts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passShortcuts.entitlements; sourceTree = ""; }; 30650E7023F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHKeyFileImportTableViewController.swift; sourceTree = ""; }; 30650E7223F847FC005CCD5E /* KeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyImporter.swift; sourceTree = ""; }; 306623322406F1A7000E2AD6 /* PasswordGeneratorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorTest.swift; sourceTree = ""; }; @@ -289,6 +311,11 @@ 30A1D2A721B2D53200E2D1F7 /* PasswordChange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordChange.swift; sourceTree = ""; }; 30A1D2A921B32A0100E2D1F7 /* OtpTypeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OtpTypeTest.swift; sourceTree = ""; }; 30A1D2AB21B32C2A00E2D1F7 /* TokenBuilderTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenBuilderTest.swift; sourceTree = ""; }; + 30A69945240EED5E00B7D967 /* PassShortcuts.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassShortcuts.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 30A69947240EED5E00B7D967 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; + 30A69949240EED5E00B7D967 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 30A6994F240EED5F00B7D967 /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; }; + 30A69968240EF52E00B7D967 /* SyncRepositoryIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncRepositoryIntentHandler.swift; sourceTree = ""; }; 30A86F94230F237000F821A4 /* CryptoFrameworkTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoFrameworkTest.swift; sourceTree = ""; }; 30B0485F209A5141001013CA /* PasswordTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTest.swift; sourceTree = ""; }; 30B4C7B924084AAA008B86F7 /* PasswordGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerator.swift; sourceTree = ""; }; @@ -312,6 +339,8 @@ 30CCA919232591320048CA51 /* ObjectivePgp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectivePgp.swift; sourceTree = ""; }; 30DAFD49240985A7002456E7 /* Array+Slices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Slices.swift"; sourceTree = ""; }; 30DAFD4B240985E3002456E7 /* Array+SlicesTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+SlicesTest.swift"; sourceTree = ""; }; + 30EE3A18241E98C1009FBB61 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = en; path = en.lproj/Intents.intentdefinition; sourceTree = ""; }; + 30EE3A1B241E98C6009FBB61 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Intents.strings; sourceTree = ""; }; 30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = ""; }; 3B2B2F844061EFA534FE9506 /* Pods_passKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_passKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62DEE9943E0F2B8C79E3FC5B /* Pods-passExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.release.xcconfig"; sourceTree = ""; }; @@ -406,6 +435,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 30A69942240EED5E00B7D967 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 304E2125241550260047FB51 /* passKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; A239F5922158C08B00576CBF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -510,6 +547,17 @@ path = Extensions; sourceTree = ""; }; + 30A69946240EED5E00B7D967 /* passShortcuts */ = { + isa = PBXGroup; + children = ( + 30A69947240EED5E00B7D967 /* IntentHandler.swift */, + 30A69968240EF52E00B7D967 /* SyncRepositoryIntentHandler.swift */, + 304E212C241AD0EB0047FB51 /* passShortcuts.entitlements */, + 30A69949240EED5E00B7D967 /* Info.plist */, + ); + path = passShortcuts; + sourceTree = ""; + }; 30A86F93230F235800F821A4 /* Crypto */ = { isa = PBXGroup; children = ( @@ -811,6 +859,7 @@ A26700251EEC466A00176B8A /* passExtension */, A26075791EEC6F34005DB03E /* passKit */, A26075861EEC6F34005DB03E /* passKitTests */, + 30A69946240EED5E00B7D967 /* passShortcuts */, DC13B14F1E8640810097803F /* passTests */, DC917BD41E2E8231000FDF54 /* Products */, 30468FC4444CE00A19257B78 /* Pods */, @@ -826,6 +875,7 @@ A26075781EEC6F34005DB03E /* passKit.framework */, A26075801EEC6F34005DB03E /* passKitTests.xctest */, A239F5952158C08B00576CBF /* passAutoFillExtension.appex */, + 30A69945240EED5E00B7D967 /* PassShortcuts.appex */, ); name = Products; sourceTree = ""; @@ -844,6 +894,7 @@ 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */, 30BF5ECA21EA8FB5000E4154 /* Localizable.strings */, 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */, + 30EE3A19241E98C1009FBB61 /* Intents.intentdefinition */, DC917BE21E2E8231000FDF54 /* Info.plist */, ); path = pass; @@ -865,6 +916,7 @@ 134DA5B66070BA56678688CF /* Pods_passKit.framework */, 3B2B2F844061EFA534FE9506 /* Pods_passKitTests.framework */, 116F7CC822E134FA003B3BAC /* Crypto.framework */, + 30A6994F240EED5F00B7D967 /* IntentsUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -883,6 +935,24 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 30A69944240EED5E00B7D967 /* passShortcuts */ = { + isa = PBXNativeTarget; + buildConfigurationList = 30A69963240EED5F00B7D967 /* Build configuration list for PBXNativeTarget "passShortcuts" */; + buildPhases = ( + 30A69941240EED5E00B7D967 /* Sources */, + 30A69942240EED5E00B7D967 /* Frameworks */, + 30A69943240EED5E00B7D967 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 304E2128241550260047FB51 /* PBXTargetDependency */, + ); + name = passShortcuts; + productName = passShortcuts; + productReference = 30A69945240EED5E00B7D967 /* PassShortcuts.appex */; + productType = "com.apple.product-type.app-extension"; + }; A239F5942158C08B00576CBF /* passAutoFillExtension */ = { isa = PBXNativeTarget; buildConfigurationList = A239F5A22158C08C00576CBF /* Build configuration list for PBXNativeTarget "passAutoFillExtension" */; @@ -995,6 +1065,7 @@ A267002D1EEC466A00176B8A /* PBXTargetDependency */, A260758C1EEC6F34005DB03E /* PBXTargetDependency */, A239F5A02158C08C00576CBF /* PBXTargetDependency */, + 30A6995C240EED5F00B7D967 /* PBXTargetDependency */, ); name = pass; productName = pass; @@ -1007,10 +1078,15 @@ DC917BCB1E2E8231000FDF54 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1000; + LastSwiftUpdateCheck = 1130; LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Bob Sun"; TargetAttributes = { + 30A69944240EED5E00B7D967 = { + CreatedOnToolsVersion = 11.3; + DevelopmentTeam = 8F45X738ZV; + ProvisioningStyle = Automatic; + }; A239F5942158C08B00576CBF = { CreatedOnToolsVersion = 10.0; DevelopmentTeam = 4WDM8E95VU; @@ -1096,11 +1172,19 @@ A26075771EEC6F34005DB03E /* passKit */, A260757F1EEC6F34005DB03E /* passKitTests */, A239F5942158C08B00576CBF /* passAutoFillExtension */, + 30A69944240EED5E00B7D967 /* passShortcuts */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 30A69943240EED5E00B7D967 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; A239F5932158C08B00576CBF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1325,6 +1409,16 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 30A69941240EED5E00B7D967 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30EE3A17241E98C1009FBB61 /* Intents.intentdefinition in Sources */, + 30EE3A14241AE6EC009FBB61 /* SyncRepositoryIntentHandler.swift in Sources */, + 30A69948240EED5E00B7D967 /* IntentHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; A239F5912158C08B00576CBF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1428,6 +1522,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 30EE3A16241E98C1009FBB61 /* Intents.intentdefinition in Sources */, DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */, DCC441541E916382008A90C4 /* SSHKeyArmorImportTableViewController.swift in Sources */, 306D970E24091CDD006C0E2E /* SwitchTableViewCell.swift in Sources */, @@ -1476,6 +1571,16 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 304E2128241550260047FB51 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = A26075771EEC6F34005DB03E /* passKit */; + targetProxy = 304E2127241550260047FB51 /* PBXContainerItemProxy */; + }; + 30A6995C240EED5F00B7D967 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 30A69944240EED5E00B7D967 /* passShortcuts */; + targetProxy = 30A6995B240EED5F00B7D967 /* PBXContainerItemProxy */; + }; A239F5A02158C08C00576CBF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = A239F5942158C08B00576CBF /* passAutoFillExtension */; @@ -1536,6 +1641,15 @@ name = InfoPlist.strings; sourceTree = ""; }; + 30EE3A19241E98C1009FBB61 /* Intents.intentdefinition */ = { + isa = PBXVariantGroup; + children = ( + 30EE3A18241E98C1009FBB61 /* en */, + 30EE3A1B241E98C6009FBB61 /* de */, + ); + name = Intents.intentdefinition; + sourceTree = ""; + }; A239F59A2158C08C00576CBF /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -1573,6 +1687,59 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 30A6995E240EED5F00B7D967 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = passShortcuts/PassShortcuts.entitlements; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 8F45X738ZV; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = passShortcuts/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MARKETING_VERSION = 0.10.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passShortcuts; + PRODUCT_NAME = PassShortcuts; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 30A6995F240EED5F00B7D967 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = passShortcuts/PassShortcuts.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 8F45X738ZV; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = passShortcuts/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MARKETING_VERSION = 0.10.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.passShortcuts; + PRODUCT_NAME = PassShortcuts; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; A239F5A32158C08C00576CBF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1653,6 +1820,7 @@ HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -1697,6 +1865,7 @@ HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -1773,6 +1942,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -1802,6 +1972,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -2004,6 +2175,7 @@ ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -2041,6 +2213,7 @@ ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; MARKETING_VERSION = 0.10.0; @@ -2061,6 +2234,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 30A69963240EED5F00B7D967 /* Build configuration list for PBXNativeTarget "passShortcuts" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30A6995E240EED5F00B7D967 /* Debug */, + 30A6995F240EED5F00B7D967 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; A239F5A22158C08C00576CBF /* Build configuration list for PBXNativeTarget "passAutoFillExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/pass/Controllers/GitRepositorySettingsTableViewController.swift b/pass/Controllers/GitRepositorySettingsTableViewController.swift index b1ccaf7..00c8e1e 100644 --- a/pass/Controllers/GitRepositorySettingsTableViewController.swift +++ b/pass/Controllers/GitRepositorySettingsTableViewController.swift @@ -141,7 +141,7 @@ class GitRepositorySettingsTableViewController: UITableViewController { self.gitBranchName = branchName.trimmed self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed - if passwordStore.repositoryExisted() { + if passwordStore.repositoryExists() { let overwriteAlert: UIAlertController = { let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in diff --git a/pass/Controllers/PasswordsViewController.swift b/pass/Controllers/PasswordsViewController.swift index 0448099..6f40678 100644 --- a/pass/Controllers/PasswordsViewController.swift +++ b/pass/Controllers/PasswordsViewController.swift @@ -158,7 +158,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV } private func syncPasswords() { - guard passwordStore.repositoryExisted() else { + guard passwordStore.repositoryExists() else { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) { Utils.alert(title: "Error".localize(), message: "NoPasswordStore.".localize(), controller: self, completion: nil) } diff --git a/pass/Info.plist b/pass/Info.plist index c4ab98c..e031099 100644 --- a/pass/Info.plist +++ b/pass/Info.plist @@ -37,6 +37,10 @@ We need to access your camera for scanning QR codes. NSFaceIDUsageDescription Enable access to Face ID to unlock Pass. + NSUserActivityTypes + + SyncRepositoryIntent + UIApplicationShortcutItems diff --git a/pass/de.lproj/Intents.strings b/pass/de.lproj/Intents.strings new file mode 100644 index 0000000..8e1d225 --- /dev/null +++ b/pass/de.lproj/Intents.strings @@ -0,0 +1,30 @@ +"0r0NKK" = "Die Übertragung von lokalen Daten zum entfernten Repository schlug fehl."; + +"2jFDLY" = "Synchronisiere das Repository."; + +"H2uxch" = "Es wurde kein Passwort für die Kommunikation mit dem Server gespeichert."; + +"HO0DF8" = "Es wurde kein Passwort für die Kommunikation mit dem Server gespeichert."; + +"IhvhFk" = "Die Synchronisation war erfolgreich."; + +"JthclV" = "Es gibt kein lokales Repository."; + +"KFGEkd" = "Synchronisiere Repository"; + +"O9MV3m" = "Die Synchronisation schlug fehl."; + +"URQN5E" = "Die Synchronisation war erfolgreich."; + +"k4AscG" = "Das Laden von Änderungen vom entfernten Server schlug fehl."; + +"kbRWJu" = "Das Laden von Änderungen vom entfernten Server schlug fehl."; + +"nuN5Fq" = "Synchronisiere das Repository."; + +"qr6SIW" = "Es gibt kein lokales Repository."; + +"wB7FJn" = "Die Synchronisation schlug fehl."; + +"z8bZQR" = "Die Übertragung von lokalen Daten zum entfernten Repository schlug fehl."; + diff --git a/pass/en.lproj/Intents.intentdefinition b/pass/en.lproj/Intents.intentdefinition new file mode 100644 index 0000000..ba1dd5f --- /dev/null +++ b/pass/en.lproj/Intents.intentdefinition @@ -0,0 +1,143 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.1 + INIntentDefinitionNamespace + wCllDN + INIntentDefinitionSystemVersion + 19D76 + INIntentDefinitionToolsBuildVersion + 11C29 + INIntentDefinitionToolsVersion + 11.3 + INIntents + + + INIntentCategory + generic + INIntentConfigurable + + INIntentDefaultImageName + Refresh + INIntentDescription + Sync the password repository. + INIntentDescriptionID + nuN5Fq + INIntentIneligibleForSuggestions + + INIntentManagedParameterCombinations + + + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Sync repository with server + INIntentParameterCombinationTitleID + 2jFDLY + INIntentParameterCombinationUpdatesLinked + + + + INIntentName + SyncRepository + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeConciseFormatString + Syncing was successful. + INIntentResponseCodeConciseFormatStringID + URQN5E + INIntentResponseCodeFormatString + Syncing was successful. + INIntentResponseCodeFormatStringID + IhvhFk + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeConciseFormatString + Syncing failed. + INIntentResponseCodeConciseFormatStringID + wB7FJn + INIntentResponseCodeFormatString + Syncing failed. + INIntentResponseCodeFormatStringID + O9MV3m + INIntentResponseCodeName + failure + + + INIntentResponseCodeConciseFormatString + There is no saved passphrase to communicate with the remote repository. + INIntentResponseCodeConciseFormatStringID + H2uxch + INIntentResponseCodeFormatString + There is no saved passphrase to communicate with the remote repository. + INIntentResponseCodeFormatStringID + HO0DF8 + INIntentResponseCodeName + noPassphrase + + + INIntentResponseCodeConciseFormatString + Pulling changes from the remote repository failed. + INIntentResponseCodeConciseFormatStringID + kbRWJu + INIntentResponseCodeFormatString + Pulling changes from the remote repository failed. + INIntentResponseCodeFormatStringID + k4AscG + INIntentResponseCodeName + pullFailed + + + INIntentResponseCodeConciseFormatString + Pushing changes to the remote repository failed. + INIntentResponseCodeConciseFormatStringID + z8bZQR + INIntentResponseCodeFormatString + Pushing changes to the remote repository failed. + INIntentResponseCodeFormatStringID + 0r0NKK + INIntentResponseCodeName + pushFailed + + + INIntentResponseCodeConciseFormatString + There is no local repository. + INIntentResponseCodeConciseFormatStringID + qr6SIW + INIntentResponseCodeFormatString + There is no local repository. + INIntentResponseCodeFormatStringID + JthclV + INIntentResponseCodeName + noRepository + + + + INIntentTitle + Sync Repository + INIntentTitleID + KFGEkd + INIntentType + Custom + INIntentUserConfirmationRequired + + INIntentVerb + Do + + + INTypes + + + diff --git a/pass/pass.entitlements b/pass/pass.entitlements index d58dedc..1444b8a 100644 --- a/pass/pass.entitlements +++ b/pass/pass.entitlements @@ -4,6 +4,8 @@ com.apple.developer.authentication-services.autofill-credential-provider + com.apple.developer.siri + com.apple.security.application-groups group.me.mssun.passforios diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 3eb4976..1d5237b 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -124,7 +124,7 @@ public class PasswordStore { Defaults.remove(\.gitSSHPrivateKeyArmor) } - public func repositoryExisted() -> Bool { + public func repositoryExists() -> Bool { let fm = FileManager() return fm.fileExists(atPath: Globals.repositoryPath) } diff --git a/passShortcuts/Info.plist b/passShortcuts/Info.plist new file mode 100644 index 0000000..8b91ff6 --- /dev/null +++ b/passShortcuts/Info.plist @@ -0,0 +1,42 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + $(PRODUCT_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsRestrictedWhileProtectedDataUnavailable + + IntentsSupported + + SyncRepositoryIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).IntentHandler + + + diff --git a/passShortcuts/IntentHandler.swift b/passShortcuts/IntentHandler.swift new file mode 100644 index 0000000..294acd6 --- /dev/null +++ b/passShortcuts/IntentHandler.swift @@ -0,0 +1,20 @@ +// +// IntentHandler.swift +// passShortcuts +// +// Created by Danny Moesch on 03.03.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +import Intents +import passKit + +class IntentHandler: INExtension { + + override func handler(for intent: INIntent) -> Any { + guard intent is SyncRepositoryIntent else { + fatalError("Unhandled intent type \(intent).") + } + return SyncRepositoryIntentHandler() + } +} diff --git a/passShortcuts/SyncRepositoryIntentHandler.swift b/passShortcuts/SyncRepositoryIntentHandler.swift new file mode 100644 index 0000000..4e4b1e0 --- /dev/null +++ b/passShortcuts/SyncRepositoryIntentHandler.swift @@ -0,0 +1,58 @@ +// +// SyncRepositoryIntentHandler.swift +// passShortcuts +// +// Created by Danny Moesch on 03.03.20. +// Copyright © 2020 Bob Sun. All rights reserved. +// + +import Intents +import passKit + +public class SyncRepositoryIntentHandler: NSObject, SyncRepositoryIntentHandling { + + private let passwordStore = PasswordStore.shared + private let keychain = AppKeychain.shared + + private var gitCredential: GitCredential { + switch Defaults.gitAuthenticationMethod { + case .password: + return GitCredential(credential: .http(userName: Defaults.gitUsername)) + case .key: + let privateKey: String = keychain.get(for: SshKey.PRIVATE.getKeychainKey()) ?? "" + return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey)) + } + } + + public func handle(intent: SyncRepositoryIntent, completion: @escaping (SyncRepositoryIntentResponse) -> Void) { + guard passwordStore.repositoryExists() else { + completion(SyncRepositoryIntentResponse(code: .noRepository, userActivity: nil)) + return + } + guard isPasswordRemembered else { + completion(SyncRepositoryIntentResponse(code: .noPassphrase, userActivity: nil)) + return + } + do { + try passwordStore.pullRepository(credential: gitCredential, requestCredentialPassword: { _, _ in nil }, progressBlock: { _, _ in }) + } catch { + completion(SyncRepositoryIntentResponse(code: .pullFailed, userActivity: nil)) + return + } + if passwordStore.numberOfLocalCommits > 0 { + do { + try passwordStore.pushRepository(credential: gitCredential, requestCredentialPassword: { _, _ in nil }, transferProgressBlock: { _, _, _, _ in }) + } catch { + completion(SyncRepositoryIntentResponse(code: .pushFailed, userActivity: nil)) + return + } + } + completion(SyncRepositoryIntentResponse(code: .success, userActivity: nil)) + } + + private var isPasswordRemembered: Bool { + let authenticationMethod = Defaults.gitAuthenticationMethod + return authenticationMethod == .password && keychain.contains(key: Globals.gitPassword) + || authenticationMethod == .key && keychain.contains(key: Globals.gitSSHPrivateKeyPassphrase) + } +} diff --git a/passShortcuts/passShortcuts.entitlements b/passShortcuts/passShortcuts.entitlements new file mode 100644 index 0000000..13c5967 --- /dev/null +++ b/passShortcuts/passShortcuts.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.me.mssun.passforios + + keychain-access-groups + + $(AppIdentifierPrefix)group.me.mssun.passforios + + +