From e4029ce77cf1ff2182bd2f43f8abd09009c5c7e5 Mon Sep 17 00:00:00 2001 From: invertedx Date: Tue, 19 Aug 2025 23:27:16 +0200 Subject: [PATCH 1/6] improved example app --- .../res/mipmap-hdpi/ic_launcher.png.license | 3 - .../res/mipmap-mdpi/ic_launcher.png.license | 3 - .../res/mipmap-xhdpi/ic_launcher.png.license | 3 - .../res/mipmap-xxhdpi/ic_launcher.png.license | 3 - .../mipmap-xxxhdpi/ic_launcher.png.license | 3 - example/lib/main.dart | 349 ++++++++++-------- 6 files changed, 202 insertions(+), 162 deletions(-) delete mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png.license delete mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png.license delete mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png.license delete mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png.license delete mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png.license diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png.license b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png.license deleted file mode 100644 index 7b44746f..00000000 --- a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2024 Foundation Devices Inc. - -SPDX-License-Identifier: MIT diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png.license b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png.license deleted file mode 100644 index 7b44746f..00000000 --- a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2024 Foundation Devices Inc. - -SPDX-License-Identifier: MIT diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png.license b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png.license deleted file mode 100644 index 7b44746f..00000000 --- a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2024 Foundation Devices Inc. - -SPDX-License-Identifier: MIT diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png.license b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png.license deleted file mode 100644 index 7b44746f..00000000 --- a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2024 Foundation Devices Inc. - -SPDX-License-Identifier: MIT diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png.license b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png.license deleted file mode 100644 index 7b44746f..00000000 --- a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2024 Foundation Devices Inc. - -SPDX-License-Identifier: MIT diff --git a/example/lib/main.dart b/example/lib/main.dart index bb867655..caf92c05 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -41,14 +41,22 @@ class _MyAppState extends State { // Flag to track if tor has started. bool torStarted = false; + // Flag to track if tor has started. + bool _loading = false; + + // Flag to track if tor has started. + String requestResponse = ""; + // Set the default text for the host input field. final hostController = TextEditingController(text: 'https://icanhazip.com/'); + // https://check.torproject.org is another good option. // Set the default text for the onion input field. final onionController = TextEditingController( text: 'https://cflarexljc3rw355ysrkrzwapozws6nre6xsy3n4yrj7taye3uiby3ad.onion'); + // See https://blog.cloudflare.com/cloudflare-onion-service/ for more options: // cflarexljc3rw355ysrkrzwapozws6nre6xsy3n4yrj7taye3uiby3ad.onion // cflarenuttlfuyn7imozr4atzvfbiw3ezgbdjdldmdx7srterayaozid.onion @@ -64,6 +72,7 @@ class _MyAppState extends State { final bitcoinOnionController = TextEditingController( text: 'qly7g5n5t3f3h23xvbp44vs6vpmayurno4basuu5rcvrupli7y2jmgid.onion:50001'); + // For more options, see https://bitnodes.io/nodes/addresses/?q=onion and // https://sethforprivacy.com/about/ @@ -98,6 +107,13 @@ class _MyAppState extends State { return Scaffold( appBar: AppBar( title: const Text('Tor example'), + bottom: PreferredSize( + preferredSize: const Size.fromHeight(0), + child: Opacity( + opacity: _loading ? 1.0 : 0.0, + child: const LinearProgressIndicator(), + ), + ), ), body: SingleChildScrollView( child: Container( @@ -168,37 +184,45 @@ class _MyAppState extends State { TextButton( onPressed: torStarted ? () async { - // `socks5_proxy` package example, use another socks5 - // connection of your choice. - - // Create HttpClient object - final client = HttpClient(); - - // Assign connection factory. - SocksTCPClient.assignToHttpClient(client, [ - ProxySettings(InternetAddress.loopbackIPv4, - Tor.instance.port, - password: - null), // TODO Need to get from tor config file. - ]); - - // GET request. - final url = Uri.parse(hostController.text); - final request = await client.getUrl(url); - final response = await request.close(); - - // Print response. - var responseString = - await utf8.decodeStream(response); - print(responseString); - // If host input left to default icanhazip.com, a Tor - // exit node IP should be printed to the console. - // - // https://check.torproject.org is also good for - // doublechecking torability. - - // Close client - client.close(); + try { + _setRequestResponse("Loading...", true); + // `socks5_proxy` package example, use another socks5 + // connection of your choice. + + // Create HttpClient object + final client = HttpClient(); + + // Assign connection factory. + SocksTCPClient.assignToHttpClient(client, [ + ProxySettings(InternetAddress.loopbackIPv4, + Tor.instance.port, + password: + null), // TODO Need to get from tor config file. + ]); + + // GET request. + final url = Uri.parse(hostController.text); + final request = await client.getUrl(url); + final response = await request.close(); + + // Print response. + var responseString = + await utf8.decodeStream(response); + print(responseString); + + _setRequestResponse(responseString, false); + + // If host input left to default icanhazip.com, a Tor + // exit node IP should be printed to the console. + // + // https://check.torproject.org is also good for + // doublechecking torability. + + // Close client + client.close(); + } catch (e) { + _setRequestResponse(e.toString(), false); + } } : null, child: const Text("Make proxied request"), @@ -209,53 +233,63 @@ class _MyAppState extends State { TextButton( onPressed: torStarted ? () async { - // Instantiate a socks socket at localhost and on the port selected by the tor service. - var socksSocket = await SOCKSSocket.create( - proxyHost: InternetAddress.loopbackIPv4.address, - proxyPort: Tor.instance.port, - sslEnabled: true, // For SSL connections. - ); - - // Connect to the socks instantiated above. - await socksSocket.connect(); - - // Connect to bitcoin.stackwallet.com on port 50002 via socks socket. - // - // Note that this is an SSL example. - await socksSocket.connectTo( - 'bitcoin.stackwallet.com', 50002); - - // Send a server features command to the connected socket, see method for more specific usage example.. - await socksSocket.sendServerFeaturesCommand(); - - // You should see a server response printed to the console. - // - // Example response: - // `flutter: secure responseData: { - // "id": "0", - // "jsonrpc": "2.0", - // "result": { - // "cashtokens": true, - // "dsproof": true, - // "genesis_hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - // "hash_function": "sha256", - // "hosts": { - // "bitcoin.stackwallet.com": { - // "ssl_port": 50002, - // "tcp_port": 50001, - // "ws_port": 50003, - // "wss_port": 50004 - // } - // }, - // "protocol_max": "1.5", - // "protocol_min": "1.4", - // "pruning": null, - // "server_version": "Fulcrum 1.9.1" - // } - // } - - // Close the socket. - await socksSocket.close(); + try { + _setRequestResponse("Loading...", true); + // Instantiate a socks socket at localhost and on the port selected by the tor service. + var socksSocket = await SOCKSSocket.create( + proxyHost: InternetAddress.loopbackIPv4.address, + proxyPort: Tor.instance.port, + sslEnabled: true, // For SSL connections. + ); + + // Connect to the socks instantiated above. + await socksSocket.connect(); + + // Connect to bitcoin.stackwallet.com on port 50002 via socks socket. + // + // Note that this is an SSL example. + await socksSocket.connectTo( + 'bitcoin.stackwallet.com', 50002); + final stream = socksSocket.responseController.stream + .listen((event) { + print("Response received: ${utf8.decode(event)}"); + _setRequestResponse(utf8.decode(event), false); + }); + // Send a server features command to the connected socket, see method for more specific usage example.. + await socksSocket.sendServerFeaturesCommand(); + + // You should see a server response printed to the console. + // + // Example response: + // `flutter: secure responseData: { + // "id": "0", + // "jsonrpc": "2.0", + // "result": { + // "cashtokens": true, + // "dsproof": true, + // "genesis_hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + // "hash_function": "sha256", + // "hosts": { + // "bitcoin.stackwallet.com": { + // "ssl_port": 50002, + // "tcp_port": 50001, + // "ws_port": 50003, + // "wss_port": 50004 + // } + // }, + // "protocol_max": "1.5", + // "protocol_min": "1.4", + // "pruning": null, + // "server_version": "Fulcrum 1.9.1" + // } + // } + + // Close the socket. + await socksSocket.close(); + stream.cancel(); + } catch (e) { + _setRequestResponse(e.toString(), false); + } } : null, child: const Text( @@ -300,6 +334,11 @@ class _MyAppState extends State { sslEnabled: !domain .endsWith(".onion"), // For SSL connections. ); + final stream = socksSocket.responseController.stream + .listen((event) { + print("Response received: ${utf8.decode(event)}"); + _setRequestResponse(utf8.decode(event), false); + }); // Connect to the socks instantiated above. await socksSocket.connect(); @@ -340,6 +379,7 @@ class _MyAppState extends State { // Close the socket. await socksSocket.close(); + stream.cancel(); } // A mutex should be added to this example to prevent @@ -378,76 +418,82 @@ class _MyAppState extends State { print("Invalid onion address (needs port)"); return; } - - final String host = - moneroOnionController.text.split(":").first; - final int port = int.parse(moneroOnionController - .text - .split(":") - .last - .split("/") - .first); - final String path = moneroOnionController.text - .split(":") - .last - .split("/") - .last; // Extract the path - - var socksSocket = await SOCKSSocket.create( - proxyHost: InternetAddress.loopbackIPv4.address, - proxyPort: Tor.instance.port, - sslEnabled: false, - ); - - await socksSocket.connect(); - await socksSocket.connectTo(host, port); - - final body = jsonEncode({ - "jsonrpc": "2.0", - "id": "0", - "method": "get_info", - }); - - final request = 'POST /$path HTTP/1.1\r\n' - 'Host: $host\r\n' - 'Content-Type: application/json\r\n' - 'Content-Length: ${body.length}\r\n' - '\r\n' - '$body'; - - socksSocket.write(request); - print("Request sent: $request"); - - await for (var response - in socksSocket.inputStream) { - final result = utf8.decode(response); - print("Response received: $result"); - break; + _setRequestResponse("Loading...", true); + + try { + final String host = + moneroOnionController.text.split(":").first; + final int port = int.parse(moneroOnionController + .text + .split(":") + .last + .split("/") + .first); + final String path = moneroOnionController.text + .split(":") + .last + .split("/") + .last; // Extract the path + + var socksSocket = await SOCKSSocket.create( + proxyHost: InternetAddress.loopbackIPv4.address, + proxyPort: Tor.instance.port, + sslEnabled: false, + ); + + await socksSocket.connect(); + await socksSocket.connectTo(host, port); + + final body = jsonEncode({ + "jsonrpc": "2.0", + "id": "0", + "method": "get_info", + }); + + final request = 'POST /$path HTTP/1.1\r\n' + 'Host: $host\r\n' + 'Content-Type: application/json\r\n' + 'Content-Length: ${body.length}\r\n' + '\r\n' + '$body'; + + socksSocket.write(request); + print("Request sent: $request"); + + await for (var response + in socksSocket.inputStream) { + final result = utf8.decode(response); + print("Response received: $result"); + _setRequestResponse(result, false); + break; + } + + // You should see a server response printed to the console. + // + // Example response: + // Host: ucdouiihzwvb5edg3ezeufcs4yp26gq4x64n6b4kuffb7s7jxynnk7qd.onion + // Content-Type: application/json + // Content-Length: 46 + // + // {"jsonrpc":"2.0","id":"0","method":"get_info"} + // flutter: Response received: HTTP/1.1 200 Ok + // Server: Epee-based + // Content-Length: 1434 + // Content-Type: application/json + // Last-Modified: Thu, 03 Oct 2024 23:08:19 GMT + // Accept-Ranges: bytes + // + // { + // "id": "0", + // "jsonrpc": "2.0", + // "result": { + // "adjusted_time": 1727996959, + // ... + + await socksSocket.close(); + } catch (e) { + _setRequestResponse(e.toString(), false); } - - // You should see a server response printed to the console. - // - // Example response: - // Host: ucdouiihzwvb5edg3ezeufcs4yp26gq4x64n6b4kuffb7s7jxynnk7qd.onion - // Content-Type: application/json - // Content-Length: 46 - // - // {"jsonrpc":"2.0","id":"0","method":"get_info"} - // flutter: Response received: HTTP/1.1 200 Ok - // Server: Epee-based - // Content-Length: 1434 - // Content-Type: application/json - // Last-Modified: Thu, 03 Oct 2024 23:08:19 GMT - // Accept-Ranges: bytes - // - // { - // "id": "0", - // "jsonrpc": "2.0", - // "result": { - // "adjusted_time": 1727996959, - // ... - - await socksSocket.close(); } // A mutex should be added to this example to prevent @@ -459,10 +505,19 @@ class _MyAppState extends State { ), ], ), + spacerSmall, + Text(requestResponse) ], ), ), ), ); } + + _setRequestResponse(String response, bool loading) { + setState(() { + _loading = loading; + requestResponse = response; + }); + } } From f2c20a66046f8bb214269ecae5f29886d15ff256 Mon Sep 17 00:00:00 2001 From: invertedx Date: Tue, 19 Aug 2025 23:33:06 +0200 Subject: [PATCH 2/6] Use flutter 3.35 --- android/build.gradle | 6 +- cargokit/gradle/plugin.gradle | 14 +-- example/.gitignore | 2 + example/android/app/build.gradle | 15 +-- example/android/build.gradle | 19 +-- .../gradle/wrapper/gradle-wrapper.properties | 7 +- example/android/settings.gradle | 30 +++-- example/ios/Podfile.lock | 6 +- example/macos/Podfile | 2 +- example/macos/Podfile.lock | 8 +- .../macos/Runner.xcodeproj/project.pbxproj | 8 +- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- example/macos/Runner/AppDelegate.swift | 6 +- example/pubspec.lock | 110 +++++++++--------- pubspec.yaml | 10 +- 15 files changed, 120 insertions(+), 126 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9b1456dd..d99df5a3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -15,7 +15,7 @@ buildscript { dependencies { // The Android Gradle Plugin knows how to build native code with the NDK. - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.12.1' } } @@ -34,7 +34,7 @@ android { } // Bumping the plugin compileSdkVersion requires all clients of this plugin // to bump the version in their app. - compileSdkVersion 33 + compileSdkVersion 36 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -42,7 +42,7 @@ android { } defaultConfig { - minSdkVersion 16 + minSdkVersion 24 } } diff --git a/cargokit/gradle/plugin.gradle b/cargokit/gradle/plugin.gradle index 0a73636e..b6d9ff00 100644 --- a/cargokit/gradle/plugin.gradle +++ b/cargokit/gradle/plugin.gradle @@ -1,7 +1,3 @@ -// SPDX-FileCopyrightText: 2024 Foundation Devices Inc. -// -// SPDX-License-Identifier: MIT - import java.nio.file.Paths import org.apache.tools.ant.taskdefs.condition.Os @@ -87,10 +83,10 @@ class CargoKitPlugin implements Plugin { _findFlutterPlugin(rootProject.childProjects) } - private Plugin _findFlutterPlugin(Map projects) { + private Plugin _findFlutterPlugin(Map projects) { for (project in projects) { for (plugin in project.value.getPlugins()) { - if (plugin.class.name == "FlutterPlugin") { + if (plugin.class.name == "com.flutter.gradle.FlutterPlugin") { return plugin; } } @@ -123,7 +119,7 @@ class CargoKitPlugin implements Plugin { def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs; jniLibs.srcDir(new File(cargoOutputDir)) - def platforms = plugin.getTargetPlatforms().collect() + def platforms = com.flutter.gradle.FlutterPluginUtils.getTargetPlatforms(project).collect() // Same thing addFlutterDependencies does in flutter.gradle if (buildType == "debug") { @@ -145,7 +141,7 @@ class CargoKitPlugin implements Plugin { } def task = project.tasks.create(taskName, CargoKitBuildTask.class) { - buildMode = variant.name + buildMode = variant.buildType.name buildDir = cargoBuildDir outputDir = cargoOutputDir ndkVersion = plugin.project.android.ndkVersion @@ -167,4 +163,4 @@ class CargoKitPlugin implements Plugin { } } } -} +} \ No newline at end of file diff --git a/example/.gitignore b/example/.gitignore index 150260c0..0b4fe0d7 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -9,9 +9,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 82d4310a..389801c5 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,7 +1,11 @@ // SPDX-FileCopyrightText: 2024 Foundation Devices Inc. // // SPDX-License-Identifier: MIT - +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -10,10 +14,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { @@ -25,10 +25,6 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { namespace "com.foundationdevices.tor_example" compileSdkVersion flutter.compileSdkVersion @@ -72,5 +68,4 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/example/android/build.gradle b/example/android/build.gradle index 7f8d47d8..8f31e8ca 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,20 +1,3 @@ -// SPDX-FileCopyrightText: 2024 Foundation Devices Inc. -// -// SPDX-License-Identifier: MIT - -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() @@ -32,4 +15,4 @@ subprojects { tasks.register("clean", Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 664b981d..6dc44808 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,9 +1,8 @@ -# SPDX-FileCopyrightText: 2024 Foundation Devices Inc. -# +#SPDX-FileCopyrightText: 2024 Foundation Devices Inc. # SPDX-License-Identifier: MIT - +#Tue Aug 19 17:05:17 CEST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-milestone-1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 7945a535..25082662 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -2,14 +2,28 @@ // // SPDX-License-Identifier: MIT -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version '8.12.1' apply false + id "org.jetbrains.kotlin.android" version "2.2.10" apply false +} + +include ":app" \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 776b3aa9..487b96de 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -20,10 +20,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/tor/ios" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 tor: 662a9f5b980b5c86decb8ba611de9bcd4c8286eb PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189 -COCOAPODS: 1.12.1 +COCOAPODS: 1.16.2 diff --git a/example/macos/Podfile b/example/macos/Podfile index c795730d..b52666a1 100644 --- a/example/macos/Podfile +++ b/example/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.14' +platform :osx, '10.15' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 52ff571f..fffbac95 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -19,10 +19,10 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/tor/macos SPEC CHECKSUMS: - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 tor: 2138c48428e696b83eacdda404de6d5574932e26 -PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 +PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 -COCOAPODS: 1.12.1 +COCOAPODS: 1.16.2 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index c39da80c..f7b9df5c 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -258,7 +258,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { @@ -567,7 +567,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 = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -648,7 +648,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 = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -695,7 +695,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 = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 24a92bb2..6229190c 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift index 9de404cf..72f59d12 100644 --- a/example/macos/Runner/AppDelegate.swift +++ b/example/macos/Runner/AppDelegate.swift @@ -5,9 +5,13 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 1ff8c916..e01fa420 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: @@ -53,18 +53,18 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -87,26 +87,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -119,10 +119,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -135,42 +135,42 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: transitive description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.2" path_provider_linux: dependency: transitive description: @@ -199,10 +199,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -215,7 +215,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" socks5_proxy: dependency: "direct main" description: @@ -228,50 +228,50 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.6" tor: dependency: "direct main" description: @@ -283,26 +283,26 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "15.0.2" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.8.0-0 <4.0.0" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index fb4a917c..fd1270ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,15 +21,15 @@ environment: dependencies: flutter: sdk: flutter - path_provider: ^2.1.4 - ffi: ^2.0.1 - plugin_platform_interface: ^2.0.2 + path_provider: ^2.1.5 + ffi: ^2.1.4 + plugin_platform_interface: ^2.1.8 dev_dependencies: - ffigen: ^11.0.0 + ffigen: ^19.1.0 flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^6.0.0 ffigen: output: 'lib/generated_bindings.dart' From f4f481e2bcad2069cf70d4f1d304c867e7721cf0 Mon Sep 17 00:00:00 2001 From: invertedx Date: Tue, 19 Aug 2025 23:34:50 +0200 Subject: [PATCH 3/6] Add 16K page size support for android --- android/build.gradle | 2 +- cargokit/build_tool/lib/src/android_environment.dart | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index d99df5a3..0ca96f2c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -42,7 +42,7 @@ android { } defaultConfig { - minSdkVersion 24 + minSdkVersion 16 } } diff --git a/cargokit/build_tool/lib/src/android_environment.dart b/cargokit/build_tool/lib/src/android_environment.dart index 1cb32821..32ae61a6 100644 --- a/cargokit/build_tool/lib/src/android_environment.dart +++ b/cargokit/build_tool/lib/src/android_environment.dart @@ -190,7 +190,17 @@ class AndroidEnvironment { if (rustFlags.isNotEmpty) { rustFlags = '$rustFlags\x1f'; } - rustFlags = '$rustFlags-L\x1f$workaroundDir'; + rustFlags = '$rustFlags-L\x1f$workaroundDir\x1f'; + + const pageSizeArgs = [ + "-C", + "link-arg=-Wl,--hash-style=both", + "-C", + "link-arg=-Wl,-z,max-page-size=16384" + ]; + final pageSizeArgsString = pageSizeArgs.join("\x1f"); + + rustFlags = '$rustFlags$pageSizeArgsString'; return rustFlags; } } From 8af60b27fddf0a7ae5ae37c354cfcf1b99f903bd Mon Sep 17 00:00:00 2001 From: invertedx Date: Wed, 20 Aug 2025 00:00:04 +0200 Subject: [PATCH 4/6] use latest flutter on workflow --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e39565a2..7a4add7c 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -28,7 +28,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: 'stable' - flutter-version: '3.16.3' + flutter-version: '3.35.1' - name: Install dependencies run: flutter pub get From fc2c94a1eea58380afee39f78925ed0c0f5bda84 Mon Sep 17 00:00:00 2001 From: invertedx Date: Wed, 20 Aug 2025 11:02:45 +0200 Subject: [PATCH 5/6] fix reuse license check on example project --- .reuse/dep5 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.reuse/dep5 b/.reuse/dep5 index e45f55fa..b033d8cd 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -23,6 +23,10 @@ Files: example/windows/flutter/generated* Copyright: 2024 Foundation Devices Inc. License: MIT +Files: example/android/* +Copyright: 2024 Foundation Devices Inc. +License: MIT + Files: rust/target/* Copyright: 2024 Foundation Devices Inc. License: MIT From c089d8bc1dc459c609a9f75303c4243d21eb4724 Mon Sep 17 00:00:00 2001 From: invertedx Date: Wed, 20 Aug 2025 11:18:22 +0200 Subject: [PATCH 6/6] fix flutter lints --- example/lib/main.dart | 2 +- example/pubspec.lock | 2 +- lib/socks_socket.dart | 4 ++-- lib/tor.dart | 10 +++++----- rust/Cargo.lock | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index caf92c05..59b8b8b0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -149,7 +149,7 @@ class _MyAppState extends State { "${DateTime.now().difference(time).inSeconds} " "seconds. Proxy running on port ${Tor.instance.port}"); - if (mounted) { + if (context.mounted) { Navigator.of(context).pop(); } }, diff --git a/example/pubspec.lock b/example/pubspec.lock index e01fa420..38efa0ce 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -278,7 +278,7 @@ packages: path: ".." relative: true source: path - version: "0.0.8" + version: "0.0.9" vector_math: dependency: transitive description: diff --git a/lib/socks_socket.dart b/lib/socks_socket.dart index 97c311da..d5ca64f1 100644 --- a/lib/socks_socket.dart +++ b/lib/socks_socket.dart @@ -98,12 +98,12 @@ class SOCKSSocket { /// Private constructor. SOCKSSocket._(this.proxyHost, this.proxyPort, this.sslEnabled); - /// Provides a stream of data as List. + /// Provides a stream of data as `List`. Stream> get inputStream => sslEnabled ? _secureResponseController.stream : _responseController.stream; - /// Provides a StreamSink compatible with List for sending data. + /// Provides a StreamSink compatible with `List` for sending data. StreamSink> get outputStream { // Create a simple StreamSink wrapper for _socksSocket and // _secureSocksSocket that accepts List and forwards it to write method. diff --git a/lib/tor.dart b/lib/tor.dart index 5960118f..b1b16491 100644 --- a/lib/tor.dart +++ b/lib/tor.dart @@ -14,7 +14,7 @@ import 'package:flutter/foundation.dart'; import 'package:path_provider/path_provider.dart'; import 'package:tor/generated_bindings.dart' as rust; -DynamicLibrary load(name) { +DynamicLibrary load(String name) { if (Platform.isAndroid || Platform.isLinux) { return DynamicLibrary.open('lib$name.so'); } else if (Platform.isIOS || Platform.isMacOS) { @@ -98,7 +98,7 @@ class Tor { /// Returns a Future that completes when the Tor service has started. /// /// Throws an exception if the Tor service fails to start. - static Future init({enabled = true}) async { + static Future init({bool enabled = true}) async { var singleton = Tor._instance; singleton._enabled = enabled; return singleton; @@ -227,13 +227,13 @@ class Tor { } /// Stops the proxy - stop() async { + Future stop() async { final lib = rust.NativeLibrary(_lib); lib.tor_proxy_stop(_proxyPtr); _proxyPtr = nullptr; } - setClientDormant(bool dormant) async { + Future setClientDormant(bool dormant) async { if (_clientPtr == nullptr || !started || !bootstrapped) { throw ClientNotActive(); } @@ -261,7 +261,7 @@ class Tor { })); } - static throwRustException(rust.NativeLibrary lib) { + static void throwRustException(rust.NativeLibrary lib) { String rustError = lib.tor_last_error_message().cast().toDartString(); throw _getRustException(rustError); diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2ee635f4..a74f43aa 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -3632,7 +3632,7 @@ checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "tor" -version = "0.0.8" +version = "0.0.9" dependencies = [ "anyhow", "arti",