From 75b28c90cebd0441dfa4673325a3e17a21eb59cd Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Mon, 15 Jan 2024 11:30:25 +0200 Subject: [PATCH 01/16] Extract dart connection status --- darwin/Classes/ConnectionStatus.swift | 25 ++++++++++++++++ darwin/Classes/ConnectionStatusObserver.swift | 29 +++++-------------- darwin/Classes/WireguardDartPlugin.swift | 11 +------ example/macos/Podfile.lock | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- lib/wireguard_dart_method_channel.dart | 12 ++++---- 7 files changed, 42 insertions(+), 41 deletions(-) create mode 100644 darwin/Classes/ConnectionStatus.swift diff --git a/darwin/Classes/ConnectionStatus.swift b/darwin/Classes/ConnectionStatus.swift new file mode 100644 index 0000000..f0b092d --- /dev/null +++ b/darwin/Classes/ConnectionStatus.swift @@ -0,0 +1,25 @@ +import Foundation +import NetworkExtension + +/// ConnectionStatus returned to Dart +enum ConnectionStatus: String { + case connected + case disconnected + case connecting + case disconnecting + case unknown + + static func fromNEVPNStatus(ns: NEVPNStatus) -> ConnectionStatus { + switch ns { + case .connected: return ConnectionStatus.connected + case .disconnected: return ConnectionStatus.disconnected + case .connecting: return ConnectionStatus.connecting + case .disconnecting: return ConnectionStatus.disconnecting + default: return ConnectionStatus.unknown + } + } + + func string() -> String { + return self.rawValue + } +} diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index 7125da9..f6feda6 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -5,7 +5,7 @@ import WireGuardKit public class ConnectionStatusObserver: NSObject, FlutterStreamHandler { - private var _sink: FlutterEventSink? + private var _eventSink: FlutterEventSink? private var _vpnManager: NETunnelProviderManager private var pIsRunning: Bool = false @@ -18,31 +18,16 @@ public class ConnectionStatusObserver: NSObject, FlutterStreamHandler { } public func _statusChanged(_: Notification?) { - guard let sink = _sink else { - return - } - let status = _vpnManager.connection.status - let mappedStatus: Dictionary = { - switch status { - case .connected: - return ["status": "connected"] - case .disconnected: - return ["status": "connected"] - case .connecting: - return ["status": "connecting"] - case .disconnecting: - return ["status": "disconnecting"] - default: - return ["status": "unknown"] - } - }() - sink(mappedStatus) + guard let _eventSink = _eventSink else { + return + } + _eventSink(ConnectionStatus.fromNEVPNStatus(ns: _vpnManager.connection.status).string()) } public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - _sink = events + self._eventSink = events if !pIsRunning { NotificationCenter.default.addObserver( @@ -66,7 +51,7 @@ public class ConnectionStatusObserver: NSObject, FlutterStreamHandler { NotificationCenter.default.removeObserver(self) - _sink = nil + _eventSink = nil return nil } diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index adb38fd..9b4f617 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -127,16 +127,7 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { return } Task { - let mappedStatus: String = { - switch vpnStatus { - case .connected: return "connected" - case .disconnected:return "disconnected" - case .connecting: return "connecting" - case .disconnecting: return "disconnecting" - default: return "unknown" - } - }() - result(["status": mappedStatus]) + result(["status": ConnectionStatus.fromNEVPNStatus(ns: vpnStatus).string()]) } default: result(FlutterMethodNotImplemented) diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 2e7985d..c8fba62 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -27,4 +27,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: be01cccb06a368ce7b4626ad8fc3db0759a91741 -COCOAPODS: 1.12.0 +COCOAPODS: 1.12.1 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 5ea6e33..17824c3 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -268,7 +268,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1410; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a70ed15..9f1a834 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ ('generateKeyPair') ?? {}; if (!result.containsKey('publicKey') || !result.containsKey('privateKey')) { throw StateError('Could not generate keypair'); - }; + } return KeyPair(result['publicKey']!, result['privateKey']!); } @@ -54,11 +54,11 @@ class MethodChannelWireguardDart extends WireguardDartPlatform { @override Stream onStatusChanged() { return statusChannel.receiveBroadcastStream().map((event) { - var statusStr = ""; - if (event is Map) { - statusStr = event['status']; - } - var status = ConnectionStatus.fromString(statusStr); + var statusStr = ""; + if (event is Map) { + statusStr = event['status']; + } + var status = ConnectionStatus.fromString(statusStr); return ConnectionStatusChanged(status); }).cast(); } From ae0a22253de3220be33f3f972cd42b10bbe1b0af Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Mon, 15 Jan 2024 12:43:20 +0200 Subject: [PATCH 02/16] Bump plugin_platform_interface --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e67d950..c8e1543 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: flutter: sdk: flutter - plugin_platform_interface: ^2.0.2 + plugin_platform_interface: ^2.1.8 dev_dependencies: flutter_test: From 102ac58a5c9ad66cfc216323b74f391ddc13113c Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Tue, 16 Jan 2024 14:22:10 +0200 Subject: [PATCH 03/16] Match bundle ID with network extension bundle ID --- example/lib/main.dart | 5 ++++- example/macos/Podfile.lock | 2 +- example/macos/Runner.xcodeproj/project.pbxproj | 18 +++++++++--------- example/macos/Runner/Base.lproj/MainMenu.xib | 10 +++++----- example/test/widget_test.dart | 3 +-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 1baa533..2a1a8be 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,6 +7,9 @@ import 'package:flutter/services.dart'; import 'package:wireguard_dart/connection_status.dart'; import 'package:wireguard_dart/wireguard_dart.dart'; +const tunBundleId = "network.mysterium.wireguardDartExample.tun"; +const winSvcName = "Wireguard_Dart_Example"; + void main() { runApp(const MyApp()); } @@ -86,7 +89,7 @@ class _MyAppState extends State { void setupTunnel() async { try { - await _wireguardDartPlugin.setupTunnel(bundleId: "mysterium", win32ServiceName: "MysteriumVPN_Wireguard"); + await _wireguardDartPlugin.setupTunnel(bundleId: tunBundleId, win32ServiceName: winSvcName); debugPrint("Setup tunnel success"); } catch (e) { developer.log( diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index c8fba62..0a0f81f 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -27,4 +27,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: be01cccb06a368ce7b4626ad8fc3db0759a91741 -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 17824c3..700e77e 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -494,7 +494,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -578,7 +578,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -625,7 +625,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -726,11 +726,11 @@ "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.WireguardExtension; + PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.tun; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -766,10 +766,10 @@ "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.WireguardExtension; + PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.tun; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -805,10 +805,10 @@ "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.WireguardExtension; + PRODUCT_BUNDLE_IDENTIFIER = network.mysterium.wireguardDartExample.tun; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/example/macos/Runner/Base.lproj/MainMenu.xib b/example/macos/Runner/Base.lproj/MainMenu.xib index 80e867a..d4bebdb 100644 --- a/example/macos/Runner/Base.lproj/MainMenu.xib +++ b/example/macos/Runner/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,7 @@ - + @@ -330,10 +330,10 @@ - + - + diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 771a917..53fa51a 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -18,8 +18,7 @@ void main() { // Verify that platform version is retrieved. expect( find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data!.startsWith('Running on:'), + (Widget widget) => widget is Text && widget.data!.startsWith('Running on:'), ), findsOneWidget, ); From e909b0c6e698a9fc3673a1fb87be7db7bb40bdd5 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Tue, 16 Jan 2024 14:22:50 +0200 Subject: [PATCH 04/16] darwin: avoid crash on native init --- darwin/Classes/WireguardDartPlugin.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index 9b4f617..6911de8 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -46,6 +46,8 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { + case "nativeInit": + result("") case "generateKeyPair": let privateKey = PrivateKey() let privateKeyResponse: [String: Any] = [ From 16f6f61e03c87c9bd52e27d5cd1b1e9b0bcf2035 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Tue, 16 Jan 2024 15:17:56 +0200 Subject: [PATCH 05/16] darwin: search vpn tunnel by bundle ID rather than name --- darwin/Classes/WireguardDartPlugin.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index 6911de8..2bec96b 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -138,13 +138,13 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { func setupProviderManager(bundleId: String) async throws -> NETunnelProviderManager { let mgrs = await fetchManagers() - let existingMgr = mgrs.first(where: { $0.localizedDescription == "Mysterium VPN" }) + let existingMgr = mgrs.first(where: { ($0.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == bundleId }) let mgr = existingMgr ?? NETunnelProviderManager() mgr.localizedDescription = "Mysterium VPN" let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = bundleId - proto.serverAddress = "127.0.0.1" // Fake address + proto.serverAddress = "" // must be non-null mgr.protocolConfiguration = proto mgr.isEnabled = true From f187a67a4280a1eca8da2a34087d81d378275088 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Wed, 17 Jan 2024 11:28:34 +0200 Subject: [PATCH 06/16] Require tunnelName in tunnel setup --- darwin/Classes/FlutterError.swift | 11 +++++++++++ darwin/Classes/WireguardDartPlugin.swift | 7 ++++--- example/lib/main.dart | 2 +- lib/wireguard_dart.dart | 4 ++-- lib/wireguard_dart_method_channel.dart | 3 ++- lib/wireguard_dart_platform_interface.dart | 2 +- test/wireguard_dart_test.dart | 3 +-- 7 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 darwin/Classes/FlutterError.swift diff --git a/darwin/Classes/FlutterError.swift b/darwin/Classes/FlutterError.swift new file mode 100644 index 0000000..55ed29c --- /dev/null +++ b/darwin/Classes/FlutterError.swift @@ -0,0 +1,11 @@ +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform") +#endif + +func nativeFlutterError(message: String) -> FlutterError { + return FlutterError(code: "NATIVE_ERR", message: message, details: nil) +} diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index 2bec96b..1c535f6 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -62,13 +62,14 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { return } guard let bundleId = args["bundleId"] as? String, !bundleId.isEmpty else { - result(FlutterError.init(code: "NATIVE_ERR", message: "required argument: 'bundleId'", details: nil)) + guard let tunnelName = args["tunnelName"] as? String, !tunnelName.isEmpty else { + result(nativeFlutterError(message: "required argument: 'tunnelName'")) return } - Self.logger.debug("Tunnel bundle ID: \(bundleId)") + Self.logger.debug("Tunnel bundle ID: \(bundleId), name: \(tunnelName)") Task { do { - vpnManager = try await setupProviderManager(bundleId: bundleId) + vpnManager = try await setupProviderManager(bundleId: bundleId, tunnelName: tunnelName) statusChannel!.setStreamHandler(ConnectionStatusObserver(vpnManager: vpnManager!)) Self.logger.debug("Tunnel setup OK") result("") diff --git a/example/lib/main.dart b/example/lib/main.dart index 2a1a8be..4ffd821 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -89,7 +89,7 @@ class _MyAppState extends State { void setupTunnel() async { try { - await _wireguardDartPlugin.setupTunnel(bundleId: tunBundleId, win32ServiceName: winSvcName); + await _wireguardDartPlugin.setupTunnel(bundleId: tunBundleId, tunnelName: "Wiregard Dart (example)", win32ServiceName: winSvcName); debugPrint("Setup tunnel success"); } catch (e) { developer.log( diff --git a/lib/wireguard_dart.dart b/lib/wireguard_dart.dart index 182cd20..b8bb526 100644 --- a/lib/wireguard_dart.dart +++ b/lib/wireguard_dart.dart @@ -12,8 +12,8 @@ class WireguardDart { return WireguardDartPlatform.instance.nativeInit(); } - Future setupTunnel({required String bundleId, String? win32ServiceName}) { - return WireguardDartPlatform.instance.setupTunnel(bundleId: bundleId, win32ServiceName: win32ServiceName); + Future setupTunnel({required String bundleId, required String tunnelName, String? win32ServiceName}) { + return WireguardDartPlatform.instance.setupTunnel(bundleId: bundleId, tunnelName: tunnelName, win32ServiceName: win32ServiceName); } Future connect({required String cfg}) { diff --git a/lib/wireguard_dart_method_channel.dart b/lib/wireguard_dart_method_channel.dart index d516e69..e773c50 100644 --- a/lib/wireguard_dart_method_channel.dart +++ b/lib/wireguard_dart_method_channel.dart @@ -27,9 +27,10 @@ class MethodChannelWireguardDart extends WireguardDartPlatform { } @override - Future setupTunnel({required String bundleId, String? win32ServiceName}) async { + Future setupTunnel({required String bundleId, required String tunnelName, String? win32ServiceName}) async { var args = { 'bundleId': bundleId, + 'tunnelName': tunnelName, if (win32ServiceName != null) 'win32ServiceName': win32ServiceName, }; await methodChannel.invokeMethod('setupTunnel', args); diff --git a/lib/wireguard_dart_platform_interface.dart b/lib/wireguard_dart_platform_interface.dart index d0636b7..9073236 100644 --- a/lib/wireguard_dart_platform_interface.dart +++ b/lib/wireguard_dart_platform_interface.dart @@ -33,7 +33,7 @@ abstract class WireguardDartPlatform extends PlatformInterface { throw UnimplementedError('nativeInit() has not been implemented'); } - Future setupTunnel({required String bundleId, String? win32ServiceName}) { + Future setupTunnel({required String bundleId, required String tunnelName, String? win32ServiceName}) { throw UnimplementedError('setupTunnel() has not been implemented'); } diff --git a/test/wireguard_dart_test.dart b/test/wireguard_dart_test.dart index 1c03eec..969a387 100644 --- a/test/wireguard_dart_test.dart +++ b/test/wireguard_dart_test.dart @@ -7,12 +7,11 @@ import 'package:wireguard_dart/wireguard_dart_platform_interface.dart'; import 'package:wireguard_dart/wireguard_dart.dart'; class MockWireguardDartPlatform with MockPlatformInterfaceMixin implements WireguardDartPlatform { - @override Future nativeInit() => Future.value(); @override - Future setupTunnel({required String bundleId, String? win32ServiceName}) => Future.value(); + Future setupTunnel({required String bundleId, required String tunnelName, String? win32ServiceName}) => Future.value(); @override Future connect({required String cfg}) => Future.value(); From 4e9df499bcc0069a50ea6d48f2efa38136227cee Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Wed, 17 Jan 2024 11:29:45 +0200 Subject: [PATCH 07/16] darwin: code cleanup --- darwin/Classes/ConnectionStatusObserver.swift | 10 +++- darwin/Classes/WireguardDartPlugin.swift | 56 ++++++------------- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index f6feda6..8eae984 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -1,5 +1,13 @@ -import Cocoa +#if os(iOS) +import Flutter +import UIKit +#elseif os(macOS) import FlutterMacOS +import Cocoa +#else +#error("Unsupported platform") +#endif + import NetworkExtension import WireGuardKit diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index 1c535f6..e957d8a 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -58,10 +58,13 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { case "setupTunnel": Self.logger.debug("handle setupTunnel") guard let args = call.arguments as? Dictionary, args["bundleId"] != nil else { - result(FlutterError.init(code: "NATIVE_ERR", message: "required argument: 'bundleId'", details: nil)) + result(nativeFlutterError(message: "required argument: 'bundleId'")) return } guard let bundleId = args["bundleId"] as? String, !bundleId.isEmpty else { + result(nativeFlutterError(message: "required argument: 'bundleId'")) + return + } guard let tunnelName = args["tunnelName"] as? String, !tunnelName.isEmpty else { result(nativeFlutterError(message: "required argument: 'tunnelName'")) return @@ -75,9 +78,7 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { result("") } catch { Self.logger.error("Tunnel setup ERROR: \(error)") - result( - FlutterError.init( - code: "NATIVE_ERR", message: "could not setup VPN tunnel: \(error)", details: nil)) + result(nativeFlutterError(message: "could not setup VPN tunnel: \(error)")) return } } @@ -89,12 +90,12 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { cfg = argCfg } else { Self.logger.error("Required argument 'cfg' not provided") - result(FlutterError.init(code: "NATIVE_ERR", message: "required argument: 'cfg'", details: nil)) + result(nativeFlutterError(message: "required argument: 'cfg'")) return } guard let mgr = vpnManager else { Self.logger.error("Tunnel not initialized, missing 'vpnManager'") - result(FlutterError.init(code: "NATIVE_ERR", message: "tunnel not initialized, missing 'vpnManager'", details: nil)) + result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Self.logger.debug("Connection configuration: \(cfg)") @@ -107,15 +108,13 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { result("") } catch { Self.logger.error("Start VPN tunnel ERROR: \(error)") - result( - FlutterError.init( - code: "NATIVE_ERR", message: "could not start VPN tunnel: \(error)", details: nil)) + result(nativeFlutterError(message: "could not start VPN tunnel: \(error)")) } } case "disconnect": guard let mgr = vpnManager else { Self.logger.error("Tunnel not initialized, missing 'vpnManager'") - result(FlutterError.init(code: "NATIVE_ERR", message: "tunnel not initialized, missing 'vpnManager'", details: nil)) + result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Task { @@ -126,7 +125,7 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { case "status": guard let mgr = vpnManager else { Self.logger.error("Tunnel not initialized, missing 'vpnManager'") - result(FlutterError.init(code: "NATIVE_ERR", message: "tunnel not initialized, missing 'vpnManager'", details: nil)) + result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Task { @@ -137,42 +136,23 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { } } - func setupProviderManager(bundleId: String) async throws -> NETunnelProviderManager { - let mgrs = await fetchManagers() - let existingMgr = mgrs.first(where: { ($0.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == bundleId }) + func setupProviderManager(bundleId: String, tunnelName: String) async throws -> NETunnelProviderManager { + let mgrs = try await NETunnelProviderManager.loadAllFromPreferences() + let existingMgr = mgrs.first(where: { + ($0.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == bundleId + }) let mgr = existingMgr ?? NETunnelProviderManager() - mgr.localizedDescription = "Mysterium VPN" + mgr.localizedDescription = tunnelName let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = bundleId proto.serverAddress = "" // must be non-null mgr.protocolConfiguration = proto mgr.isEnabled = true - try await saveManager(mgr: mgr) - return mgr - } + try await mgr.saveToPreferences() - func fetchManagers() async -> [NETunnelProviderManager] { - return await withCheckedContinuation { continuation in - NETunnelProviderManager.loadAllFromPreferences { managers, error in - continuation.resume(returning: (managers ?? [])) - } - } + return mgr } - func saveManager(mgr: NETunnelProviderManager) async throws -> Void { - return try await withCheckedThrowingContinuation { continuation in - mgr.saveToPreferences { error in - if let error: Error { - continuation.resume(throwing: error) - } else { - continuation.resume() - } - } - } - } } - - - From fe3e07be357a3aa8c3c1f3e958af3acc41b8a746 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 14:22:44 +0200 Subject: [PATCH 08/16] Return plain status string in status() and statusStream() instead of a map --- darwin/Classes/ConnectionStatusObserver.swift | 3 +++ example/lib/main.dart | 11 +++++++---- lib/wireguard_dart.dart | 4 ++-- lib/wireguard_dart_method_channel.dart | 15 ++++----------- lib/wireguard_dart_platform_interface.dart | 4 ++-- test/wireguard_dart_test.dart | 4 ++-- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index 8eae984..8d5499e 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -63,4 +63,7 @@ public class ConnectionStatusObserver: NSObject, FlutterStreamHandler { return nil } + + Logger.main.debug("VPN status changed: \(newStatus.string())") + eventSink(newStatus.string()) } diff --git a/example/lib/main.dart b/example/lib/main.dart index 4ffd821..74ffd55 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -41,10 +41,12 @@ class _MyAppState extends State { String _platformVersion = 'Unknown'; final _wireguardDartPlugin = WireguardDart(); ConnectionStatus _status = ConnectionStatus.unknown; + late Stream _statusStream; @override void initState() { super.initState(); + _statusStream = _wireguardDartPlugin.statusStream(); initPlatformState(); } @@ -229,12 +231,13 @@ class _MyAppState extends State { ), const SizedBox(height: 20), Text(_status.name), - StreamBuilder( - stream: _wireguardDartPlugin.onStatusChanged(), - builder: (BuildContext context, AsyncSnapshot snapshot) { + StreamBuilder( + initialData: ConnectionStatus.unknown, + stream: _statusStream, + builder: (BuildContext context, AsyncSnapshot snapshot) { // Check if the snapshot has data and is a map containing the 'status' key if (snapshot.hasData) { - return Text(snapshot.data!.status.name); + return Text(snapshot.data!.name); } return const CircularProgressIndicator(); }), diff --git a/lib/wireguard_dart.dart b/lib/wireguard_dart.dart index b8bb526..62b7454 100644 --- a/lib/wireguard_dart.dart +++ b/lib/wireguard_dart.dart @@ -28,7 +28,7 @@ class WireguardDart { return WireguardDartPlatform.instance.status(); } - Stream onStatusChanged() { - return WireguardDartPlatform.instance.onStatusChanged(); + Stream statusStream() { + return WireguardDartPlatform.instance.statusStream(); } } diff --git a/lib/wireguard_dart_method_channel.dart b/lib/wireguard_dart_method_channel.dart index e773c50..e9bc71f 100644 --- a/lib/wireguard_dart_method_channel.dart +++ b/lib/wireguard_dart_method_channel.dart @@ -48,19 +48,12 @@ class MethodChannelWireguardDart extends WireguardDartPlatform { @override Future status() async { - var result = await methodChannel.invokeMapMethod('status') ?? {}; - return ConnectionStatus.fromString(result['status'] ?? ''); + var result = await methodChannel.invokeMethod('status'); + return ConnectionStatus.fromString(result ?? ""); } @override - Stream onStatusChanged() { - return statusChannel.receiveBroadcastStream().map((event) { - var statusStr = ""; - if (event is Map) { - statusStr = event['status']; - } - var status = ConnectionStatus.fromString(statusStr); - return ConnectionStatusChanged(status); - }).cast(); + Stream statusStream() { + return statusChannel.receiveBroadcastStream().distinct().map((val) => ConnectionStatus.fromString(val)); } } diff --git a/lib/wireguard_dart_platform_interface.dart b/lib/wireguard_dart_platform_interface.dart index 9073236..01055d8 100644 --- a/lib/wireguard_dart_platform_interface.dart +++ b/lib/wireguard_dart_platform_interface.dart @@ -49,7 +49,7 @@ abstract class WireguardDartPlatform extends PlatformInterface { throw UnimplementedError('status() has not been implemented'); } - Stream onStatusChanged() { - throw UnimplementedError('onStatusChanged() has not been implemented'); + Stream statusStream() { + throw UnimplementedError('statusStream() has not been implemented'); } } diff --git a/test/wireguard_dart_test.dart b/test/wireguard_dart_test.dart index 969a387..8e3436e 100644 --- a/test/wireguard_dart_test.dart +++ b/test/wireguard_dart_test.dart @@ -28,8 +28,8 @@ class MockWireguardDartPlatform with MockPlatformInterfaceMixin implements Wireg Future status() => Future.value(ConnectionStatus.disconnected); @override - Stream onStatusChanged() { - return Stream.value(ConnectionStatusChanged(ConnectionStatus.disconnected)); + Stream statusStream() { + return Stream.value(ConnectionStatus.disconnected); } } From 6e9d30e66dfa81b637febcb00e7f5e5dbde6e1b6 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 14:24:18 +0200 Subject: [PATCH 09/16] darwin: fix stream handler not registering in time --- .../wireguard_dart/WireguardDartPlugin.kt | 2 +- darwin/Classes/ConnectionStatusObserver.swift | 92 ++++++++----------- darwin/Classes/Logger.swift | 7 ++ darwin/Classes/WireguardDartPlugin.swift | 69 +++++++------- .../PacketTunnelProvider.swift | 4 +- lib/wireguard_dart_method_channel.dart | 4 +- 6 files changed, 82 insertions(+), 96 deletions(-) create mode 100644 darwin/Classes/Logger.swift diff --git a/android/src/main/kotlin/network/mysterium/wireguard_dart/WireguardDartPlugin.kt b/android/src/main/kotlin/network/mysterium/wireguard_dart/WireguardDartPlugin.kt index cf67f0b..7bac73b 100644 --- a/android/src/main/kotlin/network/mysterium/wireguard_dart/WireguardDartPlugin.kt +++ b/android/src/main/kotlin/network/mysterium/wireguard_dart/WireguardDartPlugin.kt @@ -77,7 +77,7 @@ class WireguardDartPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart") - statusChannel = EventChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart.status") + statusChannel = EventChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart/status") statusBroadcaster = ConnectionStatusBroadcaster() statusChannel.setStreamHandler(statusBroadcaster) context = flutterPluginBinding.applicationContext diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index 8d5499e..30f2227 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -10,60 +10,46 @@ import Cocoa import NetworkExtension import WireGuardKit - -public class ConnectionStatusObserver: NSObject, FlutterStreamHandler { - - private var _eventSink: FlutterEventSink? - private var _vpnManager: NETunnelProviderManager - - private var pIsRunning: Bool = false - var isRunning: Bool { - pIsRunning - } - - init(vpnManager: NETunnelProviderManager) { - _vpnManager = vpnManager - } - - public func _statusChanged(_: Notification?) { - guard let _eventSink = _eventSink else { - return - } - _eventSink(ConnectionStatus.fromNEVPNStatus(ns: _vpnManager.connection.status).string()) - } - - public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) - -> FlutterError? - { - self._eventSink = events - - if !pIsRunning { - NotificationCenter.default.addObserver( - forName: NSNotification.Name.NEVPNStatusDidChange, - object: nil, - queue: OperationQueue.main, - using: _statusChanged - ) - } - - pIsRunning = true - - // Send the initial data. - - // No errors. - return nil - } - - public func onCancel(withArguments arguments: Any?) -> FlutterError? { - pIsRunning = false - - NotificationCenter.default.removeObserver(self) - - _eventSink = nil - - return nil - } +import os + +class ConnectionStatusObserver: NSObject, FlutterStreamHandler { + + private var eventSink: FlutterEventSink? + private var isRunning: Bool = false + + public func _statusChanged(n: Notification?) { + guard let conn = n?.object as? NEVPNConnection else { + return + } + guard let eventSink = eventSink else { + return + } + let newStatus = ConnectionStatus.fromNEVPNStatus(ns: conn.status) Logger.main.debug("VPN status changed: \(newStatus.string())") eventSink(newStatus.string()) + } + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + self.eventSink = events + + if !isRunning { + NotificationCenter.default.addObserver( + forName: NSNotification.Name.NEVPNStatusDidChange, + object: nil, + queue: OperationQueue.main, + using: _statusChanged + ) + } + + isRunning = true + return nil + } + + public func onCancel(withArguments arguments: Any?) -> FlutterError? { + isRunning = false + NotificationCenter.default.removeObserver(self) + eventSink = nil + return nil + } } diff --git a/darwin/Classes/Logger.swift b/darwin/Classes/Logger.swift new file mode 100644 index 0000000..aa98176 --- /dev/null +++ b/darwin/Classes/Logger.swift @@ -0,0 +1,7 @@ +import Foundation +import os.log + +public extension Logger { + private static var subsystem = Bundle.main.bundleIdentifier! + static let main = Logger(subsystem: subsystem, category: "main") +} diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index e957d8a..870fd9b 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -13,37 +13,33 @@ import NetworkExtension import os public class WireguardDartPlugin: NSObject, FlutterPlugin { - - private static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: WireguardDartPlugin.self) - ) - + private var vpnManager: NETunnelProviderManager? - private var statusChannel: FlutterEventChannel? - + private var statusChannel: FlutterEventChannel + var vpnStatus: NEVPNStatus { get { return vpnManager?.connection.status ?? NEVPNStatus.invalid } } - + init(registrar: FlutterPluginRegistrar) { - statusChannel = FlutterEventChannel(name: "wireguard_dart.status", binaryMessenger: registrar.messenger) + statusChannel = FlutterEventChannel(name: "wireguard_dart/status", binaryMessenger: registrar.messenger) + statusChannel.setStreamHandler(ConnectionStatusObserver()) } - + public static func register(with registrar: FlutterPluginRegistrar) { - #if os(iOS) +#if os(iOS) let messenger = registrar.messenger() - #else +#else let messenger = registrar.messenger - #endif +#endif let channel = FlutterMethodChannel(name: "wireguard_dart", binaryMessenger: messenger) - + let instance = WireguardDartPlugin(registrar: registrar) registrar.addMethodCallDelegate(instance, channel: channel) } - + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "nativeInit": @@ -56,7 +52,7 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { ] result(privateKeyResponse) case "setupTunnel": - Self.logger.debug("handle setupTunnel") + Logger.main.debug("handle setupTunnel") guard let args = call.arguments as? Dictionary, args["bundleId"] != nil else { result(nativeFlutterError(message: "required argument: 'bundleId'")) return @@ -69,90 +65,89 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { result(nativeFlutterError(message: "required argument: 'tunnelName'")) return } - Self.logger.debug("Tunnel bundle ID: \(bundleId), name: \(tunnelName)") + Logger.main.debug("Tunnel bundle ID: \(bundleId), name: \(tunnelName)") Task { do { vpnManager = try await setupProviderManager(bundleId: bundleId, tunnelName: tunnelName) - statusChannel!.setStreamHandler(ConnectionStatusObserver(vpnManager: vpnManager!)) - Self.logger.debug("Tunnel setup OK") + Logger.main.debug("Tunnel setup OK") result("") } catch { - Self.logger.error("Tunnel setup ERROR: \(error)") + Logger.main.error("Tunnel setup ERROR: \(error)") result(nativeFlutterError(message: "could not setup VPN tunnel: \(error)")) return } } case "connect": - Self.logger.debug("handle connect") + Logger.main.debug("handle connect") let cfg: String if let args = call.arguments as? Dictionary, let argCfg = args["cfg"] as? String { cfg = argCfg } else { - Self.logger.error("Required argument 'cfg' not provided") + Logger.main.error("Required argument 'cfg' not provided") result(nativeFlutterError(message: "required argument: 'cfg'")) return } guard let mgr = vpnManager else { - Self.logger.error("Tunnel not initialized, missing 'vpnManager'") + Logger.main.error("Tunnel not initialized, missing 'vpnManager'") result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } - Self.logger.debug("Connection configuration: \(cfg)") + Logger.main.debug("Connection configuration: \(cfg)") Task { do { try mgr.connection.startVPNTunnel(options: [ "cfg": cfg as NSObject ]) - Self.logger.debug("Start VPN tunnel OK") + Logger.main.debug("Start VPN tunnel OK") result("") } catch { - Self.logger.error("Start VPN tunnel ERROR: \(error)") + Logger.main.error("Start VPN tunnel ERROR: \(error)") result(nativeFlutterError(message: "could not start VPN tunnel: \(error)")) } } case "disconnect": guard let mgr = vpnManager else { - Self.logger.error("Tunnel not initialized, missing 'vpnManager'") + Logger.main.error("Tunnel not initialized, missing 'vpnManager'") result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Task { mgr.connection.stopVPNTunnel() - Self.logger.debug("Stop tunnel OK") + Logger.main.debug("Stop tunnel OK") result("") } case "status": - guard let mgr = vpnManager else { - Self.logger.error("Tunnel not initialized, missing 'vpnManager'") + guard let _ = vpnManager else { + Logger.main.error("Tunnel not initialized, missing 'vpnManager'") result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Task { - result(["status": ConnectionStatus.fromNEVPNStatus(ns: vpnStatus).string()]) + result(ConnectionStatus.fromNEVPNStatus(ns: vpnStatus).string()) } default: result(FlutterMethodNotImplemented) } } - + func setupProviderManager(bundleId: String, tunnelName: String) async throws -> NETunnelProviderManager { let mgrs = try await NETunnelProviderManager.loadAllFromPreferences() let existingMgr = mgrs.first(where: { ($0.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == bundleId }) let mgr = existingMgr ?? NETunnelProviderManager() - + mgr.localizedDescription = tunnelName let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = bundleId proto.serverAddress = "" // must be non-null mgr.protocolConfiguration = proto mgr.isEnabled = true - + try await mgr.saveToPreferences() - + return mgr } - + } diff --git a/example/macos/WireguardExtension/PacketTunnelProvider.swift b/example/macos/WireguardExtension/PacketTunnelProvider.swift index b93ad9b..e560ca8 100644 --- a/example/macos/WireguardExtension/PacketTunnelProvider.swift +++ b/example/macos/WireguardExtension/PacketTunnelProvider.swift @@ -15,7 +15,7 @@ class PacketTunnelProvider: WireGuardTunnelProvider { subsystem: Bundle.main.bundleIdentifier!, category: String(describing: PacketTunnelProvider.self) ) - + private lazy var adapter: WireGuardAdapter = { return WireGuardAdapter(with: self) { logLevel, message in let level: OSLogType @@ -28,7 +28,7 @@ class PacketTunnelProvider: WireGuardTunnelProvider { Self.logger.log(level: level, "\(message)") } }() - + override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { super.startTunnel(options: options, completionHandler: completionHandler) } diff --git a/lib/wireguard_dart_method_channel.dart b/lib/wireguard_dart_method_channel.dart index e9bc71f..b22cf91 100644 --- a/lib/wireguard_dart_method_channel.dart +++ b/lib/wireguard_dart_method_channel.dart @@ -5,12 +5,10 @@ import 'package:wireguard_dart/key_pair.dart'; import 'wireguard_dart_platform_interface.dart'; -/// An implementation of [WireguardDartPlatform] that uses method channels. class MethodChannelWireguardDart extends WireguardDartPlatform { - /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('wireguard_dart'); - final statusChannel = const EventChannel('wireguard_dart.status'); + final statusChannel = const EventChannel('wireguard_dart/status'); @override Future generateKeyPair() async { From a172fe3fcac225a2d856ae849e23ba35a7deeecb Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 14:30:52 +0200 Subject: [PATCH 10/16] Remove release.yml for more fine-grained control over semver/changelog --- .github/workflows/release.yml | 63 ----------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 187faa1..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Release - -on: - pull_request_target: - types: [closed] - -env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - GH_USER: MysteriumTeam - GH_EMAIL: core-services@mysterium.network - -jobs: - release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - token: ${{ env.GH_TOKEN }} - - run: git config --global user.name "${GH_USER}" - - run: git config --global user.email "${GH_EMAIL}" - - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - cache: true - - name: Install dependencies - run: flutter pub get - - name: Determine version number - run: | - VERSION=$(grep 'version: ' pubspec.yaml | awk '{print $2}') - if [[ ${{ github.event.pull_request.merged }} == 'true' ]]; then - PR_TITLE=$(echo ${{ github.event.pull_request.title }} | tr '[:upper:]' '[:lower:]') - if [[ $PR_TITLE == *'[major]'* ]]; then - echo "Merging pull request with [major] in title. Bumping major version." - NEW_VERSION=$(echo $VERSION | awk -F. '{print $1+1".0.0"}') - elif [[ $PR_TITLE == *'[minor]'* ]]; then - echo "Merging pull request with [minor] in title. Bumping minor version." - NEW_VERSION=$(echo $VERSION | awk -F. '{print $1"."$2+1".0"}') - else - echo "Merging pull request. Bumping patch version." - NEW_VERSION=$(echo $VERSION | awk -F. '{print $1"."$2"."$3+1}') - fi - sed -i "s/version: $VERSION/version: $NEW_VERSION/" pubspec.yaml - git add pubspec.yaml - git commit -m "Bump version to $NEW_VERSION" - echo "NEW_VERSION=$NEW_VERSION" >> "$GITHUB_ENV" - else - echo "Closing pull request without merging. No version bump required." - fi - - name: Create Github release - uses: softprops/action-gh-release@v1 - with: - token: ${{ env.GH_TOKEN }} - tag_name: ${{ env.NEW_VERSION }} - generate_release_notes: true - - name: Generate changelog - uses: charmixer/auto-changelog-action@v1 - with: - token: ${{ env.GH_TOKEN }} - - name: Commit changelog - run: git add CHANGELOG.md && git commit -m 'Update CHANGELOG' && echo "push=true" >> $GITHUB_ENV || echo "No changes to CHANGELOG" - - name: Push changelog - if: env.push == 'true' - run: git push "https://${GH_USER}:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" HEAD:master From 9f251ad287582f76027e6e124a4b337ba01b55bd Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 14:31:17 +0200 Subject: [PATCH 11/16] Clarify that the package is standalone --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 362be0a..2b38cc6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ A flutter plugin to setup and control VPN connection via [Wireguard](https://www.wireguard.com/) tunnel. +It includes [Wireguard implementation for the corresponding OS](https://www.wireguard.com/embedding/) (WireGuardKit for darwin, com.wireguard.android:tunnel for android, etc.) and does not require any additional dependencies. + + | | Android | iOS | Linux | macOS | Windows | |-------------|---------|-------|-------|-------|-------------| | **Support** | 21+ | 15.0+ | TBD | 12+ | 10+ | From 190ec340eace5c663ac6bf9e4270d4f424d890bf Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 16:02:17 +0200 Subject: [PATCH 12/16] ios: Fix to compile --- darwin/Classes/WireguardDartPlugin.swift | 11 +-- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile.lock | 4 +- example/ios/Runner.xcodeproj/project.pbxproj | 94 +++++++++---------- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/ios/tun/tun.entitlements | 14 ++- .../macos/Runner.xcodeproj/project.pbxproj | 2 +- 7 files changed, 61 insertions(+), 68 deletions(-) diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index 870fd9b..f6d63d3 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -15,7 +15,6 @@ import os public class WireguardDartPlugin: NSObject, FlutterPlugin { private var vpnManager: NETunnelProviderManager? - private var statusChannel: FlutterEventChannel var vpnStatus: NEVPNStatus { get { @@ -23,11 +22,6 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { } } - init(registrar: FlutterPluginRegistrar) { - statusChannel = FlutterEventChannel(name: "wireguard_dart/status", binaryMessenger: registrar.messenger) - statusChannel.setStreamHandler(ConnectionStatusObserver()) - } - public static func register(with registrar: FlutterPluginRegistrar) { #if os(iOS) let messenger = registrar.messenger() @@ -36,8 +30,11 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { #endif let channel = FlutterMethodChannel(name: "wireguard_dart", binaryMessenger: messenger) - let instance = WireguardDartPlugin(registrar: registrar) + let instance = WireguardDartPlugin() registrar.addMethodCallDelegate(instance, channel: channel) + + let statusChannel = FlutterEventChannel(name: "wireguard_dart/status", binaryMessenger: messenger) + statusChannel.setStreamHandler(ConnectionStatusObserver()) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1c841c5..c9c0487 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -21,10 +21,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wireguard_dart/darwin" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 wireguard_dart: e9f4586e6433f14a16864e80abbdb63239e1aa12 WireGuardKit: 8b9e7f28441b67aafe60d59c15b8c70bed5ab092 PODFILE CHECKSUM: ade4dc95c753c461e86203a02270c4756b4c2b1a -COCOAPODS: 1.12.0 +COCOAPODS: 1.14.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 20c717b..835ede7 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1451BD91D0534FACE487513E /* Pods_tun.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD7B61CD9704F29F43AFE4D1 /* Pods_tun.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3E4BD00B29D2D4A800F8DE16 /* Info-Release.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3E4BD00A29D2D4A800F8DE16 /* Info-Release.plist */; }; @@ -14,13 +15,11 @@ 3E62C87029D186DE003AD06E /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E62C86F29D186DE003AD06E /* NetworkExtension.framework */; }; 3E62C87329D186DE003AD06E /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E62C87229D186DE003AD06E /* PacketTunnelProvider.swift */; }; 3E62C87829D186DE003AD06E /* tun.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3E62C86E29D186DE003AD06E /* tun.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 3E62C87E29D1B6DA003AD06E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BE914DA511770D6378DCB7C /* Pods_Runner.framework */; }; - 3EE5059029D1C4060069B3BB /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E62C86F29D186DE003AD06E /* NetworkExtension.framework */; }; - 3EE5059529D2CAE00069B3BB /* Pods_tun.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1A14E920DDA39E14E965B0 /* Pods_tun.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + BFBE6A591C2694DF12E10591 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DC0188794C8FCBD13A5E31A /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,7 +49,7 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B1A14E920DDA39E14E965B0 /* Pods_tun.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_tun.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BE21020303AA49CEE2BE109 /* Pods-tun.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.profile.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.profile.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3E4BD00A29D2D4A800F8DE16 /* Info-Release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Release.plist"; sourceTree = ""; }; 3E4BD00C29D2D55400F8DE16 /* Info-Profile.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Profile.plist"; sourceTree = ""; }; @@ -60,8 +59,9 @@ 3E62C87429D186DE003AD06E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3E62C87529D186DE003AD06E /* tun.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = tun.entitlements; sourceTree = ""; }; 3E62C88129D1BA98003AD06E /* Runner.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; - 43DC35DD4C950D31FAC1A9F3 /* Pods-tun.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.release.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.release.xcconfig"; sourceTree = ""; }; - 59E1612451F0CA3551AFDB86 /* Pods-tun.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.debug.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.debug.xcconfig"; sourceTree = ""; }; + 3F2D29A3B423AE9F749FD966 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 457D1FD76BE1652D1C128610 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 4DC0188794C8FCBD13A5E31A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -72,11 +72,10 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info-Debug.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-Debug.plist"; sourceTree = ""; }; - 9BE914DA511770D6378DCB7C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AFFE594A4D811DCD6AD82E87 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - CD883311FB8123866D0BC937 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - CEF275C72952E30E6A901585 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - D2268906221E5751820806C8 /* Pods-tun.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.profile.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.profile.xcconfig"; sourceTree = ""; }; + 99BFEE0466CAA4A1BD85845A /* Pods-tun.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.debug.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.debug.xcconfig"; sourceTree = ""; }; + AD7B61CD9704F29F43AFE4D1 /* Pods_tun.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_tun.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B1030EA7B48E98FB963677E9 /* Pods-tun.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tun.release.xcconfig"; path = "Target Support Files/Pods-tun/Pods-tun.release.xcconfig"; sourceTree = ""; }; + D1C40A99DAE6FD969E5AAA3B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -84,8 +83,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3EE5059529D2CAE00069B3BB /* Pods_tun.framework in Frameworks */, 3E62C87029D186DE003AD06E /* NetworkExtension.framework in Frameworks */, + 1451BD91D0534FACE487513E /* Pods_tun.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -93,8 +92,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3E62C87E29D1B6DA003AD06E /* Pods_Runner.framework in Frameworks */, - 3EE5059029D1C4060069B3BB /* NetworkExtension.framework in Frameworks */, + BFBE6A591C2694DF12E10591 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -114,12 +112,12 @@ 7DB427E79B062483C462D389 /* Pods */ = { isa = PBXGroup; children = ( - CD883311FB8123866D0BC937 /* Pods-Runner.debug.xcconfig */, - CEF275C72952E30E6A901585 /* Pods-Runner.release.xcconfig */, - AFFE594A4D811DCD6AD82E87 /* Pods-Runner.profile.xcconfig */, - 59E1612451F0CA3551AFDB86 /* Pods-tun.debug.xcconfig */, - 43DC35DD4C950D31FAC1A9F3 /* Pods-tun.release.xcconfig */, - D2268906221E5751820806C8 /* Pods-tun.profile.xcconfig */, + 3F2D29A3B423AE9F749FD966 /* Pods-Runner.debug.xcconfig */, + D1C40A99DAE6FD969E5AAA3B /* Pods-Runner.release.xcconfig */, + 457D1FD76BE1652D1C128610 /* Pods-Runner.profile.xcconfig */, + 99BFEE0466CAA4A1BD85845A /* Pods-tun.debug.xcconfig */, + B1030EA7B48E98FB963677E9 /* Pods-tun.release.xcconfig */, + 1BE21020303AA49CEE2BE109 /* Pods-tun.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -177,9 +175,9 @@ DF04125CA7DB52DAEE6D2577 /* Frameworks */ = { isa = PBXGroup; children = ( - 9BE914DA511770D6378DCB7C /* Pods_Runner.framework */, 3E62C86F29D186DE003AD06E /* NetworkExtension.framework */, - 3B1A14E920DDA39E14E965B0 /* Pods_tun.framework */, + 4DC0188794C8FCBD13A5E31A /* Pods_Runner.framework */, + AD7B61CD9704F29F43AFE4D1 /* Pods_tun.framework */, ); name = Frameworks; sourceTree = ""; @@ -191,7 +189,7 @@ isa = PBXNativeTarget; buildConfigurationList = 3E62C87929D186DE003AD06E /* Build configuration list for PBXNativeTarget "tun" */; buildPhases = ( - 449240DC3BFE862B2C3BFF93 /* [CP] Check Pods Manifest.lock */, + 1177F6E5038EBEF27A0240F6 /* [CP] Check Pods Manifest.lock */, 3E62C86A29D186DE003AD06E /* Sources */, 3E62C86B29D186DE003AD06E /* Frameworks */, 3E62C86C29D186DE003AD06E /* Resources */, @@ -209,14 +207,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 6F36A9D287F9FE0F91502155 /* [CP] Check Pods Manifest.lock */, + 0B5FC5666B7119948393A24E /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - AFEADC65E0D6E3A874F7DC86 /* [CP] Embed Pods Frameworks */, 3E62C87D29D186DE003AD06E /* Embed Foundation Extensions */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + C015A60D940AD1948349B37D /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -235,7 +233,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 3E62C86D29D186DE003AD06E = { @@ -290,23 +288,29 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 0B5FC5666B7119948393A24E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "Thin Binary"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 449240DC3BFE862B2C3BFF93 /* [CP] Check Pods Manifest.lock */ = { + 1177F6E5038EBEF27A0240F6 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -328,27 +332,21 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 6F36A9D287F9FE0F91502155 /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); + name = "Thin Binary"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -365,7 +363,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - AFEADC65E0D6E3A874F7DC86 /* [CP] Embed Pods Frameworks */ = { + C015A60D940AD1948349B37D /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -514,7 +512,7 @@ }; 3E62C87A29D186DE003AD06E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 59E1612451F0CA3551AFDB86 /* Pods-tun.debug.xcconfig */; + baseConfigurationReference = 99BFEE0466CAA4A1BD85845A /* Pods-tun.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -554,7 +552,7 @@ }; 3E62C87B29D186DE003AD06E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 43DC35DD4C950D31FAC1A9F3 /* Pods-tun.release.xcconfig */; + baseConfigurationReference = B1030EA7B48E98FB963677E9 /* Pods-tun.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -591,7 +589,7 @@ }; 3E62C87C29D186DE003AD06E /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D2268906221E5751820806C8 /* Pods-tun.profile.xcconfig */; + baseConfigurationReference = 1BE21020303AA49CEE2BE109 /* Pods-tun.profile.xcconfig */; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..a6b826d 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - com.apple.security.network.server - - com.apple.security.app-sandbox - - com.apple.security.network.client - com.apple.developer.networking.networkextension - app-proxy-provider - content-filter-provider packet-tunnel-provider + com.apple.security.app-sandbox + + com.apple.security.network.client + + com.apple.security.network.server + diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 700e77e..62ed334 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire\n"; }; DC5ECBD2B06ED653A378967E /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; From 55cbe7506bb56df59fb4134b1e5c640ab0331a27 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Thu, 18 Jan 2024 16:19:02 +0200 Subject: [PATCH 13/16] Prepare 0.5.0 changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd58d0e..5e24ace 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.5.0](https://github.com/mysteriumnetwork/wireguard_dart/tree/0.5.0) (2024-01-18) + +- darwin: Fix connection status streaming. Two available methods are `.status()` and `.statusStream()` +- `.status()` now returns an unwrapped status instead of a map +- Add a required `tunnelName` option in addition to `bundleId` + +[Full Changelog](https://github.com/mysteriumnetwork/wireguard_dart/compare/0.4.5...0.5.0) + ## [0.4.5](https://github.com/mysteriumnetwork/wireguard_dart/tree/0.4.5) (2023-08-04) [Full Changelog](https://github.com/mysteriumnetwork/wireguard_dart/compare/0.4.4...0.4.5) From c0f5e29974ec2849ff97469e761ced9c1015cad7 Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Fri, 19 Jan 2024 09:44:07 +0200 Subject: [PATCH 14/16] Fix some lint issues --- darwin/Classes/ConnectionStatus.swift | 10 ++--- darwin/Classes/ConnectionStatusObserver.swift | 22 +++++----- darwin/Classes/FlutterError.swift | 2 +- darwin/Classes/Logger.swift | 4 +- darwin/Classes/WireguardDartPlugin.swift | 44 +++++++++---------- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/darwin/Classes/ConnectionStatus.swift b/darwin/Classes/ConnectionStatus.swift index f0b092d..375b477 100644 --- a/darwin/Classes/ConnectionStatus.swift +++ b/darwin/Classes/ConnectionStatus.swift @@ -8,9 +8,9 @@ enum ConnectionStatus: String { case connecting case disconnecting case unknown - - static func fromNEVPNStatus(ns: NEVPNStatus) -> ConnectionStatus { - switch ns { + + static func fromNEVPNStatus(status: NEVPNStatus) -> ConnectionStatus { + switch status { case .connected: return ConnectionStatus.connected case .disconnected: return ConnectionStatus.disconnected case .connecting: return ConnectionStatus.connecting @@ -18,8 +18,8 @@ enum ConnectionStatus: String { default: return ConnectionStatus.unknown } } - + func string() -> String { - return self.rawValue + rawValue } } diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index 30f2227..4475c7b 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -13,39 +13,39 @@ import WireGuardKit import os class ConnectionStatusObserver: NSObject, FlutterStreamHandler { - + private var eventSink: FlutterEventSink? private var isRunning: Bool = false - - public func _statusChanged(n: Notification?) { - guard let conn = n?.object as? NEVPNConnection else { + + public func handleStatusChanged(notification: Notification?) { + guard let conn = notification?.object as? NEVPNConnection else { return } guard let eventSink = eventSink else { return } - let newStatus = ConnectionStatus.fromNEVPNStatus(ns: conn.status) - + let newStatus = ConnectionStatus.fromNEVPNStatus(status: conn.status) + Logger.main.debug("VPN status changed: \(newStatus.string())") eventSink(newStatus.string()) } - + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { self.eventSink = events - + if !isRunning { NotificationCenter.default.addObserver( forName: NSNotification.Name.NEVPNStatusDidChange, object: nil, queue: OperationQueue.main, - using: _statusChanged + using: handleStatusChanged ) } - + isRunning = true return nil } - + public func onCancel(withArguments arguments: Any?) -> FlutterError? { isRunning = false NotificationCenter.default.removeObserver(self) diff --git a/darwin/Classes/FlutterError.swift b/darwin/Classes/FlutterError.swift index 55ed29c..497966c 100644 --- a/darwin/Classes/FlutterError.swift +++ b/darwin/Classes/FlutterError.swift @@ -7,5 +7,5 @@ import FlutterMacOS #endif func nativeFlutterError(message: String) -> FlutterError { - return FlutterError(code: "NATIVE_ERR", message: message, details: nil) + FlutterError(code: "NATIVE_ERR", message: message, details: nil) } diff --git a/darwin/Classes/Logger.swift b/darwin/Classes/Logger.swift index aa98176..66bd045 100644 --- a/darwin/Classes/Logger.swift +++ b/darwin/Classes/Logger.swift @@ -1,7 +1,7 @@ import Foundation import os.log -public extension Logger { +extension Logger { private static var subsystem = Bundle.main.bundleIdentifier! - static let main = Logger(subsystem: subsystem, category: "main") + public static let main = Logger(subsystem: subsystem, category: "main") } diff --git a/darwin/Classes/WireguardDartPlugin.swift b/darwin/Classes/WireguardDartPlugin.swift index f6d63d3..ce43f34 100644 --- a/darwin/Classes/WireguardDartPlugin.swift +++ b/darwin/Classes/WireguardDartPlugin.swift @@ -2,41 +2,38 @@ import Flutter import UIKit #elseif os(macOS) -import FlutterMacOS import Cocoa +import FlutterMacOS #else #error("Unsupported platform") #endif -import WireGuardKit import NetworkExtension import os +import WireGuardKit public class WireguardDartPlugin: NSObject, FlutterPlugin { - private var vpnManager: NETunnelProviderManager? - + var vpnStatus: NEVPNStatus { - get { - return vpnManager?.connection.status ?? NEVPNStatus.invalid - } + vpnManager?.connection.status ?? NEVPNStatus.invalid } - + public static func register(with registrar: FlutterPluginRegistrar) { -#if os(iOS) + #if os(iOS) let messenger = registrar.messenger() -#else + #else let messenger = registrar.messenger -#endif + #endif let channel = FlutterMethodChannel(name: "wireguard_dart", binaryMessenger: messenger) - + let instance = WireguardDartPlugin() registrar.addMethodCallDelegate(instance, channel: channel) - + let statusChannel = FlutterEventChannel(name: "wireguard_dart/status", binaryMessenger: messenger) statusChannel.setStreamHandler(ConnectionStatusObserver()) } - + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "nativeInit": @@ -45,12 +42,12 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { let privateKey = PrivateKey() let privateKeyResponse: [String: Any] = [ "privateKey": privateKey.base64Key, - "publicKey": privateKey.publicKey.base64Key, + "publicKey": privateKey.publicKey.base64Key ] result(privateKeyResponse) case "setupTunnel": Logger.main.debug("handle setupTunnel") - guard let args = call.arguments as? Dictionary, args["bundleId"] != nil else { + guard let args = call.arguments as? [String: Any], args["bundleId"] != nil else { result(nativeFlutterError(message: "required argument: 'bundleId'")) return } @@ -77,7 +74,7 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { case "connect": Logger.main.debug("handle connect") let cfg: String - if let args = call.arguments as? Dictionary, + if let args = call.arguments as? [String: Any], let argCfg = args["cfg"] as? String { cfg = argCfg } else { @@ -115,36 +112,35 @@ public class WireguardDartPlugin: NSObject, FlutterPlugin { result("") } case "status": - guard let _ = vpnManager else { + guard vpnManager != nil else { Logger.main.error("Tunnel not initialized, missing 'vpnManager'") result(nativeFlutterError(message: "tunnel not initialized, missing 'vpnManager'")) return } Task { - result(ConnectionStatus.fromNEVPNStatus(ns: vpnStatus).string()) + result(ConnectionStatus.fromNEVPNStatus(status: vpnStatus).string()) } default: result(FlutterMethodNotImplemented) } } - + func setupProviderManager(bundleId: String, tunnelName: String) async throws -> NETunnelProviderManager { let mgrs = try await NETunnelProviderManager.loadAllFromPreferences() let existingMgr = mgrs.first(where: { ($0.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == bundleId }) let mgr = existingMgr ?? NETunnelProviderManager() - + mgr.localizedDescription = tunnelName let proto = NETunnelProviderProtocol() proto.providerBundleIdentifier = bundleId proto.serverAddress = "" // must be non-null mgr.protocolConfiguration = proto mgr.isEnabled = true - + try await mgr.saveToPreferences() - + return mgr } - } From e80dbb9baedaf999c2b4097da063071b9501c6ff Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Fri, 19 Jan 2024 11:56:53 +0200 Subject: [PATCH 15/16] Configure swiftformat https://github.com/Alamofire/Alamofire/blob/master/.swiftformat --- .swiftformat | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .swiftformat diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 0000000..4c89d72 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,36 @@ +# file options + +--symlinks ignore +--swiftversion 5.7 + +# rules +--enable isEmpty +--disable andOperator +--disable wrapMultilineStatementBraces + +# format options + +--commas inline +--comments indent +--decimalgrouping 3,5 +--exponentcase lowercase +--exponentgrouping disabled +--extensionacl on-declarations +--fractiongrouping disabled +--ifdef no-indent +--importgrouping testable-top +--operatorfunc no-space +--nospaceoperators ..<, ... +--selfrequired validate +--someAny false +--stripunusedargs closure-only +--wraparguments preserve +--wrapcollections preserve +--wrapparameters preserve + + +# rules + +--enable isEmpty +--disable wrapMultilineStatementBraces +--disable opaqueGenericParameters From 3ac01401fe583aa34c1e34a776f1e38c3e6bb10a Mon Sep 17 00:00:00 2001 From: Tadas Krivickas Date: Fri, 19 Jan 2024 11:57:14 +0200 Subject: [PATCH 16/16] Simplify notification observer using init/deinit --- darwin/Classes/ConnectionStatusObserver.swift | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/darwin/Classes/ConnectionStatusObserver.swift b/darwin/Classes/ConnectionStatusObserver.swift index 4475c7b..b824a23 100644 --- a/darwin/Classes/ConnectionStatusObserver.swift +++ b/darwin/Classes/ConnectionStatusObserver.swift @@ -2,53 +2,50 @@ import Flutter import UIKit #elseif os(macOS) -import FlutterMacOS import Cocoa +import FlutterMacOS #else #error("Unsupported platform") #endif import NetworkExtension -import WireGuardKit import os +import WireGuardKit class ConnectionStatusObserver: NSObject, FlutterStreamHandler { - private var eventSink: FlutterEventSink? private var isRunning: Bool = false + override init() { + super.init() + NotificationCenter.default.addObserver( + forName: NSNotification.Name.NEVPNStatusDidChange, + object: nil, + queue: OperationQueue.main, + using: handleStatusChanged + ) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + public func handleStatusChanged(notification: Notification?) { guard let conn = notification?.object as? NEVPNConnection else { return } - guard let eventSink = eventSink else { - return - } let newStatus = ConnectionStatus.fromNEVPNStatus(status: conn.status) Logger.main.debug("VPN status changed: \(newStatus.string())") - eventSink(newStatus.string()) + eventSink?(newStatus.string()) } public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - self.eventSink = events - - if !isRunning { - NotificationCenter.default.addObserver( - forName: NSNotification.Name.NEVPNStatusDidChange, - object: nil, - queue: OperationQueue.main, - using: handleStatusChanged - ) - } - - isRunning = true + eventSink = events return nil } public func onCancel(withArguments arguments: Any?) -> FlutterError? { - isRunning = false - NotificationCenter.default.removeObserver(self) eventSink = nil return nil }