feat: CakeTorSocks respect SOCKS_SERVER (#2444)

cyan committed Aug 12, 2025 at 18:00 UTC b8a9863a216286b9fbcb14b5d2d79a71c45a1592
8 files changed +82 -7
cw_core/lib/utils/proxy_wrapper.dart
+1 -1
@@ -100,7 +100,7 @@ class ProxyWrapper {
100 try {
101 switch (method) {
102 case RequestMethod.get:
103 - resp = await client. get(
103 + resp = await client.get(
104 uri,
105 headers: headers,
106 );
cw_core/lib/utils/tor/abstract.dart
+26 -2
@@ -3,7 +3,7 @@ import 'dart:io';
3 import 'package:cw_core/utils/print_verbose.dart';
4 import 'package:cw_core/utils/tor/android.dart';
5 import 'package:cw_core/utils/tor/disabled.dart';
6 -import 'package:cw_core/utils/tor/tails.dart';
6 +import 'package:cw_core/utils/tor/socks.dart';
7
8 abstract class CakeTorInstance {
9 bool get started;
@@ -23,11 +23,24 @@ abstract class CakeTorInstance {
23 }
24 if (Platform.isLinux) {
25 try {
26 + String? socksServer;
27 + if (Platform.environment["SOCKS_SERVER"] != null) {
28 + socksServer = Platform.environment["SOCKS_SERVER"]!;
29 + }
30 + if (Platform.environment["SOCKS_PROXY"] != null) {
31 + socksServer = Platform.environment["SOCKS_PROXY"]!;
32 + }
33 + if (socksServer != null) {
34 + final uri = Uri.tryParse(socksServer);
35 + if (uri != null) {
36 + return CakeTorSocks(uri.port);
37 + }
38 + }
39 final os = File("/etc/os-release").readAsLinesSync();
40 for (var line in os) {
41 if (!line.startsWith("ID=")) continue;
42 if (!line.contains("tails")) continue;
30 - return CakeTorTails();
43 + return CakeTorSocks(9150);
44 }
45 } catch (e) {
46 printV("Failed to identify linux version - /etc/os-release missing");
@@ -35,4 +48,15 @@ abstract class CakeTorInstance {
48 }
49 return CakeTorDisabled();
50 }
51 +
52 + String toString() {
53 + return """
54 +CakeTorInstance(
55 + port: $port,
56 + started: $started,
57 + bootstrapped: $bootstrapped,
58 + enabled: $enabled,
59 +)
60 +""";
61 + }
62 }
\ No newline at end of file
cw_core/lib/utils/tor/android.dart
+13
@@ -70,4 +70,17 @@ DataDirectory ${p.join(dir.path, "tor-data")}
70 _proc?.stdout.transform(utf8.decoder).forEach(printV);
71 _proc?.stderr.transform(utf8.decoder).forEach(printV);
72 }
73 +
74 + @override
75 + String toString() {
76 + return """
77 +CakeTorAndroid(
78 + port: $port,
79 + started: $started,
80 + bootstrapped: $bootstrapped,
81 + enabled: $enabled,
82 + proc: $_proc,
83 +)
84 +""";
85 + }
86 }
\ No newline at end of file
cw_core/lib/utils/tor/disabled.dart
+12
@@ -18,4 +18,16 @@ class CakeTorDisabled implements CakeTorInstance {
18
19 @override
20 Future<void> stop() => throw UnimplementedError();
21 +
22 + @override
23 + String toString() {
24 + return """
25 +CakeTorDisabled(
26 + port: $port,
27 + started: $started,
28 + bootstrapped: $bootstrapped,
29 + enabled: $enabled,
30 +)
31 +""";
32 + }
33 }
\ No newline at end of file
cw_core/lib/utils/tor/socks.dart renamed
+15 -2
@@ -1,6 +1,7 @@
1 import 'package:cw_core/utils/tor/abstract.dart';
2
3 -class CakeTorTails implements CakeTorInstance {
3 +class CakeTorSocks implements CakeTorInstance {
4 + CakeTorSocks(this.port);
5 @override
6 bool get bootstrapped => true;
7
@@ -8,7 +9,7 @@ class CakeTorTails implements CakeTorInstance {
9 bool get enabled => true;
10
11 @override
11 - int get port => 9150;
12 + int port;
13
14 @override
15 Future<void> start() async {}
@@ -18,4 +19,16 @@ class CakeTorTails implements CakeTorInstance {
19
20 @override
21 Future<void> stop() async {}
22 +
23 + @override
24 + String toString() {
25 + return """
26 +CakeTorSocks(
27 + port: $port,
28 + started: $started,
29 + bootstrapped: $bootstrapped,
30 + enabled: $enabled,
31 +)
32 +""";
33 + }
34 }
\ No newline at end of file
lib/src/screens/dev/network_requests.dart
+11
@@ -5,8 +5,11 @@ import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/view_model/dev/network_requests_view_model.dart';
6 import 'package:cw_core/utils/proxy_logger/abstract.dart';
7 import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
8 +import 'package:cw_core/utils/proxy_wrapper.dart';
9 +import 'package:cw_core/utils/tor/abstract.dart';
10 import 'package:flutter/material.dart';
11 import 'package:flutter_mobx/flutter_mobx.dart';
12 +import 'package:on_chain/solana/solana.dart';
13
14 class DevNetworkRequests extends BasePage {
15 final NetworkRequestsViewModel viewModel = NetworkRequestsViewModel();
@@ -120,6 +123,14 @@ class DevRequestDetails extends BasePage {
123 _sectionTitle("Network"),
124 SelectableText(req.network.toString()),
125
126 + if (req.network == RequestNetwork.tor)
127 + ...[
128 + _sectionTitle("Tor socks server"),
129 + SelectableText(CakeTor.instance.runtimeType.toString()),
130 + _sectionTitle("Tor socks details"),
131 + SelectableText(CakeTor.instance.toString()),
132 + ],
133 +
134 _sectionTitle("Body (as UTF-8)"),
135 SelectableText(_tryDecodeBody(req.body)),
136
lib/utils/feature_flag.dart
+3 -2
@@ -1,12 +1,13 @@
1 +import 'package:cw_core/utils/proxy_wrapper.dart';
2 +import 'package:cw_core/utils/tor/disabled.dart';
3 import 'package:flutter/foundation.dart';
2 -import 'dart:io';
4
5 class FeatureFlag {
6 static const bool isCakePayEnabled = false;
7 static const bool isCakePayRedemptionFlowEnabled = false;
8 static const bool isExolixEnabled = true;
9 static const bool isBackgroundSyncEnabled = true;
9 - static final bool isInAppTorEnabled = (Platform.isAndroid);
10 + static final bool isInAppTorEnabled = CakeTor.instance is! CakeTorDisabled;
11 static const int verificationWordsCount = kDebugMode ? 0 : 2;
12 static const bool hasDevOptions = bool.fromEnvironment('hasDevOptions', defaultValue: kDebugMode);
13 static const bool hasBitcoinViewOnly = true;
lib/utils/tor.dart
+1
@@ -1,4 +1,5 @@
1 import 'dart:async';
2 +import 'dart:io';
3
4 import 'package:cw_core/utils/proxy_wrapper.dart';
5 import 'package:cw_core/utils/print_verbose.dart';