aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlessio Nossa <alessio.nossa@gmail.com>2023-04-11 23:42:09 +0200
committerAlessio Nossa <alessio.nossa@gmail.com>2023-04-12 00:44:02 +0200
commitee035362ece471b5a23e1d4b2aec862e5fe5ca83 (patch)
treed6fa7123f5202f2801799a3ec3fd79f8ef5a3cc4
parentImplement BuildPeerConfigurationUpdate App Intent (diff)
downloadwireguard-apple-ee035362ece471b5a23e1d4b2aec862e5fe5ca83.tar.xz
wireguard-apple-ee035362ece471b5a23e1d4b2aec862e5fe5ca83.zip
Implement UpdateTunnelConfiguration App Intent
Signed-off-by: Alessio Nossa <alessio.nossa@gmail.com>
-rw-r--r--Sources/WireguardAppIntents/AppIntents.strings12
-rw-r--r--Sources/WireguardAppIntents/UpdateTunnelConfiguration.swift134
-rw-r--r--WireGuard.xcodeproj/project.pbxproj4
3 files changed, 150 insertions, 0 deletions
diff --git a/Sources/WireguardAppIntents/AppIntents.strings b/Sources/WireguardAppIntents/AppIntents.strings
index 9ebdc8e..1c2064e 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 0000000..51fc605
--- /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<PeerConfiguration>.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<AppIntentsPeer> {
+ // 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 ad1ef98..119d25a 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 = "<group>"; };
A625F05029C4C627005EF23D /* GetPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPeers.swift; sourceTree = "<group>"; };
A6E361F729D8758500FFF234 /* AppIntents.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = AppIntents.strings; sourceTree = "<group>"; };
+ A6E361F929D9821100FFF234 /* UpdateTunnelConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTunnelConfiguration.swift; sourceTree = "<group>"; };
A6E361FB29D9AEEA00FFF234 /* BuildPeerConfigurationUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildPeerConfigurationUpdate.swift; sourceTree = "<group>"; };
A6E361FD29D9B18C00FFF234 /* TunnelsOptionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelsOptionsProvider.swift; sourceTree = "<group>"; };
/* 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 */,