From a0fe44d214e39b6d012d938796041c10be10d924 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Fri, 28 Jan 2022 17:20:29 +0100 Subject: [PATCH 01/27] Automatic configuration files changes by Xcode Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/UI/iOS/Info.plist | 15 +++++++------- WireGuard.xcodeproj/project.pbxproj | 28 ++++++++++++-------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Sources/WireGuardApp/UI/iOS/Info.plist b/Sources/WireGuardApp/UI/iOS/Info.plist index 7d910772d..754d12c7e 100644 --- a/Sources/WireGuardApp/UI/iOS/Info.plist +++ b/Sources/WireGuardApp/UI/iOS/Info.plist @@ -2,10 +2,10 @@ - ITSAppUsesNonExemptEncryption - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + $(PRODUCT_NAME) CFBundleDocumentTypes @@ -64,8 +64,6 @@ $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 - CFBundleDisplayName - $(PRODUCT_NAME) CFBundleName $(PRODUCT_NAME) CFBundlePackageType @@ -74,17 +72,20 @@ $(VERSION_NAME) CFBundleVersion $(VERSION_ID) + ITSAppUsesNonExemptEncryption + LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace NSCameraUsageDescription Localized + NSFaceIDUsageDescription + Localized UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities - - + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -123,8 +124,6 @@ - NSFaceIDUsageDescription - Localized com.wireguard.ios.app_group_id group.$(APP_ID_IOS) diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 8b19d16f0..25016cd18 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -347,8 +347,6 @@ 6F6483E6229293300075BA15 /* LaunchedAtLoginDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchedAtLoginDetector.swift; sourceTree = ""; }; 6F689999218043390012E523 /* WireGuard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuard-Bridging-Header.h"; sourceTree = ""; }; 6F70E20D221058DF008BDFB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Sources/WireGuardApp/Base.lproj/InfoPlist.strings; sourceTree = ""; }; - 6F70E20D221058DF008BDFBA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Sources/WireGuardApp/zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 6F70E20D221058DF008BDFC6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Sources/WireGuardApp/zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 6F70E22922106A2D008BDFB4 /* WireGuardLoginItemHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuardLoginItemHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6F70E23222106A31008BDFB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6F70E23922109BEF008BDFB4 /* LoginItemHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LoginItemHelper.entitlements; sourceTree = ""; }; @@ -404,24 +402,24 @@ 6FDEF801218646B900D8FBF6 /* ZipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipArchive.swift; sourceTree = ""; }; 6FDEF805218725D200D8FBF6 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; 6FE1765521C90BBE002690EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Sources/WireGuardApp/Base.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690FC /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh-Hant; path = Sources/WireGuardApp/zh-Hant.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F0 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh-Hans; path = Sources/WireGuardApp/zh-Hans.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690FB /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = Sources/WireGuardApp/id.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F2 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = Sources/WireGuardApp/it.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F9 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Sources/WireGuardApp/de.lproj/Localizable.strings; sourceTree = ""; }; 6FE1765521C90BBE002690EB /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Sources/WireGuardApp/fr.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F5 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = Sources/WireGuardApp/fi.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F4 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = Sources/WireGuardApp/fa.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690FA /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = Sources/WireGuardApp/sl.lproj/Localizable.strings; sourceTree = ""; }; 6FE1765521C90BBE002690EC /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = Sources/WireGuardApp/pl.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690EF /* pa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pa; path = Sources/WireGuardApp/pa.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F7 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = Sources/WireGuardApp/ko.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690ED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Sources/WireGuardApp/es.lproj/Localizable.strings; sourceTree = ""; }; 6FE1765521C90BBE002690EE /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = Sources/WireGuardApp/ca.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F6 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Sources/WireGuardApp/ru.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690EF /* pa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pa; path = Sources/WireGuardApp/pa.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F0 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Sources/WireGuardApp/zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 6FE1765521C90BBE002690F1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = Sources/WireGuardApp/ja.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F2 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = Sources/WireGuardApp/it.lproj/Localizable.strings; sourceTree = ""; }; 6FE1765521C90BBE002690F3 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = Sources/WireGuardApp/ro.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F4 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = Sources/WireGuardApp/fa.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F5 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = Sources/WireGuardApp/fi.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F6 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Sources/WireGuardApp/ru.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F7 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = Sources/WireGuardApp/ko.lproj/Localizable.strings; sourceTree = ""; }; 6FE1765521C90BBE002690F8 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = Sources/WireGuardApp/tr.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690F1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = Sources/WireGuardApp/ja.lproj/Localizable.strings; sourceTree = ""; }; - 6FE1765521C90BBE002690ED /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Sources/WireGuardApp/es.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690F9 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Sources/WireGuardApp/de.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690FA /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = Sources/WireGuardApp/sl.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690FB /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = Sources/WireGuardApp/id.lproj/Localizable.strings; sourceTree = ""; }; + 6FE1765521C90BBE002690FC /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Sources/WireGuardApp/zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 6FE1765921C90E87002690EA /* LocalizationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationHelper.swift; sourceTree = ""; }; 6FE254FA219C10800028284D /* ZipImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipImporter.swift; sourceTree = ""; }; 6FE254FE219C60290028284D /* ZipExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipExporter.swift; sourceTree = ""; }; From 3c63c386b971277a355aa6117d9b598fdf16b363 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Fri, 28 Jan 2022 21:37:06 +0100 Subject: [PATCH 02/27] project: Added WireGuardIntentsExtensioniOS target and Siri capability Signed-off-by: Alessio Nossa --- .../UI/iOS/WireGuard.entitlements | 2 + Sources/WireGuardIntentsExtension/Info.plist | 46 ++++++ .../IntentHandler.swift | 15 ++ ...ireGuardIntentsExtension-Bridging-Header.h | 1 + ...WireGuardIntentsExtension_iOS.entitlements | 10 ++ WireGuard.xcodeproj/project.pbxproj | 138 +++++++++++++++++- 6 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 Sources/WireGuardIntentsExtension/Info.plist create mode 100644 Sources/WireGuardIntentsExtension/IntentHandler.swift create mode 100644 Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h create mode 100644 Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements diff --git a/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements b/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements index 93c724936..60d6ee429 100644 --- a/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements +++ b/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements @@ -8,6 +8,8 @@ com.apple.developer.networking.wifi-info + com.apple.developer.siri + com.apple.security.application-groups group.$(APP_ID_IOS) diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist new file mode 100644 index 000000000..dac8df520 --- /dev/null +++ b/Sources/WireGuardIntentsExtension/Info.plist @@ -0,0 +1,46 @@ + + + + + ITSAppUsesNonExemptEncryption + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + WireGuardIntentsExtension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + $(VERSION_NAME) + CFBundleVersion + $(VERSION_ID) + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsSupported + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).IntentHandler + + com.wireguard.ios.app_group_id + group.$(APP_ID_IOS) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + com.wireguard.macos.app_group_id + $(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS) + + diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift new file mode 100644 index 000000000..fc4899c56 --- /dev/null +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import Intents + +class IntentHandler: INExtension { + + override func handler(for intent: INIntent) -> Any { + // This is the default implementation. If you want different objects to handle different intents, + // you can override this and return the handler you want for that particular intent. + + return self + } + +} diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h @@ -0,0 +1 @@ + diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements new file mode 100644 index 000000000..75c276b3e --- /dev/null +++ b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.$(APP_ID_IOS) + + + diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 25016cd18..5ed7ad0d4 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,6 +205,9 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; + A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; + A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8051E27A44F770088E750 /* IntentHandler.swift */; }; + A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -243,6 +246,13 @@ remoteGlobalIDString = 6FDEF7DD21846BC100D8FBF6; remoteInfo = WireGuardGoBridge; }; + A6B8052127A44F770088E750 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6FF4AC0C211EC46F002C96EB /* Project object */; + proxyType = 1; + remoteGlobalIDString = A6B8051927A44F770088E750; + remoteInfo = WireGuardIntentsExtensioniOS; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -253,6 +263,7 @@ dstSubfolderSpec = 13; files = ( 6F5D0C22218352EF000F85AD /* WireGuardNetworkExtension.appex in Embed App Extensions */, + A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -438,6 +449,12 @@ 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = ""; }; 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandOption.swift; sourceTree = ""; }; 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; + A64A79D727A462FC00F15B34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardIntentsExtension-Bridging-Header.h"; sourceTree = ""; }; + A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WireGuardIntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + A6B8051B27A44F770088E750 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; + A6B8051E27A44F770088E750 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; + A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardIntentsExtension_iOS.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -475,6 +492,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A6B8051727A44F770088E750 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -765,6 +790,7 @@ 6F5D0C432183B4A4000F85AD /* Shared */, 6FF4AC16211EC46F002C96EB /* WireGuardApp */, 6F5D0C1B218352EF000F85AD /* WireGuardNetworkExtension */, + A6B8051D27A44F770088E750 /* WireGuardIntentsExtension */, 585B10452577E293004F691E /* WireGuardKit */, 585B10532577E293004F691E /* WireGuardKitC */, 6FF4AC15211EC46F002C96EB /* Products */, @@ -780,6 +806,7 @@ 6FB1BD5D21D2607A00A991BF /* WireGuard.app */, 6FB1BD9121D4BFE600A991BF /* WireGuardNetworkExtension.appex */, 6F70E22922106A2D008BDFB4 /* WireGuardLoginItemHelper.app */, + A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */, ); name = Products; sourceTree = ""; @@ -807,10 +834,23 @@ 58DB6CD52577F95D00FB6B73 /* libwg-go.a */, 6FB1BDB621D4F8B800A991BF /* NetworkExtension.framework */, 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */, + A6B8051B27A44F770088E750 /* Intents.framework */, ); name = Frameworks; sourceTree = ""; }; + A6B8051D27A44F770088E750 /* WireGuardIntentsExtension */ = { + isa = PBXGroup; + children = ( + A64A79D727A462FC00F15B34 /* Info.plist */, + A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */, + A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */, + A6B8051E27A44F770088E750 /* IntentHandler.swift */, + ); + name = WireGuardIntentsExtension; + path = Sources/WireGuardIntentsExtension; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ @@ -944,6 +984,7 @@ ); dependencies = ( 6F5D0C21218352EF000F85AD /* PBXTargetDependency */, + A6B8052227A44F770088E750 /* PBXTargetDependency */, ); name = WireGuardiOS; packageProductDependencies = ( @@ -952,13 +993,30 @@ productReference = 6FF4AC14211EC46F002C96EB /* WireGuard.app */; productType = "com.apple.product-type.application"; }; + A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = A6B8052427A44F770088E750 /* Build configuration list for PBXNativeTarget "WireGuardIntentsExtensioniOS" */; + buildPhases = ( + A6B8051627A44F770088E750 /* Sources */, + A6B8051727A44F770088E750 /* Frameworks */, + A6B8051827A44F770088E750 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WireGuardIntentsExtensioniOS; + productName = WireGuardIntentsExtensioniOS; + productReference = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 6FF4AC0C211EC46F002C96EB /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1010; + LastSwiftUpdateCheck = 1320; LastUpgradeCheck = 1010; ORGANIZATIONNAME = "WireGuard LLC"; TargetAttributes = { @@ -1016,6 +1074,9 @@ }; }; }; + A6B8051927A44F770088E750 = { + CreatedOnToolsVersion = 13.2.1; + }; }; }; buildConfigurationList = 6FF4AC0F211EC46F002C96EB /* Build configuration list for PBXProject "WireGuard" */; @@ -1053,6 +1114,7 @@ targets = ( 6FF4AC13211EC46F002C96EB /* WireGuardiOS */, 6F5D0C19218352EF000F85AD /* WireGuardNetworkExtensioniOS */, + A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */, 6FDEF7DD21846BC100D8FBF6 /* WireGuardGoBridgeiOS */, 6FB1BD5C21D2607A00A991BF /* WireGuardmacOS */, 6FB1BD9021D4BFE600A991BF /* WireGuardNetworkExtensionmacOS */, @@ -1101,6 +1163,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A6B8051827A44F770088E750 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1465,6 +1534,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A6B8051627A44F770088E750 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1493,6 +1570,11 @@ target = 6FDEF7DD21846BC100D8FBF6 /* WireGuardGoBridgeiOS */; targetProxy = 6FDEF7E121846C0000D8FBF6 /* PBXContainerItemProxy */; }; + A6B8052227A44F770088E750 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */; + targetProxy = A6B8052127A44F770088E750 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1897,6 +1979,51 @@ }; name = Release; }; + A6B8052527A44F770088E750 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Sources/WireGuardIntentsExtension/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_IOS).intents-extension"; + PRODUCT_NAME = WireGuardIntentsExtension; + SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + A6B8052627A44F770088E750 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Sources/WireGuardIntentsExtension/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_IOS).intents-extension"; + PRODUCT_NAME = WireGuardIntentsExtension; + SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1972,6 +2099,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + A6B8052427A44F770088E750 /* Build configuration list for PBXNativeTarget "WireGuardIntentsExtensioniOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A6B8052527A44F770088E750 /* Debug */, + A6B8052627A44F770088E750 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 6FF4AC0C211EC46F002C96EB /* Project object */; From 0dd06728445470a10c840d0be165db9419c411d0 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Sat, 29 Jan 2022 17:06:18 +0100 Subject: [PATCH 03/27] project: Added sources to WireGuardIntentsExtensioniOS Signed-off-by: Alessio Nossa --- ...ireGuardIntentsExtension-Bridging-Header.h | 3 +- WireGuard.xcodeproj/project.pbxproj | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h index 8b1378917..195da7337 100644 --- a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h +++ b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h @@ -1 +1,2 @@ - +#include "../WireGuardKitC/WireGuardKitC.h" +#include "ringlogger.h" diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 5ed7ad0d4..8c9ff8788 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,6 +205,33 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; + A64A79DC27A5411700F15B34 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526E21C23FA10008484E /* Logger.swift */; }; + A64A79DD27A5411E00F15B34 /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; }; + A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; }; + A64A79E027A5422E00F15B34 /* NotificationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58233BCE2591F842002060A8 /* NotificationToken.swift */; }; + A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10492577E293004F691E /* TunnelConfiguration.swift */; }; + A64A79E227A5428C00F15B34 /* PrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B104F2577E293004F691E /* PrivateKey.swift */; }; + A64A79E327A5429100F15B34 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10472577E293004F691E /* PeerConfiguration.swift */; }; + A64A79E427A542A700F15B34 /* IPAddressRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10512577E293004F691E /* IPAddressRange.swift */; }; + A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10462577E293004F691E /* InterfaceConfiguration.swift */; }; + A64A79E627A542C700F15B34 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10522577E293004F691E /* Endpoint.swift */; }; + A64A79E727A542CA00F15B34 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10482577E293004F691E /* DNSServer.swift */; }; + A64A79E827A542F800F15B34 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 585B10572577E293004F691E /* key.c */; }; + A64A79E927A542FC00F15B34 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 585B10562577E293004F691E /* x25519.c */; }; + A64A79EA27A5439900F15B34 /* TunnelErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */; }; + A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1E821B932F700483816 /* WireGuardAppError.swift */; }; + A64A79EC27A543ED00F15B34 /* LocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765921C90E87002690EA /* LocalizationHelper.swift */; }; + A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541A821C451D100994C13 /* TunnelStatus.swift */; }; + A64A79EE27A5442000F15B34 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; + A64A79EF27A5444600F15B34 /* FileManager+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */; }; + A64A79F027A5445F00F15B34 /* RecentTunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */; }; + A64A79F127A5447000F15B34 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; }; + A64A79F227A5449300F15B34 /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; }; + A64A79F327A544A500F15B34 /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; }; + A64A79F427A544BC00F15B34 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; + A64A79F527A544E800F15B34 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; }; + A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1EA21B937EF00483816 /* WireGuardResult.swift */; }; + A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; }; A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8051E27A44F770088E750 /* IntentHandler.swift */; }; A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -1539,6 +1566,33 @@ buildActionMask = 2147483647; files = ( A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */, + A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */, + A64A79EF27A5444600F15B34 /* FileManager+Extension.swift in Sources */, + A64A79E027A5422E00F15B34 /* NotificationToken.swift in Sources */, + A64A79DC27A5411700F15B34 /* Logger.swift in Sources */, + A64A79DD27A5411E00F15B34 /* ringlogger.c in Sources */, + A64A79F527A544E800F15B34 /* TunnelConfiguration+UapiConfig.swift in Sources */, + A64A79E827A542F800F15B34 /* key.c in Sources */, + A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */, + A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */, + A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */, + A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */, + A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */, + A64A79F127A5447000F15B34 /* NETunnelProviderProtocol+Extension.swift in Sources */, + A64A79E327A5429100F15B34 /* PeerConfiguration.swift in Sources */, + A64A79EE27A5442000F15B34 /* Keychain.swift in Sources */, + A64A79F327A544A500F15B34 /* String+ArrayConversion.swift in Sources */, + A64A79E227A5428C00F15B34 /* PrivateKey.swift in Sources */, + A64A79F427A544BC00F15B34 /* ActivateOnDemandOption.swift in Sources */, + A64A79E627A542C700F15B34 /* Endpoint.swift in Sources */, + A64A79E927A542FC00F15B34 /* x25519.c in Sources */, + A64A79E727A542CA00F15B34 /* DNSServer.swift in Sources */, + A64A79E427A542A700F15B34 /* IPAddressRange.swift in Sources */, + A64A79EA27A5439900F15B34 /* TunnelErrors.swift in Sources */, + A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */, + A64A79F227A5449300F15B34 /* TunnelConfiguration+WgQuickConfig.swift in Sources */, + A64A79F027A5445F00F15B34 /* RecentTunnelsTracker.swift in Sources */, + A64A79EC27A543ED00F15B34 /* LocalizationHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From ab1e96fcdcaa5128f619ca565b0f5303935b4518 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Sat, 29 Jan 2022 19:11:32 +0100 Subject: [PATCH 04/27] Implemented GetPeers intent Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 157 ++++++++++++++++++ Sources/WireGuardIntentsExtension/Info.plist | 6 +- .../IntentHandler.swift | 12 +- .../IntentHandling.swift | 120 +++++++++++++ ...WireGuardIntentsExtension_iOS.entitlements | 4 + WireGuard.xcodeproj/project.pbxproj | 12 ++ 6 files changed, 307 insertions(+), 4 deletions(-) create mode 100644 Sources/Shared/Intents.intentdefinition create mode 100644 Sources/WireGuardIntentsExtension/IntentHandling.swift diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition new file mode 100644 index 000000000..38f8e5467 --- /dev/null +++ b/Sources/Shared/Intents.intentdefinition @@ -0,0 +1,157 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + 6NREiY + INIntentDefinitionSystemVersion + 21C52 + INIntentDefinitionToolsBuildVersion + 13C100 + INIntentDefinitionToolsVersion + 13.2.1 + INIntents + + + INIntentCategory + generic + INIntentConfigurable + + INIntentDescription + Get list of public keys of peers in the selected configuration + INIntentDescriptionID + e4jxYU + INIntentIneligibleForSuggestions + + INIntentKeyParameter + tunnel + INIntentLastParameterTag + 1 + INIntentManagedParameterCombinations + + tunnel + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Get peers of ${tunnel} + INIntentParameterCombinationTitleID + 5Ewt1o + INIntentParameterCombinationUpdatesLinked + + + + INIntentName + GetPeers + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Tunnel + INIntentParameterDisplayNameID + tUPuxx + INIntentParameterDisplayPriority + 1 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Sentences + INIntentParameterMetadataDefaultValueID + 0AfeHS + + INIntentParameterName + tunnel + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterTag + 1 + INIntentParameterType + String + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + INIntentResponseCodeConciseFormatString + Failed to retrive configuration with the provided name. + INIntentResponseCodeConciseFormatStringID + ExhkKO + INIntentResponseCodeFormatString + Failed to retrive configuration with the provided name. + INIntentResponseCodeFormatStringID + lxnQb0 + INIntentResponseCodeName + wrongTunnel + + + INIntentResponseLastParameterTag + 2 + INIntentResponseOutput + peersPublicKeys + INIntentResponseParameters + + + INIntentResponseParameterDisplayName + Peers Public Keys + INIntentResponseParameterDisplayNameID + zJOQgA + INIntentResponseParameterDisplayPriority + 1 + INIntentResponseParameterName + peersPublicKeys + INIntentResponseParameterSupportsMultipleValues + + INIntentResponseParameterTag + 2 + INIntentResponseParameterType + String + + + + INIntentTitle + Get Peers + INIntentTitleID + V1ySW4 + INIntentType + Custom + INIntentVerb + Do + + + INTypes + + + diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist index dac8df520..35910e1c6 100644 --- a/Sources/WireGuardIntentsExtension/Info.plist +++ b/Sources/WireGuardIntentsExtension/Info.plist @@ -28,8 +28,12 @@ IntentsRestrictedWhileLocked - IntentsSupported + IntentsRestrictedWhileProtectedDataUnavailable + IntentsSupported + + GetPeersIntent + NSExtensionPointIdentifier com.apple.intents-service diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index fc4899c56..4567b499c 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -5,11 +5,17 @@ import Intents class IntentHandler: INExtension { + override init() { + super.init() + Logger.configureGlobal(tagged: "INTENTS", withFilePath: FileManager.logFileURL?.path) + } + override func handler(for intent: INIntent) -> Any { - // This is the default implementation. If you want different objects to handle different intents, - // you can override this and return the handler you want for that particular intent. + guard intent is GetPeersIntent else { + fatalError("Unhandled intent type: \(intent)") + } - return self + return IntentHandling() } } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift new file mode 100644 index 000000000..d94616032 --- /dev/null +++ b/Sources/WireGuardIntentsExtension/IntentHandling.swift @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import Intents + +class IntentHandling: NSObject { + + public enum IntentError: Error { + case failedDecode + case wrongTunnel + case unknown + } + + var tunnelsManager: TunnelsManager? + + var onTunnelsManagerReady: ((TunnelsManager) -> Void)? + + override init() { + super.init() + + TunnelsManager.create { [weak self] result in + guard let self = self else { return } + + switch result { + case .failure(let error): + wg_log(.error, message: error.localizedDescription) + case .success(let tunnelsManager): + self.tunnelsManager = tunnelsManager + + self.onTunnelsManagerReady?(tunnelsManager) + self.onTunnelsManagerReady = nil + } + } + } + + init(tunnelsManager: TunnelsManager) { + super.init() + + self.tunnelsManager = tunnelsManager + } +} + +extension IntentHandling { + + private func allTunnelNames(completion: @escaping ([String]?) -> Void) { + let getTunnelsNameBlock: (TunnelsManager) -> Void = { tunnelsManager in + let tunnelsNames = tunnelsManager.mapTunnels { $0.name } + return completion(tunnelsNames) + } + + if let tunnelsManager = tunnelsManager { + getTunnelsNameBlock(tunnelsManager) + } else { + if onTunnelsManagerReady != nil { + wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelNames function. This should not happen.") + } + onTunnelsManagerReady = getTunnelsNameBlock + } + } + + private func allTunnelPeers(for tunnelName: String, completion: @escaping (Result<[String], IntentError>) -> Void) { + let getPeersFromConfigBlock: (TunnelsManager) -> Void = { tunnelsManager in + guard let tunnel = tunnelsManager.tunnel(named: tunnelName) else { + return completion(.failure(.wrongTunnel)) + } + + guard let publicKeys = tunnel.tunnelConfiguration?.peers.map({ $0.publicKey.base64Key }) else { + return completion(.failure(.unknown)) + } + return completion(.success(publicKeys)) + } + + if let tunnelsManager = tunnelsManager { + getPeersFromConfigBlock(tunnelsManager) + } else { + if onTunnelsManagerReady != nil { + wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelPeers function. This should not happen.") + } + onTunnelsManagerReady = getPeersFromConfigBlock + } + } +} + +extension IntentHandling: GetPeersIntentHandling { + + @available(iOSApplicationExtension 14.0, *) + func provideTunnelOptionsCollection(for intent: GetPeersIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + + self.allTunnelNames { tunnelsNames in + let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } + + let objectCollection = INObjectCollection(items: tunnelsNamesObjects) + completion(objectCollection, nil) + } + } + + func handle(intent: GetPeersIntent, completion: @escaping (GetPeersIntentResponse) -> Void) { + guard let tunnel = intent.tunnel else { + return completion(GetPeersIntentResponse(code: .failure, userActivity: nil)) + } + + self.allTunnelPeers(for: tunnel) { peersResult in + switch peersResult { + case .success(let peers): + let response = GetPeersIntentResponse(code: .success, userActivity: nil) + response.peersPublicKeys = peers + completion(response) + + case .failure(let error): + switch error { + case .wrongTunnel: + completion(GetPeersIntentResponse(code: .wrongTunnel, userActivity: nil)) + default: + completion(GetPeersIntentResponse(code: .failure, userActivity: nil)) + } + } + } + } + +} diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements index 75c276b3e..33ce9fca4 100644 --- a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements +++ b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements @@ -2,6 +2,10 @@ + com.apple.developer.networking.networkextension + + packet-tunnel-provider + com.apple.security.application-groups group.$(APP_ID_IOS) diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 8c9ff8788..53db590f8 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -231,6 +231,10 @@ A64A79F427A544BC00F15B34 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; A64A79F527A544E800F15B34 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; }; A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1EA21B937EF00483816 /* WireGuardResult.swift */; }; + A64A79F927A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; + A64A79FA27A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; + A64A79FC27A548A000F15B34 /* IntentHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64A79FB27A548A000F15B34 /* IntentHandling.swift */; }; + A64A79FD27A54AA500F15B34 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; }; A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8051E27A44F770088E750 /* IntentHandler.swift */; }; @@ -478,6 +482,8 @@ 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; A64A79D727A462FC00F15B34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardIntentsExtension-Bridging-Header.h"; sourceTree = ""; }; + A64A79F827A5462900F15B34 /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = ""; }; + A64A79FB27A548A000F15B34 /* IntentHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandling.swift; sourceTree = ""; }; A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WireGuardIntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; A6B8051B27A44F770088E750 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; A6B8051E27A44F770088E750 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; @@ -524,6 +530,7 @@ buildActionMask = 2147483647; files = ( A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */, + A64A79FD27A54AA500F15B34 /* NetworkExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -636,6 +643,7 @@ 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */, 6B5C5E26220A48D30024272E /* Keychain.swift */, 58233BCE2591F842002060A8 /* NotificationToken.swift */, + A64A79F827A5462900F15B34 /* Intents.intentdefinition */, ); name = Shared; path = Sources/Shared; @@ -873,6 +881,7 @@ A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */, A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */, A6B8051E27A44F770088E750 /* IntentHandler.swift */, + A64A79FB27A548A000F15B34 /* IntentHandling.swift */, ); name = WireGuardIntentsExtension; path = Sources/WireGuardIntentsExtension; @@ -1533,6 +1542,7 @@ 6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */, 5F45418C21C2D48200994C13 /* TunnelEditKeyValueCell.swift in Sources */, 6FE254FB219C10800028284D /* ZipImporter.swift in Sources */, + A64A79F927A5462900F15B34 /* Intents.intentdefinition in Sources */, 585B107E2577E294004F691E /* PrivateKey.swift in Sources */, 6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */, 6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */, @@ -1575,11 +1585,13 @@ A64A79E827A542F800F15B34 /* key.c in Sources */, A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */, A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */, + A64A79FC27A548A000F15B34 /* IntentHandling.swift in Sources */, A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */, A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */, A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */, A64A79F127A5447000F15B34 /* NETunnelProviderProtocol+Extension.swift in Sources */, A64A79E327A5429100F15B34 /* PeerConfiguration.swift in Sources */, + A64A79FA27A5462900F15B34 /* Intents.intentdefinition in Sources */, A64A79EE27A5442000F15B34 /* Keychain.swift in Sources */, A64A79F327A544A500F15B34 /* String+ArrayConversion.swift in Sources */, A64A79E227A5428C00F15B34 /* PrivateKey.swift in Sources */, From ceabb4ea341ef0e792c5d0f06c6128d1e91ad522 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Sat, 29 Jan 2022 17:17:05 +0100 Subject: [PATCH 05/27] WireguardApp: iOS: Moved tunnelsManager initialization to AppDelegate Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/UI/iOS/AppDelegate.swift | 23 +++++++++++++ .../ViewController/MainViewController.swift | 33 +++++++++---------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift index 4ab3b303f..4172b33aa 100644 --- a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift @@ -11,6 +11,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var mainVC: MainViewController? var isLaunchedForSpecificAction = false + var tunnelsManager: TunnelsManager? + + static let tunnelsManagerReadyNotificationName: Notification.Name = Notification.Name(rawValue: "com.wireguard.ios.tunnelsManagerReadyNotification") + func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path) @@ -29,6 +33,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.mainVC = mainVC + // Create the tunnels manager, and when it's ready, inform tunnelsListVC + TunnelsManager.create { [weak self] result in + guard let self = self else { return } + + switch result { + case .failure(let error): + ErrorPresenter.showErrorAlert(error: error, from: self.mainVC) + case .success(let tunnelsManager): + self.tunnelsManager = tunnelsManager + self.mainVC?.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager) + + tunnelsManager.activationDelegate = self.mainVC + + NotificationCenter.default.post(name: AppDelegate.tunnelsManagerReadyNotificationName, + object: self, + userInfo: nil) + } + } + return true } diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift index b7805172e..6aab55908 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift @@ -5,7 +5,9 @@ import UIKit class MainViewController: UISplitViewController { - var tunnelsManager: TunnelsManager? + var tunnelsManager: TunnelsManager? { + return (UIApplication.shared.delegate as? AppDelegate)?.tunnelsManager + } var onTunnelsManagerReady: ((TunnelsManager) -> Void)? var tunnelsListVC: TunnelsListTableViewController? @@ -42,29 +44,24 @@ class MainViewController: UISplitViewController { // On iPad, always show both masterVC and detailVC, even in portrait mode, like the Settings app preferredDisplayMode = .allVisible - // Create the tunnels manager, and when it's ready, inform tunnelsListVC - TunnelsManager.create { [weak self] result in - guard let self = self else { return } - - switch result { - case .failure(let error): - ErrorPresenter.showErrorAlert(error: error, from: self) - case .success(let tunnelsManager): - self.tunnelsManager = tunnelsManager - self.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager) - - tunnelsManager.activationDelegate = self - - self.onTunnelsManagerReady?(tunnelsManager) - self.onTunnelsManagerReady = nil - } - } + NotificationCenter.default.addObserver(self, selector: #selector(handleTunnelsManagerReady(_:)), + name: AppDelegate.tunnelsManagerReadyNotificationName, object: nil) } func allTunnelNames() -> [String]? { guard let tunnelsManager = self.tunnelsManager else { return nil } return tunnelsManager.mapTunnels { $0.name } } + + @objc + func handleTunnelsManagerReady(_ notification: Notification) { + guard let tunnelsManager = self.tunnelsManager else { return } + + self.onTunnelsManagerReady?(tunnelsManager) + self.onTunnelsManagerReady = nil + + NotificationCenter.default.removeObserver(self, name: AppDelegate.tunnelsManagerReadyNotificationName, object: nil) + } } extension MainViewController: TunnelsManagerActivationDelegate { From fe3f2d089bec0346c5ab338905081de59e116697 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 1 Feb 2022 10:16:38 +0100 Subject: [PATCH 06/27] Implemented UpdateConfiguration intent Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 210 ++++++++++++++++++ Sources/WireGuardApp/UI/iOS/AppDelegate.swift | 90 ++++++++ Sources/WireGuardApp/UI/iOS/Info.plist | 4 + Sources/WireGuardIntentsExtension/Info.plist | 1 + .../IntentHandler.swift | 2 +- .../IntentHandling.swift | 52 +++++ 6 files changed, 358 insertions(+), 1 deletion(-) diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 38f8e5467..590fa39c0 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -150,6 +150,216 @@ INIntentVerb Do + + INIntentCategory + generic + INIntentConfigurable + + INIntentDescription + Update peers configuration. Configuration must be provided with the same format as the following example. The fields you can update are: "Endpoint". +The fields and the peers you omit will not be modified. + +Example +{ "Peer1 Public Key (Base64)": { "Endpoint": "1.2.3.4:4321" }, + "Peer2 Public Key (Base64)": {"Endpoint": "10.11.12.13:6789"} } + INIntentDescriptionID + uTimVO + INIntentIneligibleForSuggestions + + INIntentInput + configuration + INIntentLastParameterTag + 5 + INIntentManagedParameterCombinations + + tunnel,configuration,completionUrl + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Update ${tunnel} configuration + INIntentParameterCombinationTitleID + 2ASDIM + INIntentParameterCombinationUpdatesLinked + + + + INIntentName + UpdateConfiguration + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Tunnel + INIntentParameterDisplayNameID + TjOtzk + INIntentParameterDisplayPriority + 1 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Sentences + INIntentParameterMetadataDefaultValueID + h56bAD + + INIntentParameterName + tunnel + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterTag + 1 + INIntentParameterType + String + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Configuration + INIntentParameterDisplayNameID + 3SLMhb + INIntentParameterDisplayPriority + 2 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + None + INIntentParameterMetadataDefaultValue + {"Peer Public Key": {"Endpoint":"1.2.3.4:5678"} } + INIntentParameterMetadataDefaultValueID + 1J2FBa + INIntentParameterMetadataDisableAutocorrect + + INIntentParameterMetadataDisableSmartDashes + + INIntentParameterMetadataDisableSmartQuotes + + INIntentParameterMetadataMultiline + + + INIntentParameterName + configuration + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterTag + 2 + INIntentParameterType + String + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Open URL when done + INIntentParameterDisplayNameID + dwpgmC + INIntentParameterDisplayPriority + 3 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + None + INIntentParameterMetadataDefaultValue + shortcuts:// + INIntentParameterMetadataDefaultValueID + cyr6LU + INIntentParameterMetadataDisableAutocorrect + + INIntentParameterMetadataDisableSmartDashes + + INIntentParameterMetadataDisableSmartQuotes + + + INIntentParameterName + completionUrl + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterTag + 5 + INIntentParameterType + String + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + INIntentResponseCodeConciseFormatString + The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description. + INIntentResponseCodeConciseFormatStringID + xB99X4 + INIntentResponseCodeFormatString + The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description. + INIntentResponseCodeFormatStringID + UljpyD + INIntentResponseCodeName + wrongConfiguration + + + + INIntentTitle + Update Configuration + INIntentTitleID + iYtEWT + INIntentType + Custom + INIntentVerb + Do + INTypes diff --git a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift index 4172b33aa..45ffa2b25 100644 --- a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift @@ -3,6 +3,7 @@ import UIKit import os.log +import Intents @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -105,3 +106,92 @@ extension AppDelegate { return nil } } + +extension AppDelegate { + + func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + + guard let interaction = userActivity.interaction else { + return false + } + + if interaction.intent is UpdateConfigurationIntent { + if let tunnelsManager = tunnelsManager { + self.handleupdateConfigurationIntent(interaction: interaction, tunnelsManager: tunnelsManager) + } else { + var token: NSObjectProtocol? + token = NotificationCenter.default.addObserver(forName: AppDelegate.tunnelsManagerReadyNotificationName, object: nil, queue: .main) { [weak self] _ in + guard let tunnelsManager = self?.tunnelsManager else { return } + + self?.handleupdateConfigurationIntent(interaction: interaction, tunnelsManager: tunnelsManager) + NotificationCenter.default.removeObserver(token!) + } + } + + return true + } + + return false + } + + func handleupdateConfigurationIntent(interaction: INInteraction, tunnelsManager: TunnelsManager) { + + guard let updateConfigurationIntent = interaction.intent as? UpdateConfigurationIntent, + let configurationUpdates = interaction.intentResponse?.userActivity?.userInfo else { + return + } + + guard let tunnelName = updateConfigurationIntent.tunnel, + let configurations = configurationUpdates["Configuration"] as? [String: [String: String]] else { + wg_log(.error, message: "Failed to get informations to update the configuration") + return + } + + guard let tunnel = tunnelsManager.tunnel(named: tunnelName), + let tunnelConfiguration = tunnel.tunnelConfiguration else { + wg_log(.error, message: "Failed to get tunnel configuration with name \(tunnelName)") + ErrorPresenter.showErrorAlert(title: "Tunnel not found", + message: "Tunnel with name '\(tunnelName)' is not present.", + from: self.mainVC) + return + } + + var peers = tunnelConfiguration.peers + + for (peerPubKey, valuesToUpdate) in configurations { + guard let peerIndex = peers.firstIndex(where: { $0.publicKey.base64Key == peerPubKey }) else { + wg_log(.debug, message: "Failed to find peer \(peerPubKey) in tunnel with name \(tunnelName)") + ErrorPresenter.showErrorAlert(title: "Peer not found", + message: "Peer '\(peerPubKey)' is not present in '\(tunnelName)' tunnel.", + from: self.mainVC) + continue + } + + if let endpointString = valuesToUpdate["Endpoint"] { + if let newEntpoint = Endpoint(from: endpointString) { + peers[peerIndex].endpoint = newEntpoint + } else { + wg_log(.debug, message: "Failed to convert \(endpointString) to Endpoint") + } + } + } + + let newConfiguration = TunnelConfiguration(name: tunnel.name, interface: tunnelConfiguration.interface, peers: peers) + + tunnelsManager.modify(tunnel: tunnel, tunnelConfiguration: newConfiguration, onDemandOption: tunnel.onDemandOption) { error in + guard error == nil else { + wg_log(.error, message: error!.localizedDescription) + ErrorPresenter.showErrorAlert(error: error!, from: self.mainVC) + return + } + + if let completionUrlString = updateConfigurationIntent.completionUrl, + !completionUrlString.isEmpty, + let completionUrl = URL(string: completionUrlString) { + UIApplication.shared.open(completionUrl, options: [:], completionHandler: nil) + } + + wg_log(.debug, message: "Updated configuration of tunnel \(tunnelName)") + } + } +} diff --git a/Sources/WireGuardApp/UI/iOS/Info.plist b/Sources/WireGuardApp/UI/iOS/Info.plist index 754d12c7e..101d0a79e 100644 --- a/Sources/WireGuardApp/UI/iOS/Info.plist +++ b/Sources/WireGuardApp/UI/iOS/Info.plist @@ -82,6 +82,10 @@ Localized NSFaceIDUsageDescription Localized + NSUserActivityTypes + + UpdateConfigurationIntent + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist index 35910e1c6..06ec3ab2c 100644 --- a/Sources/WireGuardIntentsExtension/Info.plist +++ b/Sources/WireGuardIntentsExtension/Info.plist @@ -33,6 +33,7 @@ IntentsSupported GetPeersIntent + UpdateConfigurationIntent NSExtensionPointIdentifier diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index 4567b499c..62eb5e23f 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -11,7 +11,7 @@ class IntentHandler: INExtension { } override func handler(for intent: INIntent) -> Any { - guard intent is GetPeersIntent else { + guard intent is GetPeersIntent || intent is UpdateConfigurationIntent else { fatalError("Unhandled intent type: \(intent)") } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift index d94616032..1de3d46ad 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandling.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandling.swift @@ -118,3 +118,55 @@ extension IntentHandling: GetPeersIntentHandling { } } + +extension IntentHandling: UpdateConfigurationIntentHandling { + + @available(iOSApplicationExtension 14.0, *) + func provideTunnelOptionsCollection(for intent: UpdateConfigurationIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + self.allTunnelNames { tunnelsNames in + let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } + + let objectCollection = INObjectCollection(items: tunnelsNamesObjects) + completion(objectCollection, nil) + } + } + + func handle(intent: UpdateConfigurationIntent, completion: @escaping (UpdateConfigurationIntentResponse) -> Void) { + // Due to an Apple bug (https://developer.apple.com/forums/thread/96020) we can't update VPN + // configuration from extensions at the moment, so we should handle the action in the app. + // We check that the configuration update data is valid and then launch the main app. + + guard let tunnelName = intent.tunnel, + let configurationString = intent.configuration else { + wg_log(.error, message: "Failed to get informations to update the configuration") + completion(UpdateConfigurationIntentResponse(code: .failure, userActivity: nil)) + return + } + + var configurations: [String: [String: String]] + + let configurationsData = Data(configurationString.utf8) + do { + // Make sure this JSON is in the format we expect + if let decodedJson = try JSONSerialization.jsonObject(with: configurationsData, options: []) as? [String: [String: String]] { + configurations = decodedJson + } else { + throw IntentError.failedDecode + } + } catch _ { + wg_log(.error, message: "Failed to decode configuration data in JSON format for \(tunnelName)") + completion(UpdateConfigurationIntentResponse(code: .wrongConfiguration, userActivity: nil)) + return + } + + var activity: NSUserActivity? + if let bundleIdentifier = Bundle.main.bundleIdentifier { + activity = NSUserActivity(activityType: "\(bundleIdentifier).activity.update-tunnel-config") + activity?.userInfo = ["TunnelName": tunnelName, + "Configuration": configurations] + } + + completion(UpdateConfigurationIntentResponse(code: .continueInApp, userActivity: activity)) + } + +} From bb6ea1b2f314928fcd3ccbb74fcd47e7a71a34e9 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 1 Feb 2022 13:28:33 +0100 Subject: [PATCH 07/27] Implemented SetTunnelStatus intent Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 354 +++++++++++++++++- Sources/WireGuardIntentsExtension/Info.plist | 1 + .../IntentHandler.swift | 4 +- .../IntentHandling.swift | 130 +++++++ 4 files changed, 487 insertions(+), 2 deletions(-) diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 590fa39c0..6f2d38c0b 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -3,7 +3,94 @@ INEnums - + + + INEnumDisplayName + State + INEnumDisplayNameID + kiXIKs + INEnumGeneratesHeader + + INEnumName + State + INEnumType + State + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + 57IgER + INEnumValueName + unknown + + + INEnumValueDisplayName + on + INEnumValueDisplayNameID + tbFf8o + INEnumValueIndex + 1 + INEnumValueName + on + + + INEnumValueDisplayName + off + INEnumValueDisplayNameID + 7lY4Sc + INEnumValueIndex + 2 + INEnumValueName + off + + + + + INEnumDisplayName + Operation + INEnumDisplayNameID + urZ7WZ + INEnumGeneratesHeader + + INEnumName + Operation + INEnumType + Regular + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + efZxZH + INEnumValueName + unknown + + + INEnumValueDisplayName + Turn + INEnumValueDisplayNameID + viQ2K7 + INEnumValueIndex + 1 + INEnumValueName + turn + + + INEnumValueDisplayName + Toggle + INEnumValueDisplayNameID + N4IzMI + INEnumValueIndex + 2 + INEnumValueName + toggle + + + + INIntentDefinitionModelVersion 1.2 INIntentDefinitionNamespace @@ -360,6 +447,271 @@ Example INIntentVerb Do + + INIntentCategory + toggle + INIntentConfigurable + + INIntentDescription + Enables or disables a tunnel. + +The action will not return an error if there are problems during the activation, it just launches the procedure. + INIntentDescriptionID + T7NEBw + INIntentEligibleForWidgets + + INIntentLastParameterTag + 4 + INIntentManagedParameterCombinations + + state,tunnel,operation + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + ${operation} ${tunnel} tunnel ${state} + INIntentParameterCombinationTitleID + juDVvv + INIntentParameterCombinationUpdatesLinked + + + tunnel,operation + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + ${operation} ${tunnel} tunnel + INIntentParameterCombinationTitleID + kMEAI0 + + + INIntentName + SetTunnelStatus + INIntentParameterCombinations + + state,tunnel,operation + + INIntentParameterCombinationIsLinked + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + ${operation} ${tunnel} tunnel ${state} + INIntentParameterCombinationTitleID + SjQ7Ur + + + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Tunnel + INIntentParameterDisplayNameID + mbhQcc + INIntentParameterDisplayPriority + 1 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Sentences + INIntentParameterMetadataDefaultValueID + iBD5fT + + INIntentParameterName + tunnel + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${tunnel}’. + INIntentParameterPromptDialogFormatStringID + 73NvEc + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${tunnel}’? + INIntentParameterPromptDialogFormatStringID + 63TirR + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterTag + 2 + INIntentParameterType + String + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Operation + INIntentParameterDisplayNameID + U9YFTG + INIntentParameterDisplayPriority + 2 + INIntentParameterEnumType + Operation + INIntentParameterEnumTypeNamespace + 6NREiY + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + turn + + INIntentParameterName + operation + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${operation}’. + INIntentParameterPromptDialogFormatStringID + SALmBF + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${operation}’? + INIntentParameterPromptDialogFormatStringID + vB13mD + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterTag + 4 + INIntentParameterType + Integer + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + State + INIntentParameterDisplayNameID + sLIh6r + INIntentParameterDisplayPriority + 3 + INIntentParameterEnumType + State + INIntentParameterEnumTypeNamespace + 6NREiY + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + on + + INIntentParameterName + state + INIntentParameterRelationship + + INIntentParameterRelationshipParentName + operation + INIntentParameterRelationshipPredicateName + EnumHasExactValue + INIntentParameterRelationshipPredicateValue + turn + + INIntentParameterTag + 1 + INIntentParameterType + Integer + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + INIntentResponseLastParameterTag + 1 + INIntentResponseParameters + + + INIntentResponseParameterConfigurable + + INIntentResponseParameterCustomDisambiguation + + INIntentResponseParameterDisplayName + State + INIntentResponseParameterDisplayNameID + TXqy56 + INIntentResponseParameterDisplayPriority + 1 + INIntentResponseParameterEnumType + State + INIntentResponseParameterEnumTypeNamespace + 6NREiY + INIntentResponseParameterName + state + INIntentResponseParameterSupportsResolution + + INIntentResponseParameterTag + 1 + INIntentResponseParameterType + Integer + + + + INIntentTitle + Set Tunnel Status + INIntentTitleID + HULmDn + INIntentType + Custom + INIntentVerb + Toggle + INTypes diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist index 06ec3ab2c..fbe7d5600 100644 --- a/Sources/WireGuardIntentsExtension/Info.plist +++ b/Sources/WireGuardIntentsExtension/Info.plist @@ -33,6 +33,7 @@ IntentsSupported GetPeersIntent + SetTunnelStatusIntent UpdateConfigurationIntent diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index 62eb5e23f..6f1995144 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -11,7 +11,9 @@ class IntentHandler: INExtension { } override func handler(for intent: INIntent) -> Any { - guard intent is GetPeersIntent || intent is UpdateConfigurationIntent else { + guard intent is GetPeersIntent || + intent is UpdateConfigurationIntent || + intent is SetTunnelStatusIntent else { fatalError("Unhandled intent type: \(intent)") } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift index 1de3d46ad..78004e07a 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandling.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandling.swift @@ -15,6 +15,8 @@ class IntentHandling: NSObject { var onTunnelsManagerReady: ((TunnelsManager) -> Void)? + var onTunnelStatusActivationReturn: ((Bool) -> Void)? + override init() { super.init() @@ -27,6 +29,8 @@ class IntentHandling: NSObject { case .success(let tunnelsManager): self.tunnelsManager = tunnelsManager + self.tunnelsManager?.activationDelegate = self + self.onTunnelsManagerReady?(tunnelsManager) self.onTunnelsManagerReady = nil } @@ -170,3 +174,129 @@ extension IntentHandling: UpdateConfigurationIntentHandling { } } + +extension IntentHandling: SetTunnelStatusIntentHandling { + + @available(iOSApplicationExtension 14.0, *) + func provideTunnelOptionsCollection(for intent: SetTunnelStatusIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + + self.allTunnelNames { tunnelsNames in + let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } + + let objectCollection = INObjectCollection(items: tunnelsNamesObjects) + completion(objectCollection, nil) + } + } + + func handle(intent: SetTunnelStatusIntent, completion: @escaping (SetTunnelStatusIntentResponse) -> Void) { + guard let tunnelName = intent.tunnel else { + return completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + } + + let setTunnelStatusResultBlock: (Bool) -> Void = { result in + if result { + completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) + } else { + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + } + } + + let updateStatusBlock: (TunnelsManager) -> Void = { tunnelsManager in + guard let tunnel = tunnelsManager.tunnel(named: tunnelName) else { + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + return + } + + let operation = intent.operation + let isOn: Bool + + if operation == .toggle { + switch tunnel.status { + case .inactive: + isOn = true + case .active: + isOn = false + default: + wg_log(.error, message: "SetTunnelStatusIntent action cannot be executed due to the current state of \(tunnelName) tunnel: \(tunnel.status)") + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + return + } + + } else if operation == .turn { + if (tunnel.status == .inactive) || (tunnel.status == .active) { + isOn = (intent.state == .on) + + if (isOn && tunnel.status == .active) || (!isOn && tunnel.status == .inactive) { + wg_log(.debug, message: "Tunnel \(tunnelName) is already \(isOn ? "active" : "inactive")") + completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) + return + } + } else { + wg_log(.error, message: "SetTunnelStatusIntent action cannot be executed due to the current state of \(tunnelName) tunnel: \(tunnel.status)") + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + return + } + + } else { + wg_log(.error, message: "Invalid 'operation' option in action") + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + return + } + + if tunnel.hasOnDemandRules { + tunnelsManager.setOnDemandEnabled(isOn, on: tunnel) { error in + guard error == nil else { + wg_log(.error, message: "Error setting OnDemand status: \(error!.localizedDescription).") + completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) + return + } + + if !isOn { + tunnelsManager.startDeactivation(of: tunnel) + } + + completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) + } + } else { + if isOn { + self.onTunnelStatusActivationReturn = setTunnelStatusResultBlock + tunnelsManager.startActivation(of: tunnel) + } else { + tunnelsManager.startDeactivation(of: tunnel) + completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) + } + } + } + + if let tunnelsManager = tunnelsManager { + updateStatusBlock(tunnelsManager) + } else { + if onTunnelsManagerReady != nil { + wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelPeers function. This should not happen.") + } + onTunnelsManagerReady = updateStatusBlock + } + } + +} + +extension IntentHandling: TunnelsManagerActivationDelegate { + func tunnelActivationAttemptFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationAttemptError) { + wg_log(.error, message: "Tunnel Activation Attempt Failed with error: \(error.localizedDescription)") + self.onTunnelStatusActivationReturn?(false) + } + + func tunnelActivationAttemptSucceeded(tunnel: TunnelContainer) { + // Nothing to do, we wait tunnelActivationSucceeded to be sure all activation logic has been executed + } + + func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationError) { + wg_log(.error, message: "Tunnel Activation Failed with error: \(error.localizedDescription)") + self.onTunnelStatusActivationReturn?(false) + } + + func tunnelActivationSucceeded(tunnel: TunnelContainer) { + self.onTunnelStatusActivationReturn?(true) + } + +} From c29787f898da0c27a16b0e61149f34a8f031bffd Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 1 Feb 2022 17:51:18 +0100 Subject: [PATCH 08/27] WireguardApp: iOS: Added Siri shortcuts donations for SetTunnelStatus intent Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/Tunnel/TunnelsManager.swift | 10 ++++++++++ .../iOS/ViewController/MainViewController.swift | 16 ++++++++++++++++ .../TunnelDetailTableViewController.swift | 13 +++++++++++++ .../TunnelsListTableViewController.swift | 14 ++++++++++++++ 4 files changed, 53 insertions(+) diff --git a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift index 7751e5457..fbf29c4fe 100644 --- a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift +++ b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift @@ -5,6 +5,10 @@ import Foundation import NetworkExtension import os.log +#if os(iOS) +import Intents +#endif + protocol TunnelsManagerListDelegate: AnyObject { func tunnelAdded(at index: Int) func tunnelModified(at index: Int) @@ -307,6 +311,12 @@ class TunnelsManager { } #elseif os(iOS) (tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference() + + INInteraction.delete(with: "com.wireguard.intents.tunnel.\(tunnel.name)") { error in + if let error = error { + wg_log(.error, message: "Error deleting donated interactions for tunnel \(tunnel.name): \(error.localizedDescription)") + } + } #else #error("Unimplemented") #endif diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift index 6aab55908..74a8149fe 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift @@ -2,6 +2,7 @@ // Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. import UIKit +import Intents class MainViewController: UISplitViewController { @@ -96,10 +97,25 @@ extension MainViewController { if let tunnel = tunnelsManager.tunnel(named: tunnelName) { tunnelsListVC.showTunnelDetail(for: tunnel, animated: false) if shouldToggleStatus { + + let intent = SetTunnelStatusIntent() + intent.tunnel = tunnel.name + intent.operation = .turn + if tunnel.status == .inactive { tunnelsManager.startActivation(of: tunnel) + intent.state = .on } else if tunnel.status == .active { tunnelsManager.startDeactivation(of: tunnel) + intent.state = .off + } + + let interaction = INInteraction(intent: intent, response: nil) + interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(tunnel.name)" + interaction.donate { error in + if let error = error { + wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") + } } } } diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift index 196de0c69..0361d44b8 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift @@ -2,6 +2,7 @@ // Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. import UIKit +import Intents class TunnelDetailTableViewController: UITableViewController { @@ -387,6 +388,18 @@ extension TunnelDetailTableViewController { cell.onSwitchToggled = { [weak self] isOn in guard let self = self else { return } + let intent = SetTunnelStatusIntent() + intent.tunnel = self.tunnel.name + intent.operation = .turn + intent.state = isOn ? .on : .off + let interaction = INInteraction(intent: intent, response: nil) + interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(self.tunnel.name)" + interaction.donate { error in + if let error = error { + wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") + } + } + if self.tunnel.hasOnDemandRules { self.tunnelsManager.setOnDemandEnabled(isOn, on: self.tunnel) { error in if error == nil && !isOn { diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift index 85e64cea2..c5132a207 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift @@ -4,6 +4,7 @@ import UIKit import MobileCoreServices import UserNotifications +import Intents class TunnelsListTableViewController: UIViewController { @@ -317,6 +318,19 @@ extension TunnelsListTableViewController: UITableViewDataSource { cell.tunnel = tunnel cell.onSwitchToggled = { [weak self] isOn in guard let self = self, let tunnelsManager = self.tunnelsManager else { return } + + let intent = SetTunnelStatusIntent() + intent.tunnel = tunnel.name + intent.operation = .turn + intent.state = isOn ? .on : .off + let interaction = INInteraction(intent: intent, response: nil) + interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(tunnel.name)" + interaction.donate { error in + if let error = error { + wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") + } + } + if tunnel.hasOnDemandRules { tunnelsManager.setOnDemandEnabled(isOn, on: tunnel) { error in if error == nil && !isOn { From 63c09565f2956fa92c25240e885a0f04fcd711c6 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Sat, 1 Apr 2023 16:00:24 +0200 Subject: [PATCH 09/27] Removed SetTunnelStatus Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 271 +----------------- .../WireGuardApp/Tunnel/TunnelsManager.swift | 10 - .../ViewController/MainViewController.swift | 16 -- .../TunnelDetailTableViewController.swift | 12 - .../TunnelsListTableViewController.swift | 14 - .../IntentHandler.swift | 3 +- .../IntentHandling.swift | 130 --------- 7 files changed, 4 insertions(+), 452 deletions(-) diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 6f2d38c0b..74bbf1fc0 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -96,11 +96,11 @@ INIntentDefinitionNamespace 6NREiY INIntentDefinitionSystemVersion - 21C52 + 21G419 INIntentDefinitionToolsBuildVersion - 13C100 + 14C18 INIntentDefinitionToolsVersion - 13.2.1 + 14.2 INIntents @@ -447,271 +447,6 @@ Example INIntentVerb Do - - INIntentCategory - toggle - INIntentConfigurable - - INIntentDescription - Enables or disables a tunnel. - -The action will not return an error if there are problems during the activation, it just launches the procedure. - INIntentDescriptionID - T7NEBw - INIntentEligibleForWidgets - - INIntentLastParameterTag - 4 - INIntentManagedParameterCombinations - - state,tunnel,operation - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - ${operation} ${tunnel} tunnel ${state} - INIntentParameterCombinationTitleID - juDVvv - INIntentParameterCombinationUpdatesLinked - - - tunnel,operation - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - ${operation} ${tunnel} tunnel - INIntentParameterCombinationTitleID - kMEAI0 - - - INIntentName - SetTunnelStatus - INIntentParameterCombinations - - state,tunnel,operation - - INIntentParameterCombinationIsLinked - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - ${operation} ${tunnel} tunnel ${state} - INIntentParameterCombinationTitleID - SjQ7Ur - - - INIntentParameters - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Tunnel - INIntentParameterDisplayNameID - mbhQcc - INIntentParameterDisplayPriority - 1 - INIntentParameterMetadata - - INIntentParameterMetadataCapitalization - Sentences - INIntentParameterMetadataDefaultValueID - iBD5fT - - INIntentParameterName - tunnel - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - There are ${count} options matching ‘${tunnel}’. - INIntentParameterPromptDialogFormatStringID - 73NvEc - INIntentParameterPromptDialogType - DisambiguationIntroduction - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - Just to confirm, you wanted ‘${tunnel}’? - INIntentParameterPromptDialogFormatStringID - 63TirR - INIntentParameterPromptDialogType - Confirmation - - - INIntentParameterSupportsDynamicEnumeration - - INIntentParameterTag - 2 - INIntentParameterType - String - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Operation - INIntentParameterDisplayNameID - U9YFTG - INIntentParameterDisplayPriority - 2 - INIntentParameterEnumType - Operation - INIntentParameterEnumTypeNamespace - 6NREiY - INIntentParameterMetadata - - INIntentParameterMetadataDefaultValue - turn - - INIntentParameterName - operation - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - There are ${count} options matching ‘${operation}’. - INIntentParameterPromptDialogFormatStringID - SALmBF - INIntentParameterPromptDialogType - DisambiguationIntroduction - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - Just to confirm, you wanted ‘${operation}’? - INIntentParameterPromptDialogFormatStringID - vB13mD - INIntentParameterPromptDialogType - Confirmation - - - INIntentParameterTag - 4 - INIntentParameterType - Integer - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - State - INIntentParameterDisplayNameID - sLIh6r - INIntentParameterDisplayPriority - 3 - INIntentParameterEnumType - State - INIntentParameterEnumTypeNamespace - 6NREiY - INIntentParameterMetadata - - INIntentParameterMetadataDefaultValue - on - - INIntentParameterName - state - INIntentParameterRelationship - - INIntentParameterRelationshipParentName - operation - INIntentParameterRelationshipPredicateName - EnumHasExactValue - INIntentParameterRelationshipPredicateValue - turn - - INIntentParameterTag - 1 - INIntentParameterType - Integer - - - INIntentResponse - - INIntentResponseCodes - - - INIntentResponseCodeName - success - INIntentResponseCodeSuccess - - - - INIntentResponseCodeName - failure - - - INIntentResponseLastParameterTag - 1 - INIntentResponseParameters - - - INIntentResponseParameterConfigurable - - INIntentResponseParameterCustomDisambiguation - - INIntentResponseParameterDisplayName - State - INIntentResponseParameterDisplayNameID - TXqy56 - INIntentResponseParameterDisplayPriority - 1 - INIntentResponseParameterEnumType - State - INIntentResponseParameterEnumTypeNamespace - 6NREiY - INIntentResponseParameterName - state - INIntentResponseParameterSupportsResolution - - INIntentResponseParameterTag - 1 - INIntentResponseParameterType - Integer - - - - INIntentTitle - Set Tunnel Status - INIntentTitleID - HULmDn - INIntentType - Custom - INIntentVerb - Toggle - INTypes diff --git a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift index fbf29c4fe..7751e5457 100644 --- a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift +++ b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift @@ -5,10 +5,6 @@ import Foundation import NetworkExtension import os.log -#if os(iOS) -import Intents -#endif - protocol TunnelsManagerListDelegate: AnyObject { func tunnelAdded(at index: Int) func tunnelModified(at index: Int) @@ -311,12 +307,6 @@ class TunnelsManager { } #elseif os(iOS) (tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference() - - INInteraction.delete(with: "com.wireguard.intents.tunnel.\(tunnel.name)") { error in - if let error = error { - wg_log(.error, message: "Error deleting donated interactions for tunnel \(tunnel.name): \(error.localizedDescription)") - } - } #else #error("Unimplemented") #endif diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift index 74a8149fe..6aab55908 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/MainViewController.swift @@ -2,7 +2,6 @@ // Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. import UIKit -import Intents class MainViewController: UISplitViewController { @@ -97,25 +96,10 @@ extension MainViewController { if let tunnel = tunnelsManager.tunnel(named: tunnelName) { tunnelsListVC.showTunnelDetail(for: tunnel, animated: false) if shouldToggleStatus { - - let intent = SetTunnelStatusIntent() - intent.tunnel = tunnel.name - intent.operation = .turn - if tunnel.status == .inactive { tunnelsManager.startActivation(of: tunnel) - intent.state = .on } else if tunnel.status == .active { tunnelsManager.startDeactivation(of: tunnel) - intent.state = .off - } - - let interaction = INInteraction(intent: intent, response: nil) - interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(tunnel.name)" - interaction.donate { error in - if let error = error { - wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") - } } } } diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift index 0361d44b8..2c185d94c 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift @@ -388,18 +388,6 @@ extension TunnelDetailTableViewController { cell.onSwitchToggled = { [weak self] isOn in guard let self = self else { return } - let intent = SetTunnelStatusIntent() - intent.tunnel = self.tunnel.name - intent.operation = .turn - intent.state = isOn ? .on : .off - let interaction = INInteraction(intent: intent, response: nil) - interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(self.tunnel.name)" - interaction.donate { error in - if let error = error { - wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") - } - } - if self.tunnel.hasOnDemandRules { self.tunnelsManager.setOnDemandEnabled(isOn, on: self.tunnel) { error in if error == nil && !isOn { diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift index c5132a207..85e64cea2 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelsListTableViewController.swift @@ -4,7 +4,6 @@ import UIKit import MobileCoreServices import UserNotifications -import Intents class TunnelsListTableViewController: UIViewController { @@ -318,19 +317,6 @@ extension TunnelsListTableViewController: UITableViewDataSource { cell.tunnel = tunnel cell.onSwitchToggled = { [weak self] isOn in guard let self = self, let tunnelsManager = self.tunnelsManager else { return } - - let intent = SetTunnelStatusIntent() - intent.tunnel = tunnel.name - intent.operation = .turn - intent.state = isOn ? .on : .off - let interaction = INInteraction(intent: intent, response: nil) - interaction.groupIdentifier = "com.wireguard.intents.tunnel.\(tunnel.name)" - interaction.donate { error in - if let error = error { - wg_log(.error, message: "Error donating interaction for SetTunnelStatusIntent: \(error.localizedDescription)") - } - } - if tunnel.hasOnDemandRules { tunnelsManager.setOnDemandEnabled(isOn, on: tunnel) { error in if error == nil && !isOn { diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index 6f1995144..a3527ef93 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -12,8 +12,7 @@ class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any { guard intent is GetPeersIntent || - intent is UpdateConfigurationIntent || - intent is SetTunnelStatusIntent else { + intent is UpdateConfigurationIntent else { fatalError("Unhandled intent type: \(intent)") } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift index 78004e07a..1de3d46ad 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandling.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandling.swift @@ -15,8 +15,6 @@ class IntentHandling: NSObject { var onTunnelsManagerReady: ((TunnelsManager) -> Void)? - var onTunnelStatusActivationReturn: ((Bool) -> Void)? - override init() { super.init() @@ -29,8 +27,6 @@ class IntentHandling: NSObject { case .success(let tunnelsManager): self.tunnelsManager = tunnelsManager - self.tunnelsManager?.activationDelegate = self - self.onTunnelsManagerReady?(tunnelsManager) self.onTunnelsManagerReady = nil } @@ -174,129 +170,3 @@ extension IntentHandling: UpdateConfigurationIntentHandling { } } - -extension IntentHandling: SetTunnelStatusIntentHandling { - - @available(iOSApplicationExtension 14.0, *) - func provideTunnelOptionsCollection(for intent: SetTunnelStatusIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { - - self.allTunnelNames { tunnelsNames in - let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } - - let objectCollection = INObjectCollection(items: tunnelsNamesObjects) - completion(objectCollection, nil) - } - } - - func handle(intent: SetTunnelStatusIntent, completion: @escaping (SetTunnelStatusIntentResponse) -> Void) { - guard let tunnelName = intent.tunnel else { - return completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - } - - let setTunnelStatusResultBlock: (Bool) -> Void = { result in - if result { - completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) - } else { - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - } - } - - let updateStatusBlock: (TunnelsManager) -> Void = { tunnelsManager in - guard let tunnel = tunnelsManager.tunnel(named: tunnelName) else { - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - return - } - - let operation = intent.operation - let isOn: Bool - - if operation == .toggle { - switch tunnel.status { - case .inactive: - isOn = true - case .active: - isOn = false - default: - wg_log(.error, message: "SetTunnelStatusIntent action cannot be executed due to the current state of \(tunnelName) tunnel: \(tunnel.status)") - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - return - } - - } else if operation == .turn { - if (tunnel.status == .inactive) || (tunnel.status == .active) { - isOn = (intent.state == .on) - - if (isOn && tunnel.status == .active) || (!isOn && tunnel.status == .inactive) { - wg_log(.debug, message: "Tunnel \(tunnelName) is already \(isOn ? "active" : "inactive")") - completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) - return - } - } else { - wg_log(.error, message: "SetTunnelStatusIntent action cannot be executed due to the current state of \(tunnelName) tunnel: \(tunnel.status)") - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - return - } - - } else { - wg_log(.error, message: "Invalid 'operation' option in action") - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - return - } - - if tunnel.hasOnDemandRules { - tunnelsManager.setOnDemandEnabled(isOn, on: tunnel) { error in - guard error == nil else { - wg_log(.error, message: "Error setting OnDemand status: \(error!.localizedDescription).") - completion(SetTunnelStatusIntentResponse(code: .failure, userActivity: nil)) - return - } - - if !isOn { - tunnelsManager.startDeactivation(of: tunnel) - } - - completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) - } - } else { - if isOn { - self.onTunnelStatusActivationReturn = setTunnelStatusResultBlock - tunnelsManager.startActivation(of: tunnel) - } else { - tunnelsManager.startDeactivation(of: tunnel) - completion(SetTunnelStatusIntentResponse(code: .success, userActivity: nil)) - } - } - } - - if let tunnelsManager = tunnelsManager { - updateStatusBlock(tunnelsManager) - } else { - if onTunnelsManagerReady != nil { - wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelPeers function. This should not happen.") - } - onTunnelsManagerReady = updateStatusBlock - } - } - -} - -extension IntentHandling: TunnelsManagerActivationDelegate { - func tunnelActivationAttemptFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationAttemptError) { - wg_log(.error, message: "Tunnel Activation Attempt Failed with error: \(error.localizedDescription)") - self.onTunnelStatusActivationReturn?(false) - } - - func tunnelActivationAttemptSucceeded(tunnel: TunnelContainer) { - // Nothing to do, we wait tunnelActivationSucceeded to be sure all activation logic has been executed - } - - func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationError) { - wg_log(.error, message: "Tunnel Activation Failed with error: \(error.localizedDescription)") - self.onTunnelStatusActivationReturn?(false) - } - - func tunnelActivationSucceeded(tunnel: TunnelContainer) { - self.onTunnelStatusActivationReturn?(true) - } - -} From 7ec6974005d2451fc20672e0789e0c0ecd43743f Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Sat, 1 Apr 2023 16:12:32 +0200 Subject: [PATCH 10/27] Complete cleanup after SetTunnelStatus Intent removal Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 89 +------------------ .../TunnelDetailTableViewController.swift | 1 - Sources/WireGuardIntentsExtension/Info.plist | 1 - 3 files changed, 1 insertion(+), 90 deletions(-) diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 74bbf1fc0..8c8d33b63 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -3,94 +3,7 @@ INEnums - - - INEnumDisplayName - State - INEnumDisplayNameID - kiXIKs - INEnumGeneratesHeader - - INEnumName - State - INEnumType - State - INEnumValues - - - INEnumValueDisplayName - unknown - INEnumValueDisplayNameID - 57IgER - INEnumValueName - unknown - - - INEnumValueDisplayName - on - INEnumValueDisplayNameID - tbFf8o - INEnumValueIndex - 1 - INEnumValueName - on - - - INEnumValueDisplayName - off - INEnumValueDisplayNameID - 7lY4Sc - INEnumValueIndex - 2 - INEnumValueName - off - - - - - INEnumDisplayName - Operation - INEnumDisplayNameID - urZ7WZ - INEnumGeneratesHeader - - INEnumName - Operation - INEnumType - Regular - INEnumValues - - - INEnumValueDisplayName - unknown - INEnumValueDisplayNameID - efZxZH - INEnumValueName - unknown - - - INEnumValueDisplayName - Turn - INEnumValueDisplayNameID - viQ2K7 - INEnumValueIndex - 1 - INEnumValueName - turn - - - INEnumValueDisplayName - Toggle - INEnumValueDisplayNameID - N4IzMI - INEnumValueIndex - 2 - INEnumValueName - toggle - - - - + INIntentDefinitionModelVersion 1.2 INIntentDefinitionNamespace diff --git a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift index 2c185d94c..196de0c69 100644 --- a/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift +++ b/Sources/WireGuardApp/UI/iOS/ViewController/TunnelDetailTableViewController.swift @@ -2,7 +2,6 @@ // Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. import UIKit -import Intents class TunnelDetailTableViewController: UITableViewController { diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist index fbe7d5600..06ec3ab2c 100644 --- a/Sources/WireGuardIntentsExtension/Info.plist +++ b/Sources/WireGuardIntentsExtension/Info.plist @@ -33,7 +33,6 @@ IntentsSupported GetPeersIntent - SetTunnelStatusIntent UpdateConfigurationIntent From 29522061388daa4742985e91495ce555c01598aa Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 5 Apr 2023 13:30:40 +0200 Subject: [PATCH 11/27] Remove GetPeers SiriKit Intent Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 134 ------------------ .../IntentHandler.swift | 3 +- .../IntentHandling.swift | 60 -------- 3 files changed, 1 insertion(+), 196 deletions(-) diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 8c8d33b63..97b2595ec 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -16,140 +16,6 @@ 14.2 INIntents - - INIntentCategory - generic - INIntentConfigurable - - INIntentDescription - Get list of public keys of peers in the selected configuration - INIntentDescriptionID - e4jxYU - INIntentIneligibleForSuggestions - - INIntentKeyParameter - tunnel - INIntentLastParameterTag - 1 - INIntentManagedParameterCombinations - - tunnel - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - Get peers of ${tunnel} - INIntentParameterCombinationTitleID - 5Ewt1o - INIntentParameterCombinationUpdatesLinked - - - - INIntentName - GetPeers - INIntentParameters - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Tunnel - INIntentParameterDisplayNameID - tUPuxx - INIntentParameterDisplayPriority - 1 - INIntentParameterMetadata - - INIntentParameterMetadataCapitalization - Sentences - INIntentParameterMetadataDefaultValueID - 0AfeHS - - INIntentParameterName - tunnel - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterSupportsDynamicEnumeration - - INIntentParameterTag - 1 - INIntentParameterType - String - - - INIntentResponse - - INIntentResponseCodes - - - INIntentResponseCodeName - success - INIntentResponseCodeSuccess - - - - INIntentResponseCodeName - failure - - - INIntentResponseCodeConciseFormatString - Failed to retrive configuration with the provided name. - INIntentResponseCodeConciseFormatStringID - ExhkKO - INIntentResponseCodeFormatString - Failed to retrive configuration with the provided name. - INIntentResponseCodeFormatStringID - lxnQb0 - INIntentResponseCodeName - wrongTunnel - - - INIntentResponseLastParameterTag - 2 - INIntentResponseOutput - peersPublicKeys - INIntentResponseParameters - - - INIntentResponseParameterDisplayName - Peers Public Keys - INIntentResponseParameterDisplayNameID - zJOQgA - INIntentResponseParameterDisplayPriority - 1 - INIntentResponseParameterName - peersPublicKeys - INIntentResponseParameterSupportsMultipleValues - - INIntentResponseParameterTag - 2 - INIntentResponseParameterType - String - - - - INIntentTitle - Get Peers - INIntentTitleID - V1ySW4 - INIntentType - Custom - INIntentVerb - Do - INIntentCategory generic diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index a3527ef93..bc85e2adb 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -11,8 +11,7 @@ class IntentHandler: INExtension { } override func handler(for intent: INIntent) -> Any { - guard intent is GetPeersIntent || - intent is UpdateConfigurationIntent else { + guard intent is UpdateConfigurationIntent else { fatalError("Unhandled intent type: \(intent)") } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift index 1de3d46ad..461c5aa16 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandling.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandling.swift @@ -57,66 +57,6 @@ extension IntentHandling { onTunnelsManagerReady = getTunnelsNameBlock } } - - private func allTunnelPeers(for tunnelName: String, completion: @escaping (Result<[String], IntentError>) -> Void) { - let getPeersFromConfigBlock: (TunnelsManager) -> Void = { tunnelsManager in - guard let tunnel = tunnelsManager.tunnel(named: tunnelName) else { - return completion(.failure(.wrongTunnel)) - } - - guard let publicKeys = tunnel.tunnelConfiguration?.peers.map({ $0.publicKey.base64Key }) else { - return completion(.failure(.unknown)) - } - return completion(.success(publicKeys)) - } - - if let tunnelsManager = tunnelsManager { - getPeersFromConfigBlock(tunnelsManager) - } else { - if onTunnelsManagerReady != nil { - wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelPeers function. This should not happen.") - } - onTunnelsManagerReady = getPeersFromConfigBlock - } - } -} - -extension IntentHandling: GetPeersIntentHandling { - - @available(iOSApplicationExtension 14.0, *) - func provideTunnelOptionsCollection(for intent: GetPeersIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { - - self.allTunnelNames { tunnelsNames in - let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } - - let objectCollection = INObjectCollection(items: tunnelsNamesObjects) - completion(objectCollection, nil) - } - } - - func handle(intent: GetPeersIntent, completion: @escaping (GetPeersIntentResponse) -> Void) { - guard let tunnel = intent.tunnel else { - return completion(GetPeersIntentResponse(code: .failure, userActivity: nil)) - } - - self.allTunnelPeers(for: tunnel) { peersResult in - switch peersResult { - case .success(let peers): - let response = GetPeersIntentResponse(code: .success, userActivity: nil) - response.peersPublicKeys = peers - completion(response) - - case .failure(let error): - switch error { - case .wrongTunnel: - completion(GetPeersIntentResponse(code: .wrongTunnel, userActivity: nil)) - default: - completion(GetPeersIntentResponse(code: .failure, userActivity: nil)) - } - } - } - } - } extension IntentHandling: UpdateConfigurationIntentHandling { From bee5d346b1d1c17ac0363d5949c0a039d62ce000 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 17:29:52 +0200 Subject: [PATCH 12/27] Implement GetPeers AppIntent Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/UI/iOS/AppDelegate.swift | 5 ++ .../WireguardAppIntents/AppIntents.strings | 12 ++++ Sources/WireguardAppIntents/GetPeers.swift | 55 +++++++++++++++++++ .../TunnelsOptionsProvider.swift | 15 +++++ WireGuard.xcodeproj/project.pbxproj | 21 +++++++ 5 files changed, 108 insertions(+) create mode 100644 Sources/WireguardAppIntents/AppIntents.strings create mode 100644 Sources/WireguardAppIntents/GetPeers.swift create mode 100644 Sources/WireguardAppIntents/TunnelsOptionsProvider.swift diff --git a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift index 45ffa2b25..d8629c4d1 100644 --- a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift @@ -4,6 +4,7 @@ import UIKit import os.log import Intents +import AppIntents @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -47,6 +48,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { tunnelsManager.activationDelegate = self.mainVC + if #available(iOS 16.0, *) { + AppDependencyManager.shared.add(dependency: tunnelsManager) + } + NotificationCenter.default.post(name: AppDelegate.tunnelsManagerReadyNotificationName, object: self, userInfo: nil) diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings new file mode 100644 index 000000000..e53949965 --- /dev/null +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +// App Intents Common +"wireguardAppIntentsWrongTunnelError %@" = "Cannot find a tunnel with the name \"%1$@\""; +"wireguardAppIntentsMissingConfigurationError" = "The selected tunnel has no configuration."; + +// Get peers Intent +"getPeersIntentName" = "Get Peers"; +"getPeersIntentDescription" = "Get list of public keys of peers in the selected configuration"; +"getPeersIntentTunnelParameterTitle" = "Tunnel"; +"getPeersIntentSummary ${tunnelName}" = "Get peers of ${tunnelName}"; diff --git a/Sources/WireguardAppIntents/GetPeers.swift b/Sources/WireguardAppIntents/GetPeers.swift new file mode 100644 index 000000000..ce6849e3f --- /dev/null +++ b/Sources/WireguardAppIntents/GetPeers.swift @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import Foundation +import AppIntents + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct GetPeers: AppIntent { + + static var title = LocalizedStringResource("getPeersIntentName", table: "AppIntents") + static var description = IntentDescription( + LocalizedStringResource("getPeersIntentDescription", table: "AppIntents") + ) + + @Parameter( + title: LocalizedStringResource("getPeersIntentTunnelParameterTitle", table: "AppIntents"), + optionsProvider: TunnelsOptionsProvider() + ) + var tunnelName: String + + @Dependency + var tunnelsManager: TunnelsManager + + func perform() async throws -> some ReturnsValue { + guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { + throw GetPeersIntentError.wrongTunnel(name: tunnelName) + } + + guard let tunnelConfiguration = tunnelContainer.tunnelConfiguration else { + throw GetPeersIntentError.missingConfiguration + } + + let publicKeys = tunnelConfiguration.peers.map { $0.publicKey.base64Key } + return .result(value: publicKeys) + } + + static var parameterSummary: some ParameterSummary { + Summary("getPeersIntentSummary \(\.$tunnelName)", table: "AppIntents") + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +enum GetPeersIntentError: Swift.Error, CustomLocalizedStringResourceConvertible { + case wrongTunnel(name: String) + case missingConfiguration + + var localizedStringResource: LocalizedStringResource { + switch self { + case .wrongTunnel(let name): + return LocalizedStringResource("wireguardAppIntentsWrongTunnelError \(name)", table: "AppIntents") + case .missingConfiguration: + return LocalizedStringResource("wireguardAppIntentsMissingConfigurationError", table: "AppIntents") + } + } +} diff --git a/Sources/WireguardAppIntents/TunnelsOptionsProvider.swift b/Sources/WireguardAppIntents/TunnelsOptionsProvider.swift new file mode 100644 index 000000000..a21109c5d --- /dev/null +++ b/Sources/WireguardAppIntents/TunnelsOptionsProvider.swift @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import AppIntents + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct TunnelsOptionsProvider: DynamicOptionsProvider { + @Dependency + var tunnelsManager: TunnelsManager + + func results() async throws -> [String] { + let tunnelsNames = tunnelsManager.mapTunnels { $0.name } + return tunnelsNames + } +} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 53db590f8..e7ad37b66 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,6 +205,7 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; + A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A64A79DC27A5411700F15B34 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526E21C23FA10008484E /* Logger.swift */; }; A64A79DD27A5411E00F15B34 /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; }; A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; }; @@ -239,6 +240,8 @@ A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8051E27A44F770088E750 /* IntentHandler.swift */; }; A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; + A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -480,6 +483,7 @@ 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = ""; }; 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandOption.swift; sourceTree = ""; }; 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; + A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; A64A79D727A462FC00F15B34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardIntentsExtension-Bridging-Header.h"; sourceTree = ""; }; A64A79F827A5462900F15B34 /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = ""; }; @@ -488,6 +492,8 @@ A6B8051B27A44F770088E750 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; A6B8051E27A44F770088E750 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardIntentsExtension_iOS.entitlements; sourceTree = ""; }; + A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; + A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -820,6 +826,7 @@ 6FF4AC0B211EC46F002C96EB = { isa = PBXGroup; children = ( + A625F04C29C4C627005EF23D /* WireguardAppIntents */, 6F70E20C221058DF008BDFB4 /* InfoPlist.strings */, 6FE1765421C90BBE002690EA /* Localizable.strings */, 6F5D0C432183B4A4000F85AD /* Shared */, @@ -874,6 +881,17 @@ name = Frameworks; sourceTree = ""; }; + A625F04C29C4C627005EF23D /* WireguardAppIntents */ = { + isa = PBXGroup; + children = ( + A625F05029C4C627005EF23D /* GetPeers.swift */, + A6E361F729D8758500FFF234 /* AppIntents.strings */, + A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */, + ); + name = WireguardAppIntents; + path = Sources/WireguardAppIntents; + sourceTree = ""; + }; A6B8051D27A44F770088E750 /* WireGuardIntentsExtension */ = { isa = PBXGroup; children = ( @@ -1193,6 +1211,7 @@ 6FE1765621C90BBE002690EA /* Localizable.strings in Resources */, 6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */, 6F919EDA218C65C50023B400 /* wireguard_doc_logo_44x58.png in Resources */, + A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */, 6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */, 6F919EDB218C65C50023B400 /* wireguard_doc_logo_64x64.png in Resources */, 6F919EDC218C65C50023B400 /* wireguard_doc_logo_320x320.png in Resources */, @@ -1524,8 +1543,10 @@ 6FDB6D18224CC05A00EE4BC3 /* LogViewController.swift in Sources */, 6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */, 5F4541A921C451D100994C13 /* TunnelStatus.swift in Sources */, + A625F05529C4C627005EF23D /* GetPeers.swift in Sources */, 6F8F0D7422267AD2000E8335 /* ChevronCell.swift in Sources */, 6F61F1E921B932F700483816 /* WireGuardAppError.swift in Sources */, + A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */, 6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */, 6FDEF80021863C0100D8FBF6 /* ioapi.c in Sources */, 6F7F7E5F21C7D74B00527607 /* TunnelErrors.swift in Sources */, From d05a1693e257b18f02ffb302ef478e999b0ef992 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 5 Apr 2023 15:40:51 +0200 Subject: [PATCH 13/27] Removed UpdateConfigurationIntent SiriKit Intent Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 213 +----------------- Sources/WireGuardApp/UI/iOS/AppDelegate.swift | 82 ------- Sources/WireGuardApp/UI/iOS/Info.plist | 4 +- .../IntentHandler.swift | 6 +- .../IntentHandling.swift | 112 --------- WireGuard.xcodeproj/project.pbxproj | 4 - 6 files changed, 3 insertions(+), 418 deletions(-) delete mode 100644 Sources/WireGuardIntentsExtension/IntentHandling.swift diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition index 97b2595ec..fd9a8dc85 100644 --- a/Sources/Shared/Intents.intentdefinition +++ b/Sources/Shared/Intents.intentdefinition @@ -15,218 +15,7 @@ INIntentDefinitionToolsVersion 14.2 INIntents - - - INIntentCategory - generic - INIntentConfigurable - - INIntentDescription - Update peers configuration. Configuration must be provided with the same format as the following example. The fields you can update are: "Endpoint". -The fields and the peers you omit will not be modified. - -Example -{ "Peer1 Public Key (Base64)": { "Endpoint": "1.2.3.4:4321" }, - "Peer2 Public Key (Base64)": {"Endpoint": "10.11.12.13:6789"} } - INIntentDescriptionID - uTimVO - INIntentIneligibleForSuggestions - - INIntentInput - configuration - INIntentLastParameterTag - 5 - INIntentManagedParameterCombinations - - tunnel,configuration,completionUrl - - INIntentParameterCombinationSupportsBackgroundExecution - - INIntentParameterCombinationTitle - Update ${tunnel} configuration - INIntentParameterCombinationTitleID - 2ASDIM - INIntentParameterCombinationUpdatesLinked - - - - INIntentName - UpdateConfiguration - INIntentParameters - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Tunnel - INIntentParameterDisplayNameID - TjOtzk - INIntentParameterDisplayPriority - 1 - INIntentParameterMetadata - - INIntentParameterMetadataCapitalization - Sentences - INIntentParameterMetadataDefaultValueID - h56bAD - - INIntentParameterName - tunnel - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterSupportsDynamicEnumeration - - INIntentParameterTag - 1 - INIntentParameterType - String - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Configuration - INIntentParameterDisplayNameID - 3SLMhb - INIntentParameterDisplayPriority - 2 - INIntentParameterMetadata - - INIntentParameterMetadataCapitalization - None - INIntentParameterMetadataDefaultValue - {"Peer Public Key": {"Endpoint":"1.2.3.4:5678"} } - INIntentParameterMetadataDefaultValueID - 1J2FBa - INIntentParameterMetadataDisableAutocorrect - - INIntentParameterMetadataDisableSmartDashes - - INIntentParameterMetadataDisableSmartQuotes - - INIntentParameterMetadataMultiline - - - INIntentParameterName - configuration - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterTag - 2 - INIntentParameterType - String - - - INIntentParameterConfigurable - - INIntentParameterDisplayName - Open URL when done - INIntentParameterDisplayNameID - dwpgmC - INIntentParameterDisplayPriority - 3 - INIntentParameterMetadata - - INIntentParameterMetadataCapitalization - None - INIntentParameterMetadataDefaultValue - shortcuts:// - INIntentParameterMetadataDefaultValueID - cyr6LU - INIntentParameterMetadataDisableAutocorrect - - INIntentParameterMetadataDisableSmartDashes - - INIntentParameterMetadataDisableSmartQuotes - - - INIntentParameterName - completionUrl - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterTag - 5 - INIntentParameterType - String - - - INIntentResponse - - INIntentResponseCodes - - - INIntentResponseCodeName - success - INIntentResponseCodeSuccess - - - - INIntentResponseCodeName - failure - - - INIntentResponseCodeConciseFormatString - The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description. - INIntentResponseCodeConciseFormatStringID - xB99X4 - INIntentResponseCodeFormatString - The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description. - INIntentResponseCodeFormatStringID - UljpyD - INIntentResponseCodeName - wrongConfiguration - - - - INIntentTitle - Update Configuration - INIntentTitleID - iYtEWT - INIntentType - Custom - INIntentVerb - Do - - + INTypes diff --git a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift index d8629c4d1..e05a31963 100644 --- a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift @@ -115,88 +115,6 @@ extension AppDelegate { extension AppDelegate { func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { - - guard let interaction = userActivity.interaction else { - return false - } - - if interaction.intent is UpdateConfigurationIntent { - if let tunnelsManager = tunnelsManager { - self.handleupdateConfigurationIntent(interaction: interaction, tunnelsManager: tunnelsManager) - } else { - var token: NSObjectProtocol? - token = NotificationCenter.default.addObserver(forName: AppDelegate.tunnelsManagerReadyNotificationName, object: nil, queue: .main) { [weak self] _ in - guard let tunnelsManager = self?.tunnelsManager else { return } - - self?.handleupdateConfigurationIntent(interaction: interaction, tunnelsManager: tunnelsManager) - NotificationCenter.default.removeObserver(token!) - } - } - - return true - } - return false } - - func handleupdateConfigurationIntent(interaction: INInteraction, tunnelsManager: TunnelsManager) { - - guard let updateConfigurationIntent = interaction.intent as? UpdateConfigurationIntent, - let configurationUpdates = interaction.intentResponse?.userActivity?.userInfo else { - return - } - - guard let tunnelName = updateConfigurationIntent.tunnel, - let configurations = configurationUpdates["Configuration"] as? [String: [String: String]] else { - wg_log(.error, message: "Failed to get informations to update the configuration") - return - } - - guard let tunnel = tunnelsManager.tunnel(named: tunnelName), - let tunnelConfiguration = tunnel.tunnelConfiguration else { - wg_log(.error, message: "Failed to get tunnel configuration with name \(tunnelName)") - ErrorPresenter.showErrorAlert(title: "Tunnel not found", - message: "Tunnel with name '\(tunnelName)' is not present.", - from: self.mainVC) - return - } - - var peers = tunnelConfiguration.peers - - for (peerPubKey, valuesToUpdate) in configurations { - guard let peerIndex = peers.firstIndex(where: { $0.publicKey.base64Key == peerPubKey }) else { - wg_log(.debug, message: "Failed to find peer \(peerPubKey) in tunnel with name \(tunnelName)") - ErrorPresenter.showErrorAlert(title: "Peer not found", - message: "Peer '\(peerPubKey)' is not present in '\(tunnelName)' tunnel.", - from: self.mainVC) - continue - } - - if let endpointString = valuesToUpdate["Endpoint"] { - if let newEntpoint = Endpoint(from: endpointString) { - peers[peerIndex].endpoint = newEntpoint - } else { - wg_log(.debug, message: "Failed to convert \(endpointString) to Endpoint") - } - } - } - - let newConfiguration = TunnelConfiguration(name: tunnel.name, interface: tunnelConfiguration.interface, peers: peers) - - tunnelsManager.modify(tunnel: tunnel, tunnelConfiguration: newConfiguration, onDemandOption: tunnel.onDemandOption) { error in - guard error == nil else { - wg_log(.error, message: error!.localizedDescription) - ErrorPresenter.showErrorAlert(error: error!, from: self.mainVC) - return - } - - if let completionUrlString = updateConfigurationIntent.completionUrl, - !completionUrlString.isEmpty, - let completionUrl = URL(string: completionUrlString) { - UIApplication.shared.open(completionUrl, options: [:], completionHandler: nil) - } - - wg_log(.debug, message: "Updated configuration of tunnel \(tunnelName)") - } - } } diff --git a/Sources/WireGuardApp/UI/iOS/Info.plist b/Sources/WireGuardApp/UI/iOS/Info.plist index 101d0a79e..bfe758dbc 100644 --- a/Sources/WireGuardApp/UI/iOS/Info.plist +++ b/Sources/WireGuardApp/UI/iOS/Info.plist @@ -83,9 +83,7 @@ NSFaceIDUsageDescription Localized NSUserActivityTypes - - UpdateConfigurationIntent - + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift index bc85e2adb..dddb61bd0 100644 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ b/Sources/WireGuardIntentsExtension/IntentHandler.swift @@ -11,11 +11,7 @@ class IntentHandler: INExtension { } override func handler(for intent: INIntent) -> Any { - guard intent is UpdateConfigurationIntent else { - fatalError("Unhandled intent type: \(intent)") - } - - return IntentHandling() + fatalError("Unhandled intent type: \(intent)") } } diff --git a/Sources/WireGuardIntentsExtension/IntentHandling.swift b/Sources/WireGuardIntentsExtension/IntentHandling.swift deleted file mode 100644 index 461c5aa16..000000000 --- a/Sources/WireGuardIntentsExtension/IntentHandling.swift +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. - -import Intents - -class IntentHandling: NSObject { - - public enum IntentError: Error { - case failedDecode - case wrongTunnel - case unknown - } - - var tunnelsManager: TunnelsManager? - - var onTunnelsManagerReady: ((TunnelsManager) -> Void)? - - override init() { - super.init() - - TunnelsManager.create { [weak self] result in - guard let self = self else { return } - - switch result { - case .failure(let error): - wg_log(.error, message: error.localizedDescription) - case .success(let tunnelsManager): - self.tunnelsManager = tunnelsManager - - self.onTunnelsManagerReady?(tunnelsManager) - self.onTunnelsManagerReady = nil - } - } - } - - init(tunnelsManager: TunnelsManager) { - super.init() - - self.tunnelsManager = tunnelsManager - } -} - -extension IntentHandling { - - private func allTunnelNames(completion: @escaping ([String]?) -> Void) { - let getTunnelsNameBlock: (TunnelsManager) -> Void = { tunnelsManager in - let tunnelsNames = tunnelsManager.mapTunnels { $0.name } - return completion(tunnelsNames) - } - - if let tunnelsManager = tunnelsManager { - getTunnelsNameBlock(tunnelsManager) - } else { - if onTunnelsManagerReady != nil { - wg_log(.error, message: "Overriding onTunnelsManagerReady action in allTunnelNames function. This should not happen.") - } - onTunnelsManagerReady = getTunnelsNameBlock - } - } -} - -extension IntentHandling: UpdateConfigurationIntentHandling { - - @available(iOSApplicationExtension 14.0, *) - func provideTunnelOptionsCollection(for intent: UpdateConfigurationIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { - self.allTunnelNames { tunnelsNames in - let tunnelsNamesObjects = (tunnelsNames ?? []).map { NSString(string: $0) } - - let objectCollection = INObjectCollection(items: tunnelsNamesObjects) - completion(objectCollection, nil) - } - } - - func handle(intent: UpdateConfigurationIntent, completion: @escaping (UpdateConfigurationIntentResponse) -> Void) { - // Due to an Apple bug (https://developer.apple.com/forums/thread/96020) we can't update VPN - // configuration from extensions at the moment, so we should handle the action in the app. - // We check that the configuration update data is valid and then launch the main app. - - guard let tunnelName = intent.tunnel, - let configurationString = intent.configuration else { - wg_log(.error, message: "Failed to get informations to update the configuration") - completion(UpdateConfigurationIntentResponse(code: .failure, userActivity: nil)) - return - } - - var configurations: [String: [String: String]] - - let configurationsData = Data(configurationString.utf8) - do { - // Make sure this JSON is in the format we expect - if let decodedJson = try JSONSerialization.jsonObject(with: configurationsData, options: []) as? [String: [String: String]] { - configurations = decodedJson - } else { - throw IntentError.failedDecode - } - } catch _ { - wg_log(.error, message: "Failed to decode configuration data in JSON format for \(tunnelName)") - completion(UpdateConfigurationIntentResponse(code: .wrongConfiguration, userActivity: nil)) - return - } - - var activity: NSUserActivity? - if let bundleIdentifier = Bundle.main.bundleIdentifier { - activity = NSUserActivity(activityType: "\(bundleIdentifier).activity.update-tunnel-config") - activity?.userInfo = ["TunnelName": tunnelName, - "Configuration": configurations] - } - - completion(UpdateConfigurationIntentResponse(code: .continueInApp, userActivity: activity)) - } - -} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index e7ad37b66..4aeb2c81b 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -234,7 +234,6 @@ A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1EA21B937EF00483816 /* WireGuardResult.swift */; }; A64A79F927A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; A64A79FA27A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; - A64A79FC27A548A000F15B34 /* IntentHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64A79FB27A548A000F15B34 /* IntentHandling.swift */; }; A64A79FD27A54AA500F15B34 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; }; A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; @@ -487,7 +486,6 @@ A64A79D727A462FC00F15B34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardIntentsExtension-Bridging-Header.h"; sourceTree = ""; }; A64A79F827A5462900F15B34 /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = ""; }; - A64A79FB27A548A000F15B34 /* IntentHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandling.swift; sourceTree = ""; }; A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WireGuardIntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; A6B8051B27A44F770088E750 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; A6B8051E27A44F770088E750 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; @@ -899,7 +897,6 @@ A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */, A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */, A6B8051E27A44F770088E750 /* IntentHandler.swift */, - A64A79FB27A548A000F15B34 /* IntentHandling.swift */, ); name = WireGuardIntentsExtension; path = Sources/WireGuardIntentsExtension; @@ -1606,7 +1603,6 @@ A64A79E827A542F800F15B34 /* key.c in Sources */, A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */, A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */, - A64A79FC27A548A000F15B34 /* IntentHandling.swift in Sources */, A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */, A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */, A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */, From c1d7199f8549206a662059f990aec6d3213edda4 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 5 Apr 2023 15:48:46 +0200 Subject: [PATCH 14/27] Remove WireGuardIntentsExtension Signed-off-by: Alessio Nossa --- Sources/Shared/Intents.intentdefinition | 22 -- Sources/WireGuardIntentsExtension/Info.plist | 51 ----- .../IntentHandler.swift | 17 -- ...ireGuardIntentsExtension-Bridging-Header.h | 2 - ...WireGuardIntentsExtension_iOS.entitlements | 14 -- WireGuard.xcodeproj/project.pbxproj | 198 ------------------ 6 files changed, 304 deletions(-) delete mode 100644 Sources/Shared/Intents.intentdefinition delete mode 100644 Sources/WireGuardIntentsExtension/Info.plist delete mode 100644 Sources/WireGuardIntentsExtension/IntentHandler.swift delete mode 100644 Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h delete mode 100644 Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements diff --git a/Sources/Shared/Intents.intentdefinition b/Sources/Shared/Intents.intentdefinition deleted file mode 100644 index fd9a8dc85..000000000 --- a/Sources/Shared/Intents.intentdefinition +++ /dev/null @@ -1,22 +0,0 @@ - - - - - INEnums - - INIntentDefinitionModelVersion - 1.2 - INIntentDefinitionNamespace - 6NREiY - INIntentDefinitionSystemVersion - 21G419 - INIntentDefinitionToolsBuildVersion - 14C18 - INIntentDefinitionToolsVersion - 14.2 - INIntents - - INTypes - - - diff --git a/Sources/WireGuardIntentsExtension/Info.plist b/Sources/WireGuardIntentsExtension/Info.plist deleted file mode 100644 index 06ec3ab2c..000000000 --- a/Sources/WireGuardIntentsExtension/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - WireGuardIntentsExtension - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - XPC! - CFBundleShortVersionString - $(VERSION_NAME) - CFBundleVersion - $(VERSION_ID) - NSExtension - - NSExtensionAttributes - - IntentsRestrictedWhileLocked - - IntentsRestrictedWhileProtectedDataUnavailable - - IntentsSupported - - GetPeersIntent - UpdateConfigurationIntent - - - NSExtensionPointIdentifier - com.apple.intents-service - NSExtensionPrincipalClass - $(PRODUCT_MODULE_NAME).IntentHandler - - com.wireguard.ios.app_group_id - group.$(APP_ID_IOS) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - com.wireguard.macos.app_group_id - $(DEVELOPMENT_TEAM).group.$(APP_ID_MACOS) - - diff --git a/Sources/WireGuardIntentsExtension/IntentHandler.swift b/Sources/WireGuardIntentsExtension/IntentHandler.swift deleted file mode 100644 index dddb61bd0..000000000 --- a/Sources/WireGuardIntentsExtension/IntentHandler.swift +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. - -import Intents - -class IntentHandler: INExtension { - - override init() { - super.init() - Logger.configureGlobal(tagged: "INTENTS", withFilePath: FileManager.logFileURL?.path) - } - - override func handler(for intent: INIntent) -> Any { - fatalError("Unhandled intent type: \(intent)") - } - -} diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h deleted file mode 100644 index 195da7337..000000000 --- a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "../WireGuardKitC/WireGuardKitC.h" -#include "ringlogger.h" diff --git a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements b/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements deleted file mode 100644 index 33ce9fca4..000000000 --- a/Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements +++ /dev/null @@ -1,14 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - com.apple.security.application-groups - - group.$(APP_ID_IOS) - - - diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 4aeb2c81b..8c97b5c53 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -206,39 +206,6 @@ 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; - A64A79DC27A5411700F15B34 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526E21C23FA10008484E /* Logger.swift */; }; - A64A79DD27A5411E00F15B34 /* ringlogger.c in Sources */ = {isa = PBXBuildFile; fileRef = 6FF3526C21C23F960008484E /* ringlogger.c */; }; - A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774EE21722D97006A79B3 /* TunnelsManager.swift */; }; - A64A79E027A5422E00F15B34 /* NotificationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58233BCE2591F842002060A8 /* NotificationToken.swift */; }; - A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10492577E293004F691E /* TunnelConfiguration.swift */; }; - A64A79E227A5428C00F15B34 /* PrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B104F2577E293004F691E /* PrivateKey.swift */; }; - A64A79E327A5429100F15B34 /* PeerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10472577E293004F691E /* PeerConfiguration.swift */; }; - A64A79E427A542A700F15B34 /* IPAddressRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10512577E293004F691E /* IPAddressRange.swift */; }; - A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10462577E293004F691E /* InterfaceConfiguration.swift */; }; - A64A79E627A542C700F15B34 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10522577E293004F691E /* Endpoint.swift */; }; - A64A79E727A542CA00F15B34 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B10482577E293004F691E /* DNSServer.swift */; }; - A64A79E827A542F800F15B34 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 585B10572577E293004F691E /* key.c */; }; - A64A79E927A542FC00F15B34 /* x25519.c in Sources */ = {isa = PBXBuildFile; fileRef = 585B10562577E293004F691E /* x25519.c */; }; - A64A79EA27A5439900F15B34 /* TunnelErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7F7E5E21C7D74B00527607 /* TunnelErrors.swift */; }; - A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1E821B932F700483816 /* WireGuardAppError.swift */; }; - A64A79EC27A543ED00F15B34 /* LocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE1765921C90E87002690EA /* LocalizationHelper.swift */; }; - A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541A821C451D100994C13 /* TunnelStatus.swift */; }; - A64A79EE27A5442000F15B34 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5C5E26220A48D30024272E /* Keychain.swift */; }; - A64A79EF27A5444600F15B34 /* FileManager+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */; }; - A64A79F027A5445F00F15B34 /* RecentTunnelsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F29A9422278518D00DC6A6B /* RecentTunnelsTracker.swift */; }; - A64A79F127A5447000F15B34 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; }; - A64A79F227A5449300F15B34 /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9696AF21CD7128008063FE /* TunnelConfiguration+WgQuickConfig.swift */; }; - A64A79F327A544A500F15B34 /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4541B121CBFAEE00994C13 /* String+ArrayConversion.swift */; }; - A64A79F427A544BC00F15B34 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; - A64A79F527A544E800F15B34 /* TunnelConfiguration+UapiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B707D8321F918D4000A8F73 /* TunnelConfiguration+UapiConfig.swift */; }; - A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F61F1EA21B937EF00483816 /* WireGuardResult.swift */; }; - A64A79F927A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; - A64A79FA27A5462900F15B34 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = A64A79F827A5462900F15B34 /* Intents.intentdefinition */; }; - A64A79FD27A54AA500F15B34 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */; }; - A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; }; - A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6B8051B27A44F770088E750 /* Intents.framework */; }; - A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B8051E27A44F770088E750 /* IntentHandler.swift */; }; - A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; /* End PBXBuildFile section */ @@ -279,13 +246,6 @@ remoteGlobalIDString = 6FDEF7DD21846BC100D8FBF6; remoteInfo = WireGuardGoBridge; }; - A6B8052127A44F770088E750 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6FF4AC0C211EC46F002C96EB /* Project object */; - proxyType = 1; - remoteGlobalIDString = A6B8051927A44F770088E750; - remoteInfo = WireGuardIntentsExtensioniOS; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -296,7 +256,6 @@ dstSubfolderSpec = 13; files = ( 6F5D0C22218352EF000F85AD /* WireGuardNetworkExtension.appex in Embed App Extensions */, - A6B8052327A44F770088E750 /* WireGuardIntentsExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -483,13 +442,6 @@ 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandOption.swift; sourceTree = ""; }; 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; - A64A79D727A462FC00F15B34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WireGuardIntentsExtension-Bridging-Header.h"; sourceTree = ""; }; - A64A79F827A5462900F15B34 /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = ""; }; - A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WireGuardIntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - A6B8051B27A44F770088E750 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - A6B8051E27A44F770088E750 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; - A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuardIntentsExtension_iOS.entitlements; sourceTree = ""; }; A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -529,15 +481,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A6B8051727A44F770088E750 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A6B8051C27A44F770088E750 /* Intents.framework in Frameworks */, - A64A79FD27A54AA500F15B34 /* NetworkExtension.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -647,7 +590,6 @@ 6F5A2B4421AFDE020081EDD8 /* FileManager+Extension.swift */, 6B5C5E26220A48D30024272E /* Keychain.swift */, 58233BCE2591F842002060A8 /* NotificationToken.swift */, - A64A79F827A5462900F15B34 /* Intents.intentdefinition */, ); name = Shared; path = Sources/Shared; @@ -830,7 +772,6 @@ 6F5D0C432183B4A4000F85AD /* Shared */, 6FF4AC16211EC46F002C96EB /* WireGuardApp */, 6F5D0C1B218352EF000F85AD /* WireGuardNetworkExtension */, - A6B8051D27A44F770088E750 /* WireGuardIntentsExtension */, 585B10452577E293004F691E /* WireGuardKit */, 585B10532577E293004F691E /* WireGuardKitC */, 6FF4AC15211EC46F002C96EB /* Products */, @@ -846,7 +787,6 @@ 6FB1BD5D21D2607A00A991BF /* WireGuard.app */, 6FB1BD9121D4BFE600A991BF /* WireGuardNetworkExtension.appex */, 6F70E22922106A2D008BDFB4 /* WireGuardLoginItemHelper.app */, - A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */, ); name = Products; sourceTree = ""; @@ -874,7 +814,6 @@ 58DB6CD52577F95D00FB6B73 /* libwg-go.a */, 6FB1BDB621D4F8B800A991BF /* NetworkExtension.framework */, 6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */, - A6B8051B27A44F770088E750 /* Intents.framework */, ); name = Frameworks; sourceTree = ""; @@ -890,18 +829,6 @@ path = Sources/WireguardAppIntents; sourceTree = ""; }; - A6B8051D27A44F770088E750 /* WireGuardIntentsExtension */ = { - isa = PBXGroup; - children = ( - A64A79D727A462FC00F15B34 /* Info.plist */, - A6B8052727A454150088E750 /* WireGuardIntentsExtension_iOS.entitlements */, - A64A79D827A48A8E00F15B34 /* WireGuardIntentsExtension-Bridging-Header.h */, - A6B8051E27A44F770088E750 /* IntentHandler.swift */, - ); - name = WireGuardIntentsExtension; - path = Sources/WireGuardIntentsExtension; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ @@ -1035,7 +962,6 @@ ); dependencies = ( 6F5D0C21218352EF000F85AD /* PBXTargetDependency */, - A6B8052227A44F770088E750 /* PBXTargetDependency */, ); name = WireGuardiOS; packageProductDependencies = ( @@ -1044,23 +970,6 @@ productReference = 6FF4AC14211EC46F002C96EB /* WireGuard.app */; productType = "com.apple.product-type.application"; }; - A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = A6B8052427A44F770088E750 /* Build configuration list for PBXNativeTarget "WireGuardIntentsExtensioniOS" */; - buildPhases = ( - A6B8051627A44F770088E750 /* Sources */, - A6B8051727A44F770088E750 /* Frameworks */, - A6B8051827A44F770088E750 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = WireGuardIntentsExtensioniOS; - productName = WireGuardIntentsExtensioniOS; - productReference = A6B8051A27A44F770088E750 /* WireGuardIntentsExtension.appex */; - productType = "com.apple.product-type.app-extension"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1125,9 +1034,6 @@ }; }; }; - A6B8051927A44F770088E750 = { - CreatedOnToolsVersion = 13.2.1; - }; }; }; buildConfigurationList = 6FF4AC0F211EC46F002C96EB /* Build configuration list for PBXProject "WireGuard" */; @@ -1165,7 +1071,6 @@ targets = ( 6FF4AC13211EC46F002C96EB /* WireGuardiOS */, 6F5D0C19218352EF000F85AD /* WireGuardNetworkExtensioniOS */, - A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */, 6FDEF7DD21846BC100D8FBF6 /* WireGuardGoBridgeiOS */, 6FB1BD5C21D2607A00A991BF /* WireGuardmacOS */, 6FB1BD9021D4BFE600A991BF /* WireGuardNetworkExtensionmacOS */, @@ -1215,13 +1120,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A6B8051827A44F770088E750 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1560,7 +1458,6 @@ 6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */, 5F45418C21C2D48200994C13 /* TunnelEditKeyValueCell.swift in Sources */, 6FE254FB219C10800028284D /* ZipImporter.swift in Sources */, - A64A79F927A5462900F15B34 /* Intents.intentdefinition in Sources */, 585B107E2577E294004F691E /* PrivateKey.swift in Sources */, 6FDEF7FB21863B6100D8FBF6 /* unzip.c in Sources */, 6F29A9432278518D00DC6A6B /* RecentTunnelsTracker.swift in Sources */, @@ -1589,42 +1486,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A6B8051627A44F770088E750 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A6B8051F27A44F770088E750 /* IntentHandler.swift in Sources */, - A64A79FE27A58F1800F15B34 /* MockTunnels.swift in Sources */, - A64A79EF27A5444600F15B34 /* FileManager+Extension.swift in Sources */, - A64A79E027A5422E00F15B34 /* NotificationToken.swift in Sources */, - A64A79DC27A5411700F15B34 /* Logger.swift in Sources */, - A64A79DD27A5411E00F15B34 /* ringlogger.c in Sources */, - A64A79F527A544E800F15B34 /* TunnelConfiguration+UapiConfig.swift in Sources */, - A64A79E827A542F800F15B34 /* key.c in Sources */, - A64A79E127A5426C00F15B34 /* TunnelConfiguration.swift in Sources */, - A64A79DE27A541F500F15B34 /* TunnelsManager.swift in Sources */, - A64A79ED27A5440E00F15B34 /* TunnelStatus.swift in Sources */, - A64A79EB27A543D400F15B34 /* WireGuardAppError.swift in Sources */, - A64A79E527A542C000F15B34 /* InterfaceConfiguration.swift in Sources */, - A64A79F127A5447000F15B34 /* NETunnelProviderProtocol+Extension.swift in Sources */, - A64A79E327A5429100F15B34 /* PeerConfiguration.swift in Sources */, - A64A79FA27A5462900F15B34 /* Intents.intentdefinition in Sources */, - A64A79EE27A5442000F15B34 /* Keychain.swift in Sources */, - A64A79F327A544A500F15B34 /* String+ArrayConversion.swift in Sources */, - A64A79E227A5428C00F15B34 /* PrivateKey.swift in Sources */, - A64A79F427A544BC00F15B34 /* ActivateOnDemandOption.swift in Sources */, - A64A79E627A542C700F15B34 /* Endpoint.swift in Sources */, - A64A79E927A542FC00F15B34 /* x25519.c in Sources */, - A64A79E727A542CA00F15B34 /* DNSServer.swift in Sources */, - A64A79E427A542A700F15B34 /* IPAddressRange.swift in Sources */, - A64A79EA27A5439900F15B34 /* TunnelErrors.swift in Sources */, - A64A79F627A5450000F15B34 /* WireGuardResult.swift in Sources */, - A64A79F227A5449300F15B34 /* TunnelConfiguration+WgQuickConfig.swift in Sources */, - A64A79F027A5445F00F15B34 /* RecentTunnelsTracker.swift in Sources */, - A64A79EC27A543ED00F15B34 /* LocalizationHelper.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1653,11 +1514,6 @@ target = 6FDEF7DD21846BC100D8FBF6 /* WireGuardGoBridgeiOS */; targetProxy = 6FDEF7E121846C0000D8FBF6 /* PBXContainerItemProxy */; }; - A6B8052227A44F770088E750 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = A6B8051927A44F770088E750 /* WireGuardIntentsExtensioniOS */; - targetProxy = A6B8052127A44F770088E750 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -2062,51 +1918,6 @@ }; name = Release; }; - A6B8052527A44F770088E750 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Sources/WireGuardIntentsExtension/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_IOS).intents-extension"; - PRODUCT_NAME = WireGuardIntentsExtension; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - A6B8052627A44F770088E750 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Sources/WireGuardIntentsExtension/WireGuardIntentsExtension_iOS.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Sources/WireGuardIntentsExtension/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(APP_ID_IOS).intents-extension"; - PRODUCT_NAME = WireGuardIntentsExtension; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "Sources/WireGuardIntentsExtension/WireGuardIntentsExtension-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2182,15 +1993,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - A6B8052427A44F770088E750 /* Build configuration list for PBXNativeTarget "WireGuardIntentsExtensioniOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A6B8052527A44F770088E750 /* Debug */, - A6B8052627A44F770088E750 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 6FF4AC0C211EC46F002C96EB /* Project object */; From a0a6f26846cdc13f2224702fd6df6ee113871766 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 12 Apr 2023 00:20:02 +0200 Subject: [PATCH 15/27] WireguardApp: iOS: Cleanup after SiriKit Intents removal Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/UI/iOS/AppDelegate.swift | 8 -------- Sources/WireGuardApp/UI/iOS/WireGuard.entitlements | 2 -- 2 files changed, 10 deletions(-) diff --git a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift index e05a31963..9be1ba146 100644 --- a/Sources/WireGuardApp/UI/iOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/iOS/AppDelegate.swift @@ -3,7 +3,6 @@ import UIKit import os.log -import Intents import AppIntents @UIApplicationMain @@ -111,10 +110,3 @@ extension AppDelegate { return nil } } - -extension AppDelegate { - - func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { - return false - } -} diff --git a/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements b/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements index 60d6ee429..93c724936 100644 --- a/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements +++ b/Sources/WireGuardApp/UI/iOS/WireGuard.entitlements @@ -8,8 +8,6 @@ com.apple.developer.networking.wifi-info - com.apple.developer.siri - com.apple.security.application-groups group.$(APP_ID_IOS) From 1cb06536f19e06aad6bc490bbcc99cccfc0469c4 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 18:46:35 +0200 Subject: [PATCH 16/27] WireguardApp: Add async variant of modify tunnel function Signed-off-by: Alessio Nossa --- .../WireGuardApp/Tunnel/TunnelsManager.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift index 7751e5457..44718594a 100644 --- a/Sources/WireGuardApp/Tunnel/TunnelsManager.swift +++ b/Sources/WireGuardApp/Tunnel/TunnelsManager.swift @@ -206,6 +206,7 @@ class TunnelsManager { } } + @available(*, renamed: "modify(tunnel:tunnelConfiguration:onDemandOption:shouldEnsureOnDemandEnabled:)") func modify(tunnel: TunnelContainer, tunnelConfiguration: TunnelConfiguration, onDemandOption: ActivateOnDemandOption, shouldEnsureOnDemandEnabled: Bool = false, @@ -299,6 +300,22 @@ class TunnelsManager { } } + @available(iOS 13.0, macOS 10.15.0, *) + func modify(tunnel: TunnelContainer, tunnelConfiguration: TunnelConfiguration, + onDemandOption: ActivateOnDemandOption, + shouldEnsureOnDemandEnabled: Bool = false) async throws { + return try await withCheckedThrowingContinuation { continuation in + modify(tunnel: tunnel, tunnelConfiguration: tunnelConfiguration, onDemandOption: onDemandOption, shouldEnsureOnDemandEnabled: shouldEnsureOnDemandEnabled) { error in + if let error = error { + continuation.resume(throwing: error) + return + } + + continuation.resume(returning: ()) + } + } + } + func remove(tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) { let tunnelProviderManager = tunnel.tunnelProvider #if os(macOS) From ba250fe1a5c57ed3fc2f18560c0ddd72cefafc73 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 18:26:32 +0200 Subject: [PATCH 17/27] Implement UpdateConfiguration AppIntent with Dictionary as input Signed-off-by: Alessio Nossa --- .../WireguardAppIntents/AppIntents.strings | 18 +++ .../UpdateConfiguration.swift | 135 ++++++++++++++++++ WireGuard.xcodeproj/project.pbxproj | 4 + 3 files changed, 157 insertions(+) create mode 100644 Sources/WireguardAppIntents/UpdateConfiguration.swift diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index e53949965..a752acbc3 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -10,3 +10,21 @@ "getPeersIntentDescription" = "Get list of public keys of peers in the selected configuration"; "getPeersIntentTunnelParameterTitle" = "Tunnel"; "getPeersIntentSummary ${tunnelName}" = "Get peers of ${tunnelName}"; + +// Update configuration [Dictionary] +"updateConfigurationIntentName" = "Update Tunnel Configuration [Dictionary]"; +"updateConfigurationIntentDescription" = "Update peers configuration. Configuration must be provided as a JSON object that has the peers public keys as dictionary's keys and a nested dictionary with with the fields to update a as velue, like the following example. The fields you can update are: \"Endpoint\". +The fields and the peers you omit will not be modified. + +Example +{ \"Peer1_Public_Key_(Base64)\": { \"Endpoint\": \"1.2.3.4:4321\" }, + \"Peer1_Public_Key_(Base64)\": { \"Endpoint\": \"10.11.12.13:6789\"} } + +In the Shortcuts app, you can pass directly a Dictionary object."; +"updateConfigurationIntentTunnelParameterTitle" = "Tunnel"; +"updateConfigurationIntentConfigurationParameterTitle" = "Configuration"; +"updateConfigurationIntentSummary ${tunnelName}" = "Update ${tunnelName} configuration"; + +"updateConfigurationIntentInvalidConfigurationError" = "The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description."; +"updateConfigurationIntentJsonDecodingError" = "The configuration update provided is not a valid JSON object. Make sure you pass configuration as described in Action description."; +"updateConfigurationIntentMalformedPublicKeyError %@" = "The key \"%1$@\" is not a valid Public Key encoded in Base64 format."; diff --git a/Sources/WireguardAppIntents/UpdateConfiguration.swift b/Sources/WireguardAppIntents/UpdateConfiguration.swift new file mode 100644 index 000000000..686d154bc --- /dev/null +++ b/Sources/WireguardAppIntents/UpdateConfiguration.swift @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import Foundation +import AppIntents + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct UpdateConfiguration: AppIntent { + + static var title = LocalizedStringResource("updateConfigurationIntentName", table: "AppIntents") + static var description = IntentDescription( + LocalizedStringResource("updateConfigurationIntentDescription", table: "AppIntents") + ) + + @Parameter( + title: LocalizedStringResource("updateConfigurationIntentTunnelParameterTitle", table: "AppIntents"), + optionsProvider: TunnelsOptionsProvider() + ) + var tunnelName: String + + @Parameter( + title: LocalizedStringResource("updateConfigurationIntentConfigurationParameterTitle", table: "AppIntents"), + default: #"{"Peer Public Key": {"Endpoint":"1.2.3.4:5678"} }"#, + // Multiline not working in iOS 16.4 (FB12099849) + inputOptions: .init(capitalizationType: .none, multiline: true, autocorrect: false, + smartQuotes: false, smartDashes: false) + ) + var configurationsString: String + + @Dependency + var tunnelsManager: TunnelsManager + + func perform() async throws -> some IntentResult { + guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { + throw UpdateConfigurationIntentError.wrongTunnel(name: tunnelName) + } + + guard let tunnelConfiguration = tunnelContainer.tunnelConfiguration else { + throw UpdateConfigurationIntentError.missingConfiguration + } + + let confugurationsUpdates = try extractConfigurationDictionary(from: configurationsString) + + let newConfiguration = try buildNewConfiguration(from: tunnelConfiguration, configurationUpdates: confugurationsUpdates) + + do { + try await tunnelsManager.modify(tunnel: tunnelContainer, tunnelConfiguration: newConfiguration, onDemandOption: tunnelContainer.onDemandOption) + } catch { + wg_log(.error, message: error.localizedDescription) + throw error + } + + wg_log(.debug, message: "Updated configuration of tunnel \(tunnelName)") + + return .result() + } + + static var parameterSummary: some ParameterSummary { + Summary("updateConfigurationIntentSummary \(\.$tunnelName)", table: "AppIntents") { + \.$configurationsString + } + } + + private func extractConfigurationDictionary(from configurationString: String) throws -> [String: [String: String]] { + let configurationsData = Data(configurationsString.utf8) + + var configurations: [String: [String: String]] + do { + let decodedJson = try JSONSerialization.jsonObject(with: configurationsData, options: []) + // Make sure this JSON is in the format we expect + if let configDictionary = decodedJson as? [String: [String: String]] { + configurations = configDictionary + } else { + throw UpdateConfigurationIntentError.invalidConfiguration + } + } catch { + wg_log(.error, message: "Failed to decode configuration data in JSON format for \(tunnelName). \(error.localizedDescription)") + + throw UpdateConfigurationIntentError.jsonDecodingFailure + } + + return configurations + } + + private func buildNewConfiguration(from oldConfiguration: TunnelConfiguration, configurationUpdates: [String: [String: String]]) throws -> TunnelConfiguration { + var peers = oldConfiguration.peers + + for (peerPubKey, valuesToUpdate) in configurationUpdates { + if let peerIndex = peers.firstIndex(where: { $0.publicKey.base64Key == peerPubKey }) { + if let endpointString = valuesToUpdate[kEndpointConfigurationUpdateDictionaryKey] { + if let newEntpoint = Endpoint(from: endpointString) { + peers[peerIndex].endpoint = newEntpoint + } else { + wg_log(.debug, message: "Failed to convert \(endpointString) to Endpoint") + } + } + } else { + wg_log(.debug, message: "Failed to find peer \(peerPubKey) in tunnel with name \(tunnelName). Adding it.") + + guard let pubKeyEncoded = PublicKey(base64Key: peerPubKey) else { + throw UpdateConfigurationIntentError.malformedPublicKey(key: peerPubKey) + } + let newPeerConfig = PeerConfiguration(publicKey: pubKeyEncoded) + peers.append(newPeerConfig) + } + } + + let newConfiguration = TunnelConfiguration(name: oldConfiguration.name, interface: oldConfiguration.interface, peers: peers) + return newConfiguration + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +enum UpdateConfigurationIntentError: Swift.Error, CustomLocalizedStringResourceConvertible { + case wrongTunnel(name: String) + case missingConfiguration + case invalidConfiguration + case jsonDecodingFailure + case malformedPublicKey(key: String) + + var localizedStringResource: LocalizedStringResource { + switch self { + case .wrongTunnel(let name): + return LocalizedStringResource("wireguardAppIntentsWrongTunnelError \(name)", table: "AppIntents") + case .missingConfiguration: + return LocalizedStringResource("wireguardAppIntentsMissingConfigurationError", table: "AppIntents") + case .invalidConfiguration: + return LocalizedStringResource("updateConfigurationIntentInvalidConfigurationError", table: "AppIntents") + case .jsonDecodingFailure: + return LocalizedStringResource("updateConfigurationIntentJsonDecodingError", table: "AppIntents") + case .malformedPublicKey(let malformedKey): + return LocalizedStringResource("updateConfigurationIntentMalformedPublicKeyError \(malformedKey)", table: "AppIntents") + } + } +} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 8c97b5c53..2be99b7dc 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,6 +205,7 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; + A625F05329C4C627005EF23D /* UpdateConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; @@ -441,6 +442,7 @@ 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = ""; }; 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandOption.swift; sourceTree = ""; }; 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; + A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateConfiguration.swift; sourceTree = ""; }; A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; @@ -821,6 +823,7 @@ A625F04C29C4C627005EF23D /* WireguardAppIntents */ = { isa = PBXGroup; children = ( + A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */, A625F05029C4C627005EF23D /* GetPeers.swift */, A6E361F729D8758500FFF234 /* AppIntents.strings */, A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */, @@ -1435,6 +1438,7 @@ 6F8F0D7722267C57000E8335 /* SSIDOptionEditTableViewController.swift in Sources */, 585B10622577E293004F691E /* DNSServer.swift in Sources */, 6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */, + A625F05329C4C627005EF23D /* UpdateConfiguration.swift in Sources */, 6FDB6D18224CC05A00EE4BC3 /* LogViewController.swift in Sources */, 6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */, 5F4541A921C451D100994C13 /* TunnelStatus.swift in Sources */, From eec11c1eefe5400b85107e5cba21e950505b90ea Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 23:33:21 +0200 Subject: [PATCH 18/27] Remove UpdateConfiguration Intent with Dictionary input Signed-off-by: Alessio Nossa --- .../WireguardAppIntents/AppIntents.strings | 18 --- .../UpdateConfiguration.swift | 135 ------------------ WireGuard.xcodeproj/project.pbxproj | 4 - 3 files changed, 157 deletions(-) delete mode 100644 Sources/WireguardAppIntents/UpdateConfiguration.swift diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index a752acbc3..e53949965 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -10,21 +10,3 @@ "getPeersIntentDescription" = "Get list of public keys of peers in the selected configuration"; "getPeersIntentTunnelParameterTitle" = "Tunnel"; "getPeersIntentSummary ${tunnelName}" = "Get peers of ${tunnelName}"; - -// Update configuration [Dictionary] -"updateConfigurationIntentName" = "Update Tunnel Configuration [Dictionary]"; -"updateConfigurationIntentDescription" = "Update peers configuration. Configuration must be provided as a JSON object that has the peers public keys as dictionary's keys and a nested dictionary with with the fields to update a as velue, like the following example. The fields you can update are: \"Endpoint\". -The fields and the peers you omit will not be modified. - -Example -{ \"Peer1_Public_Key_(Base64)\": { \"Endpoint\": \"1.2.3.4:4321\" }, - \"Peer1_Public_Key_(Base64)\": { \"Endpoint\": \"10.11.12.13:6789\"} } - -In the Shortcuts app, you can pass directly a Dictionary object."; -"updateConfigurationIntentTunnelParameterTitle" = "Tunnel"; -"updateConfigurationIntentConfigurationParameterTitle" = "Configuration"; -"updateConfigurationIntentSummary ${tunnelName}" = "Update ${tunnelName} configuration"; - -"updateConfigurationIntentInvalidConfigurationError" = "The configuration update provided is not in the right format. Make sure you pass configuration as described in Action description."; -"updateConfigurationIntentJsonDecodingError" = "The configuration update provided is not a valid JSON object. Make sure you pass configuration as described in Action description."; -"updateConfigurationIntentMalformedPublicKeyError %@" = "The key \"%1$@\" is not a valid Public Key encoded in Base64 format."; diff --git a/Sources/WireguardAppIntents/UpdateConfiguration.swift b/Sources/WireguardAppIntents/UpdateConfiguration.swift deleted file mode 100644 index 686d154bc..000000000 --- a/Sources/WireguardAppIntents/UpdateConfiguration.swift +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. - -import Foundation -import AppIntents - -@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -struct UpdateConfiguration: AppIntent { - - static var title = LocalizedStringResource("updateConfigurationIntentName", table: "AppIntents") - static var description = IntentDescription( - LocalizedStringResource("updateConfigurationIntentDescription", table: "AppIntents") - ) - - @Parameter( - title: LocalizedStringResource("updateConfigurationIntentTunnelParameterTitle", table: "AppIntents"), - optionsProvider: TunnelsOptionsProvider() - ) - var tunnelName: String - - @Parameter( - title: LocalizedStringResource("updateConfigurationIntentConfigurationParameterTitle", table: "AppIntents"), - default: #"{"Peer Public Key": {"Endpoint":"1.2.3.4:5678"} }"#, - // Multiline not working in iOS 16.4 (FB12099849) - inputOptions: .init(capitalizationType: .none, multiline: true, autocorrect: false, - smartQuotes: false, smartDashes: false) - ) - var configurationsString: String - - @Dependency - var tunnelsManager: TunnelsManager - - func perform() async throws -> some IntentResult { - guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { - throw UpdateConfigurationIntentError.wrongTunnel(name: tunnelName) - } - - guard let tunnelConfiguration = tunnelContainer.tunnelConfiguration else { - throw UpdateConfigurationIntentError.missingConfiguration - } - - let confugurationsUpdates = try extractConfigurationDictionary(from: configurationsString) - - let newConfiguration = try buildNewConfiguration(from: tunnelConfiguration, configurationUpdates: confugurationsUpdates) - - do { - try await tunnelsManager.modify(tunnel: tunnelContainer, tunnelConfiguration: newConfiguration, onDemandOption: tunnelContainer.onDemandOption) - } catch { - wg_log(.error, message: error.localizedDescription) - throw error - } - - wg_log(.debug, message: "Updated configuration of tunnel \(tunnelName)") - - return .result() - } - - static var parameterSummary: some ParameterSummary { - Summary("updateConfigurationIntentSummary \(\.$tunnelName)", table: "AppIntents") { - \.$configurationsString - } - } - - private func extractConfigurationDictionary(from configurationString: String) throws -> [String: [String: String]] { - let configurationsData = Data(configurationsString.utf8) - - var configurations: [String: [String: String]] - do { - let decodedJson = try JSONSerialization.jsonObject(with: configurationsData, options: []) - // Make sure this JSON is in the format we expect - if let configDictionary = decodedJson as? [String: [String: String]] { - configurations = configDictionary - } else { - throw UpdateConfigurationIntentError.invalidConfiguration - } - } catch { - wg_log(.error, message: "Failed to decode configuration data in JSON format for \(tunnelName). \(error.localizedDescription)") - - throw UpdateConfigurationIntentError.jsonDecodingFailure - } - - return configurations - } - - private func buildNewConfiguration(from oldConfiguration: TunnelConfiguration, configurationUpdates: [String: [String: String]]) throws -> TunnelConfiguration { - var peers = oldConfiguration.peers - - for (peerPubKey, valuesToUpdate) in configurationUpdates { - if let peerIndex = peers.firstIndex(where: { $0.publicKey.base64Key == peerPubKey }) { - if let endpointString = valuesToUpdate[kEndpointConfigurationUpdateDictionaryKey] { - if let newEntpoint = Endpoint(from: endpointString) { - peers[peerIndex].endpoint = newEntpoint - } else { - wg_log(.debug, message: "Failed to convert \(endpointString) to Endpoint") - } - } - } else { - wg_log(.debug, message: "Failed to find peer \(peerPubKey) in tunnel with name \(tunnelName). Adding it.") - - guard let pubKeyEncoded = PublicKey(base64Key: peerPubKey) else { - throw UpdateConfigurationIntentError.malformedPublicKey(key: peerPubKey) - } - let newPeerConfig = PeerConfiguration(publicKey: pubKeyEncoded) - peers.append(newPeerConfig) - } - } - - let newConfiguration = TunnelConfiguration(name: oldConfiguration.name, interface: oldConfiguration.interface, peers: peers) - return newConfiguration - } -} - -@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -enum UpdateConfigurationIntentError: Swift.Error, CustomLocalizedStringResourceConvertible { - case wrongTunnel(name: String) - case missingConfiguration - case invalidConfiguration - case jsonDecodingFailure - case malformedPublicKey(key: String) - - var localizedStringResource: LocalizedStringResource { - switch self { - case .wrongTunnel(let name): - return LocalizedStringResource("wireguardAppIntentsWrongTunnelError \(name)", table: "AppIntents") - case .missingConfiguration: - return LocalizedStringResource("wireguardAppIntentsMissingConfigurationError", table: "AppIntents") - case .invalidConfiguration: - return LocalizedStringResource("updateConfigurationIntentInvalidConfigurationError", table: "AppIntents") - case .jsonDecodingFailure: - return LocalizedStringResource("updateConfigurationIntentJsonDecodingError", table: "AppIntents") - case .malformedPublicKey(let malformedKey): - return LocalizedStringResource("updateConfigurationIntentMalformedPublicKeyError \(malformedKey)", table: "AppIntents") - } - } -} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 2be99b7dc..8c97b5c53 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,7 +205,6 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; - A625F05329C4C627005EF23D /* UpdateConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; @@ -442,7 +441,6 @@ 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = ""; }; 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandOption.swift; sourceTree = ""; }; 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; - A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateConfiguration.swift; sourceTree = ""; }; A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; @@ -823,7 +821,6 @@ A625F04C29C4C627005EF23D /* WireguardAppIntents */ = { isa = PBXGroup; children = ( - A625F04E29C4C627005EF23D /* UpdateConfiguration.swift */, A625F05029C4C627005EF23D /* GetPeers.swift */, A6E361F729D8758500FFF234 /* AppIntents.strings */, A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */, @@ -1438,7 +1435,6 @@ 6F8F0D7722267C57000E8335 /* SSIDOptionEditTableViewController.swift in Sources */, 585B10622577E293004F691E /* DNSServer.swift in Sources */, 6FDEF7E62185EFB200D8FBF6 /* QRScanViewController.swift in Sources */, - A625F05329C4C627005EF23D /* UpdateConfiguration.swift in Sources */, 6FDB6D18224CC05A00EE4BC3 /* LogViewController.swift in Sources */, 6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */, 5F4541A921C451D100994C13 /* TunnelStatus.swift in Sources */, From e13bc40f88a498e0b76e1725919993aec9f5f909 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 23:41:31 +0200 Subject: [PATCH 19/27] Implement BuildPeerConfigurationUpdate App Intent Signed-off-by: Alessio Nossa --- .../WireguardAppIntents/AppIntents.strings | 12 +++ .../BuildPeerConfigurationUpdate.swift | 77 +++++++++++++++++++ WireGuard.xcodeproj/project.pbxproj | 4 + 3 files changed, 93 insertions(+) create mode 100644 Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index e53949965..9ebdc8ea3 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -10,3 +10,15 @@ "getPeersIntentDescription" = "Get list of public keys of peers in the selected configuration"; "getPeersIntentTunnelParameterTitle" = "Tunnel"; "getPeersIntentSummary ${tunnelName}" = "Get peers of ${tunnelName}"; + +// Build Peer Configuration +"buildPeerConfigurationUpdateIntentName" = "Build Peer Configuration"; +"buildPeerConfigurationUpdateIntentDescription" = ""; +"buildPeerConfigurationUpdateIntentSummary ${publicKey}" = "Build configuration for peer ${publicKey}"; +"buildPeerConfigurationUpdateIntentPublicKeyParameterTitle" = "Peer Public Key"; +"buildPeerConfigurationUpdateIntentEndpointParameterTitle" = "Endpoint"; + +// Peer Configuration Update Entity +"peerConfigurationUpdateEntityName" = "Configuration Update - Peer"; +"peerConfigurationUpdateEntityPropertyPublicKeyTitle" = "Public Key"; +"peerConfigurationUpdateEntityPropertyEndpointTitle" = "Endpoint"; diff --git a/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift new file mode 100644 index 000000000..d6c003289 --- /dev/null +++ b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import AppIntents + +let kEndpointConfigurationUpdateDictionaryKey = "Endpoint" + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct BuildPeerConfigurationUpdate: AppIntent { + + static var title = LocalizedStringResource("buildPeerConfigurationUpdateIntentName", table: "AppIntents") + static var description = IntentDescription( + LocalizedStringResource("buildPeerConfigurationUpdateIntentDescription", table: "AppIntents") + ) + + @Parameter( + title: LocalizedStringResource("buildPeerConfigurationUpdateIntentPublicKeyParameterTitle", table: "AppIntents") + ) + var publicKey: String + + @Parameter( + title: LocalizedStringResource("buildPeerConfigurationUpdateIntentEndpointParameterTitle", table: "AppIntents") + ) + var endpoint: String + + func perform() async throws -> some IntentResult { + let peerConfigurationUpdate = AppIntentsPeer() + peerConfigurationUpdate.publicKey = publicKey + peerConfigurationUpdate.endpoint = endpoint + + return .result(value: peerConfigurationUpdate) + } + + static var parameterSummary: some ParameterSummary { + Summary("buildPeerConfigurationUpdateIntentSummary \(\.$publicKey)", table: "AppIntents") { + \.$endpoint + } + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct AppIntentsPeer: TransientAppEntity { + + static var typeDisplayRepresentation = TypeDisplayRepresentation( + name: LocalizedStringResource("peerConfigurationUpdateEntityName", table: "AppIntents") + ) + + @Property( + title: LocalizedStringResource("peerConfigurationUpdateEntityPropertyPublicKeyTitle", table: "AppIntents") + ) + var publicKey: String + + @Property( + title: LocalizedStringResource("peerConfigurationUpdateEntityPropertyEndpointTitle", table: "AppIntents") + ) + var endpoint: String? + + var displayRepresentation: DisplayRepresentation { + var dictionary: [String: [String: String]] = [:] + dictionary[publicKey] = [:] + + if let endpoint { + dictionary[publicKey]?.updateValue(endpoint, forKey: kEndpointConfigurationUpdateDictionaryKey) + } + + let jsonData: Data + do { + jsonData = try JSONSerialization.data(withJSONObject: dictionary) + } catch { + return DisplayRepresentation(stringLiteral: error.localizedDescription) + } + + let jsonString = String(data: jsonData, encoding: .utf8)! + + return DisplayRepresentation(stringLiteral: jsonString) + } +} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 8c97b5c53..ad1ef98da 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -207,6 +207,7 @@ 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; + A6E361FC29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */; }; A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; /* End PBXBuildFile section */ @@ -443,6 +444,7 @@ 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; + A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildPeerConfigurationUpdate.swift; sourceTree = ""; }; A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -821,6 +823,7 @@ A625F04C29C4C627005EF23D /* WireguardAppIntents */ = { isa = PBXGroup; children = ( + A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */, A625F05029C4C627005EF23D /* GetPeers.swift */, A6E361F729D8758500FFF234 /* AppIntents.strings */, A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */, @@ -1456,6 +1459,7 @@ 6F919EC3218A2AE90023B400 /* ErrorPresenter.swift in Sources */, 6B62E45F220A6FA900EF34A6 /* PrivateDataConfirmation.swift in Sources */, 6F5A2B4821AFF49A0081EDD8 /* FileManager+Extension.swift in Sources */, + A6E361FC29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift in Sources */, 5F45418C21C2D48200994C13 /* TunnelEditKeyValueCell.swift in Sources */, 6FE254FB219C10800028284D /* ZipImporter.swift in Sources */, 585B107E2577E294004F691E /* PrivateKey.swift in Sources */, From ee035362ece471b5a23e1d4b2aec862e5fe5ca83 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Tue, 11 Apr 2023 23:42:09 +0200 Subject: [PATCH 20/27] Implement UpdateTunnelConfiguration App Intent Signed-off-by: Alessio Nossa --- .../WireguardAppIntents/AppIntents.strings | 12 ++ .../UpdateTunnelConfiguration.swift | 134 ++++++++++++++++++ WireGuard.xcodeproj/project.pbxproj | 4 + 3 files changed, 150 insertions(+) create mode 100644 Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index 9ebdc8ea3..1c2064ea7 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -11,6 +11,18 @@ "getPeersIntentTunnelParameterTitle" = "Tunnel"; "getPeersIntentSummary ${tunnelName}" = "Get peers of ${tunnelName}"; +// Tunnel Configuration Update +"updateTunnelConfigurationIntentName" = "Update Tunnel Configuration"; +"updateTunnelConfigurationDescription" = "Update peers configuration of the selected tunnel."; +"updateTunnelConfigurationIntentTunnelParameterTitle" = "Tunnel"; +"updateTunnelConfigurationIntentPeersParameterTitle" = "Peers"; +"updateTunnelConfigurationIntentMergeParameterTitle" = "Merge configuration"; +"updateTunnelConfigurationIntentSummary ${tunnelName}" = "Update ${tunnelName} configuration"; + +"updateTunnelConfigurationIntentPeerOptionsUnavailableError" = "Use the output of \"Build Peer Configuration\" action to update tunnel configuration."; +"updateTunnelConfigurationIntentMissingPeerParameterError" = "Peer parameter value is missing"; +"updateTunnelConfigurationIntentMalformedPublicKeyError %@" = "The key \"%1$@\" is not a valid Public Key encoded in Base64 format."; + // Build Peer Configuration "buildPeerConfigurationUpdateIntentName" = "Build Peer Configuration"; "buildPeerConfigurationUpdateIntentDescription" = ""; diff --git a/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift b/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift new file mode 100644 index 000000000..51fc605c6 --- /dev/null +++ b/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved. + +import AppIntents + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct UpdateTunnelConfiguration: AppIntent { + + static var title = LocalizedStringResource("updateTunnelConfigurationIntentName", table: "AppIntents") + static var description = IntentDescription( + LocalizedStringResource("updateTunnelConfigurationDescription", table: "AppIntents") + ) + + @Parameter( + title: LocalizedStringResource("updateTunnelConfigurationIntentTunnelParameterTitle", table: "AppIntents"), + optionsProvider: TunnelsOptionsProvider() + ) + var tunnelName: String + + @Parameter( + title: LocalizedStringResource("updateTunnelConfigurationIntentPeersParameterTitle", table: "AppIntents"), + optionsProvider: AppIntentsPeerOptionsProvider() + ) + var peers: [AppIntentsPeer]? + + @Parameter( + title: LocalizedStringResource("updateTunnelConfigurationIntentMergeParameterTitle", table: "AppIntents"), + default: true + ) + var mergeConfiguration: Bool + + @Dependency + var tunnelsManager: TunnelsManager + + func perform() async throws -> some IntentResult { + guard let peers else { throw AppIntentConfigurationUpdateError.missingPeerParameter } + + guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { + throw AppIntentConfigurationUpdateError.wrongTunnel(name: tunnelName) + } + + guard let tunnelConfiguration = tunnelContainer.tunnelConfiguration else { + throw AppIntentConfigurationUpdateError.missingConfiguration + } + + let newConfiguration = try buildNewConfiguration(from: tunnelConfiguration, peersUpdates: peers, mergeChanges: mergeConfiguration) + + do { + try await tunnelsManager.modify(tunnel: tunnelContainer, tunnelConfiguration: newConfiguration, onDemandOption: tunnelContainer.onDemandOption) + } catch { + wg_log(.error, message: error.localizedDescription) + throw error + } + + wg_log(.debug, message: "Updated configuration of tunnel \(tunnelName)") + + return .result() + } + + static var parameterSummary: some ParameterSummary { + Summary("updateTunnelConfigurationIntentSummary \(\.$tunnelName)", table: "AppIntents") { + \.$peers + \.$mergeConfiguration + } + } + + private func buildNewConfiguration(from oldConfiguration: TunnelConfiguration, peersUpdates: [AppIntentsPeer], mergeChanges: Bool) throws -> TunnelConfiguration { + var peers = oldConfiguration.peers + + for peerUpdate in peersUpdates { + let peerIndex: Array.Index + if let foundIndex = peers.firstIndex(where: { $0.publicKey.base64Key == peerUpdate.publicKey }) { + peerIndex = foundIndex + if mergeChanges == false { + peers[peerIndex] = PeerConfiguration(publicKey: peers[peerIndex].publicKey) + } + } else { + wg_log(.debug, message: "Failed to find peer \(peerUpdate.publicKey) in tunnel with name \(tunnelName). Adding it.") + + guard let pubKeyEncoded = PublicKey(base64Key: peerUpdate.publicKey) else { + throw AppIntentConfigurationUpdateError.malformedPublicKey(key: peerUpdate.publicKey) + } + let newPeerConfig = PeerConfiguration(publicKey: pubKeyEncoded) + peerIndex = peers.endIndex + peers.append(newPeerConfig) + } + + if let endpointString = peerUpdate.endpoint { + if let newEntpoint = Endpoint(from: endpointString) { + peers[peerIndex].endpoint = newEntpoint + } else { + wg_log(.debug, message: "Failed to convert \(endpointString) to Endpoint") + } + } + } + + let newConfiguration = TunnelConfiguration(name: oldConfiguration.name, interface: oldConfiguration.interface, peers: peers) + return newConfiguration + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct AppIntentsPeerOptionsProvider: DynamicOptionsProvider { + + func results() async throws -> ItemCollection { + // The error thrown here is not displayed correctly to the user. A Feedback + // has been opened (FB12098463). + throw AppIntentConfigurationUpdateError.peerOptionsUnavailable + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +enum AppIntentConfigurationUpdateError: Swift.Error, CustomLocalizedStringResourceConvertible { + case wrongTunnel(name: String) + case missingConfiguration + case peerOptionsUnavailable + case missingPeerParameter + case malformedPublicKey(key: String) + + var localizedStringResource: LocalizedStringResource { + switch self { + case .wrongTunnel(let name): + return LocalizedStringResource("wireguardAppIntentsWrongTunnelError \(name)", table: "AppIntents") + case .missingConfiguration: + return LocalizedStringResource("wireguardAppIntentsMissingConfigurationError", table: "AppIntents") + case .peerOptionsUnavailable: + return LocalizedStringResource("updateTunnelConfigurationIntentPeerOptionsUnavailableError", table: "AppIntents") + case .missingPeerParameter: + return LocalizedStringResource("updateTunnelConfigurationIntentMissingPeerParameterError", table: "AppIntents") + case .malformedPublicKey(let malformedKey): + return LocalizedStringResource("updateTunnelConfigurationIntentMalformedPublicKeyError \(malformedKey)", table: "AppIntents") + } + } +} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index ad1ef98da..119d25a1f 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -207,6 +207,7 @@ 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; + A6E361FA29D9821200FFF234 /* UpdateTunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */; }; A6E361FC29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */; }; A6E361FE29D9B18C00FFF234 /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; /* End PBXBuildFile section */ @@ -444,6 +445,7 @@ 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseError+WireGuardAppError.swift"; sourceTree = ""; }; A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = ""; }; A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = ""; }; + A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTunnelConfiguration.swift; sourceTree = ""; }; A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildPeerConfigurationUpdate.swift; sourceTree = ""; }; A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -823,6 +825,7 @@ A625F04C29C4C627005EF23D /* WireguardAppIntents */ = { isa = PBXGroup; children = ( + A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */, A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */, A625F05029C4C627005EF23D /* GetPeers.swift */, A6E361F729D8758500FFF234 /* AppIntents.strings */, @@ -1427,6 +1430,7 @@ 6FF3527221C2616C0008484E /* ringlogger.c in Sources */, 6F0F44CB222D55FD00B0FF04 /* EditableTextCell.swift in Sources */, 585B105E2577E293004F691E /* PeerConfiguration.swift in Sources */, + A6E361FA29D9821200FFF234 /* UpdateTunnelConfiguration.swift in Sources */, 6FF3527321C2616C0008484E /* Logger.swift in Sources */, 6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */, 585B108E2577E294004F691E /* x25519.c in Sources */, From 97bf1c1309f8c1c2a963ffa964ba699031e9ede7 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 12 Apr 2023 00:05:14 +0200 Subject: [PATCH 21/27] WireguardApp: macOS: Add App Intents to macOS app Signed-off-by: Alessio Nossa --- Sources/WireGuardApp/UI/macOS/AppDelegate.swift | 5 +++++ WireGuard.xcodeproj/project.pbxproj | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/Sources/WireGuardApp/UI/macOS/AppDelegate.swift b/Sources/WireGuardApp/UI/macOS/AppDelegate.swift index f1ed4cd31..38950ed98 100644 --- a/Sources/WireGuardApp/UI/macOS/AppDelegate.swift +++ b/Sources/WireGuardApp/UI/macOS/AppDelegate.swift @@ -3,6 +3,7 @@ import Cocoa import ServiceManagement +import AppIntents @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @@ -58,6 +59,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.tunnelsTracker = tunnelsTracker self.statusItemController = statusItemController + if #available(macOS 13.0, *) { + AppDependencyManager.shared.add(dependency: tunnelsManager) + } + if !isLaunchedAtLogin { self.showManageTunnelsWindow(completion: nil) } diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 119d25a1f..0caa8f3d6 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -205,6 +205,11 @@ 6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; }; 6FFA5DA42197085D0001E2F7 /* ActivateOnDemandOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandOption.swift */; }; 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFACD1E21E4D89600E9A2A5 /* ParseError+WireGuardAppError.swift */; }; + A25DF37029E60E870094E89B /* BuildPeerConfigurationUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */; }; + A25DF37129E60E8C0094E89B /* UpdateTunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */; }; + A25DF37229E60E8F0094E89B /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; + A25DF37329E60E930094E89B /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; + A25DF37429E60E960094E89B /* TunnelsOptionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */; }; A625F05529C4C627005EF23D /* GetPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A625F05029C4C627005EF23D /* GetPeers.swift */; }; A6E361F829D8758500FFF234 /* AppIntents.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6E361F729D8758500FFF234 /* AppIntents.strings */; }; A6E361FA29D9821200FFF234 /* UpdateTunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */; }; @@ -1100,6 +1105,7 @@ files = ( 6FB1BD6221D2607E00A991BF /* Assets.xcassets in Resources */, 6F70E20F221058E1008BDFB4 /* InfoPlist.strings in Resources */, + A25DF37329E60E930094E89B /* AppIntents.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1328,6 +1334,7 @@ 6FB1BDD121D50F5300A991BF /* ZipImporter.swift in Sources */, 6FB1BDD221D50F5300A991BF /* ZipExporter.swift in Sources */, 585B10642577E294004F691E /* DNSServer.swift in Sources */, + A25DF37129E60E8C0094E89B /* UpdateTunnelConfiguration.swift in Sources */, 585B108C2577E294004F691E /* Endpoint.swift in Sources */, 6FBA104621D7EBFA0051C35F /* TunnelsListTableViewController.swift in Sources */, 6FB1BDD321D50F5300A991BF /* ZipArchive.swift in Sources */, @@ -1365,11 +1372,13 @@ 6FE3661D21F64F6B00F78C7D /* ConfTextColorTheme.swift in Sources */, 6F3E02E9228000F6001FE7E3 /* MainMenu.swift in Sources */, 5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */, + A25DF37229E60E8F0094E89B /* GetPeers.swift in Sources */, 6FB1BDBE21D50F0200A991BF /* Logger.swift in Sources */, 6F6483E7229293300075BA15 /* LaunchedAtLoginDetector.swift in Sources */, 6FB1BDBF21D50F0200A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */, 6FADE96C2254B8C300B838A4 /* UnusableTunnelDetailViewController.swift in Sources */, 6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */, + A25DF37029E60E870094E89B /* BuildPeerConfigurationUpdate.swift in Sources */, 6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */, 6F1075642258AE9800D78929 /* DeleteTunnelsConfirmationAlert.swift in Sources */, 6FBA101821D656000051C35F /* StatusMenu.swift in Sources */, @@ -1380,6 +1389,7 @@ 6FBA104021D6B7040051C35F /* ErrorPresenterProtocol.swift in Sources */, 6FCD99AA21E0E14700BA4C82 /* ButtonedDetailViewController.swift in Sources */, 6FBA104321D6BC250051C35F /* ErrorPresenter.swift in Sources */, + A25DF37429E60E960094E89B /* TunnelsOptionsProvider.swift in Sources */, 6F2449E8226587B90047B9E9 /* MacAppStoreUpdateDetector.swift in Sources */, 585B105C2577E293004F691E /* InterfaceConfiguration.swift in Sources */, 6F907C9D224663A2003CED21 /* LogViewHelper.swift in Sources */, From 7abdf6eaf2ffd3c90a2d5fa6606777b8e18ea324 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:12:14 +0100 Subject: [PATCH 22/27] Fix return value of AppIntents in iOS 17 Signed-off-by: Alessio Nossa --- Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift | 2 +- Sources/WireguardAppIntents/GetPeers.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift index d6c003289..090e52a5a 100644 --- a/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift +++ b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift @@ -23,7 +23,7 @@ struct BuildPeerConfigurationUpdate: AppIntent { ) var endpoint: String - func perform() async throws -> some IntentResult { + func perform() async throws -> some IntentResult & ReturnsValue { let peerConfigurationUpdate = AppIntentsPeer() peerConfigurationUpdate.publicKey = publicKey peerConfigurationUpdate.endpoint = endpoint diff --git a/Sources/WireguardAppIntents/GetPeers.swift b/Sources/WireguardAppIntents/GetPeers.swift index ce6849e3f..00e539910 100644 --- a/Sources/WireguardAppIntents/GetPeers.swift +++ b/Sources/WireguardAppIntents/GetPeers.swift @@ -21,7 +21,7 @@ struct GetPeers: AppIntent { @Dependency var tunnelsManager: TunnelsManager - func perform() async throws -> some ReturnsValue { + func perform() async throws -> some IntentResult & ReturnsValue<[String]> { guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { throw GetPeersIntentError.wrongTunnel(name: tunnelName) } From 56c4d6cc4dce69ee8bdc613078a1d284480e953b Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:16:19 +0100 Subject: [PATCH 23/27] Remove missing peers error in UpdateTunnelConfiguration Intent Signed-off-by: Alessio Nossa --- Sources/WireguardAppIntents/AppIntents.strings | 1 - Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index 1c2064ea7..cfc183b2a 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -20,7 +20,6 @@ "updateTunnelConfigurationIntentSummary ${tunnelName}" = "Update ${tunnelName} configuration"; "updateTunnelConfigurationIntentPeerOptionsUnavailableError" = "Use the output of \"Build Peer Configuration\" action to update tunnel configuration."; -"updateTunnelConfigurationIntentMissingPeerParameterError" = "Peer parameter value is missing"; "updateTunnelConfigurationIntentMalformedPublicKeyError %@" = "The key \"%1$@\" is not a valid Public Key encoded in Base64 format."; // Build Peer Configuration diff --git a/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift b/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift index 51fc605c6..68e88fae2 100644 --- a/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift +++ b/Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift @@ -33,7 +33,7 @@ struct UpdateTunnelConfiguration: AppIntent { var tunnelsManager: TunnelsManager func perform() async throws -> some IntentResult { - guard let peers else { throw AppIntentConfigurationUpdateError.missingPeerParameter } + let peers = peers ?? [] guard let tunnelContainer = tunnelsManager.tunnel(named: tunnelName) else { throw AppIntentConfigurationUpdateError.wrongTunnel(name: tunnelName) @@ -114,7 +114,6 @@ enum AppIntentConfigurationUpdateError: Swift.Error, CustomLocalizedStringResour case wrongTunnel(name: String) case missingConfiguration case peerOptionsUnavailable - case missingPeerParameter case malformedPublicKey(key: String) var localizedStringResource: LocalizedStringResource { @@ -125,8 +124,6 @@ enum AppIntentConfigurationUpdateError: Swift.Error, CustomLocalizedStringResour return LocalizedStringResource("wireguardAppIntentsMissingConfigurationError", table: "AppIntents") case .peerOptionsUnavailable: return LocalizedStringResource("updateTunnelConfigurationIntentPeerOptionsUnavailableError", table: "AppIntents") - case .missingPeerParameter: - return LocalizedStringResource("updateTunnelConfigurationIntentMissingPeerParameterError", table: "AppIntents") case .malformedPublicKey(let malformedKey): return LocalizedStringResource("updateTunnelConfigurationIntentMalformedPublicKeyError \(malformedKey)", table: "AppIntents") } From 7da272a421039fc7f967a3a71787a55904bf8cac Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:19:52 +0100 Subject: [PATCH 24/27] Rename constant to satisfy SwiftLint Signed-off-by: Alessio Nossa --- .../WireguardAppIntents/BuildPeerConfigurationUpdate.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift index 090e52a5a..d5f8cbfdd 100644 --- a/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift +++ b/Sources/WireguardAppIntents/BuildPeerConfigurationUpdate.swift @@ -3,8 +3,6 @@ import AppIntents -let kEndpointConfigurationUpdateDictionaryKey = "Endpoint" - @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) struct BuildPeerConfigurationUpdate: AppIntent { @@ -40,6 +38,8 @@ struct BuildPeerConfigurationUpdate: AppIntent { @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) struct AppIntentsPeer: TransientAppEntity { + + static let kEndpointConfigUpdateDictionaryKey = "Endpoint" static var typeDisplayRepresentation = TypeDisplayRepresentation( name: LocalizedStringResource("peerConfigurationUpdateEntityName", table: "AppIntents") @@ -60,7 +60,7 @@ struct AppIntentsPeer: TransientAppEntity { dictionary[publicKey] = [:] if let endpoint { - dictionary[publicKey]?.updateValue(endpoint, forKey: kEndpointConfigurationUpdateDictionaryKey) + dictionary[publicKey]?.updateValue(endpoint, forKey: Self.kEndpointConfigUpdateDictionaryKey) } let jsonData: Data From 06ed6e91aded7bf572f0f76ff619a9daa7f669f3 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:20:56 +0100 Subject: [PATCH 25/27] Update AppIntents Strings Signed-off-by: Alessio Nossa --- Sources/WireguardAppIntents/AppIntents.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings index cfc183b2a..e799409d1 100644 --- a/Sources/WireguardAppIntents/AppIntents.strings +++ b/Sources/WireguardAppIntents/AppIntents.strings @@ -19,12 +19,12 @@ "updateTunnelConfigurationIntentMergeParameterTitle" = "Merge configuration"; "updateTunnelConfigurationIntentSummary ${tunnelName}" = "Update ${tunnelName} configuration"; -"updateTunnelConfigurationIntentPeerOptionsUnavailableError" = "Use the output of \"Build Peer Configuration\" action to update tunnel configuration."; +"updateTunnelConfigurationIntentPeerOptionsUnavailableError" = "Use the output of \"Build Peer Configuration\" action to update tunnel configuration. To update multiple peers at once, you can use the \"Add to Variable\" action and pass the resulting Variable in this field."; "updateTunnelConfigurationIntentMalformedPublicKeyError %@" = "The key \"%1$@\" is not a valid Public Key encoded in Base64 format."; // Build Peer Configuration "buildPeerConfigurationUpdateIntentName" = "Build Peer Configuration"; -"buildPeerConfigurationUpdateIntentDescription" = ""; +"buildPeerConfigurationUpdateIntentDescription" = "Build an item that contains the informations needed to update an peer's configuration."; "buildPeerConfigurationUpdateIntentSummary ${publicKey}" = "Build configuration for peer ${publicKey}"; "buildPeerConfigurationUpdateIntentPublicKeyParameterTitle" = "Peer Public Key"; "buildPeerConfigurationUpdateIntentEndpointParameterTitle" = "Endpoint"; From 8a2a4ebd9fcef6eb37ceab687e455d18aaaf62d2 Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:24:09 +0100 Subject: [PATCH 26/27] Add backwards compatibility of GetPeers wit SiriKit version Signed-off-by: Alessio Nossa --- Sources/WireguardAppIntents/GetPeers.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/WireguardAppIntents/GetPeers.swift b/Sources/WireguardAppIntents/GetPeers.swift index 00e539910..fe6ba48f8 100644 --- a/Sources/WireguardAppIntents/GetPeers.swift +++ b/Sources/WireguardAppIntents/GetPeers.swift @@ -5,7 +5,9 @@ import Foundation import AppIntents @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -struct GetPeers: AppIntent { +struct GetPeers: AppIntent, CustomIntentMigratedAppIntent { + + static var intentClassName: String = "GetPeersIntent" static var title = LocalizedStringResource("getPeersIntentName", table: "AppIntents") static var description = IntentDescription( From 2f99f5c78171e53da2015d0786293ebc1b39c26c Mon Sep 17 00:00:00 2001 From: Alessio Nossa Date: Wed, 28 Feb 2024 00:26:10 +0100 Subject: [PATCH 27/27] Remove backward compatibility of GetPeers with SiriKit version Signed-off-by: Alessio Nossa --- Sources/WireguardAppIntents/GetPeers.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/WireguardAppIntents/GetPeers.swift b/Sources/WireguardAppIntents/GetPeers.swift index fe6ba48f8..00e539910 100644 --- a/Sources/WireguardAppIntents/GetPeers.swift +++ b/Sources/WireguardAppIntents/GetPeers.swift @@ -5,9 +5,7 @@ import Foundation import AppIntents @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -struct GetPeers: AppIntent, CustomIntentMigratedAppIntent { - - static var intentClassName: String = "GetPeersIntent" +struct GetPeers: AppIntent { static var title = LocalizedStringResource("getPeersIntentName", table: "AppIntents") static var description = IntentDescription(