From 38d943a6e3b009d33f7edafe2cd8166280df6c8a Mon Sep 17 00:00:00 2001 From: Czarek Nakamoto Date: Fri, 25 Apr 2025 13:10:17 +0200 Subject: [PATCH] feat(cw_bitcoin): support socks proxy and CakeTor --- cw_bitcoin/lib/electrum.dart | 16 +++---- cw_bitcoin/pubspec.lock | 22 ++++++--- cw_bitcoin/pubspec.yaml | 4 ++ cw_core/lib/node.dart | 11 ++--- cw_core/lib/utils/proxy_socket/abstract.dart | 47 ++++++++++++++++++++ cw_core/lib/utils/proxy_socket/insecure.dart | 34 ++++++++++++++ cw_core/lib/utils/proxy_socket/secure.dart | 34 ++++++++++++++ cw_core/lib/utils/proxy_socket/socks.dart | 36 +++++++++++++++ cw_core/lib/utils/proxy_wrapper.dart | 10 ++++- cw_core/pubspec.lock | 11 ++++- cw_core/pubspec.yaml | 4 ++ cw_decred/pubspec.lock | 28 +++++++++--- cw_monero/pubspec.lock | 22 ++++++--- cw_nano/pubspec.lock | 22 ++++++--- cw_wownero/pubspec.lock | 22 ++++++--- cw_zano/pubspec.lock | 20 ++++++--- 16 files changed, 288 insertions(+), 55 deletions(-) create mode 100644 cw_core/lib/utils/proxy_socket/abstract.dart create mode 100644 cw_core/lib/utils/proxy_socket/insecure.dart create mode 100644 cw_core/lib/utils/proxy_socket/secure.dart create mode 100644 cw_core/lib/utils/proxy_socket/socks.dart diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index f265f91cc..8a78a92cc 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -5,6 +5,8 @@ import 'dart:typed_data'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_core/utils/print_verbose.dart'; +import 'package:cw_core/utils/proxy_socket/abstract.dart'; +import 'package:cw_core/utils/proxy_wrapper.dart'; import 'package:flutter/foundation.dart'; import 'package:rxdart/rxdart.dart'; @@ -42,7 +44,7 @@ class ElectrumClient { static const aliveTimerDuration = Duration(seconds: 4); bool get isConnected => _isConnected; - Socket? socket; + ProxySocket? socket; void Function(ConnectionStatus)? onConnectionStatusChange; int _id; final Map _tasks; @@ -73,17 +75,9 @@ class ElectrumClient { socket = null; try { - if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) { - socket = await Socket.connect(host, port, timeout: connectionTimeout); - } else { - socket = await SecureSocket.connect( - host, - port, - timeout: connectionTimeout, - onBadCertificate: (_) => true, - ); - } + socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, host, port, connectionTimeout: connectionTimeout); } catch (e) { + printV("connect: $e"); if (e is HandshakeException) { useSSL = !(useSSL ?? false); } diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index f71f16e78..dd52978ca 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -948,11 +948,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: "direct main" + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -1038,7 +1048,7 @@ packages: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 09369de8e..c24732c3a 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -54,6 +54,10 @@ dependencies: git: url: https://github.com/cake-tech/ledger-flutter-plus-plugins path: packages/ledger-litecoin + socks_socket: + git: + url: https://github.com/sneurlax/socks_socket + ref: e6232c53c1595469931ababa878759a067c02e94 dev_dependencies: flutter_test: diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index b59577d2b..24fa7defc 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:cw_core/keyable.dart'; +import 'package:cw_core/utils/proxy_socket/abstract.dart'; import 'package:cw_core/utils/proxy_wrapper.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'dart:convert'; @@ -303,13 +304,9 @@ class Node extends HiveObject with Keyable { // you try to communicate with it Future requestElectrumServer() async { try { - final Socket socket; - if (useSSL == true) { - socket = await SecureSocket.connect(uri.host, uri.port, - timeout: Duration(seconds: 5), onBadCertificate: (_) => true); - } else { - socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5)); - } + final ProxySocket socket; + socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port); + socket.destroy(); return true; diff --git a/cw_core/lib/utils/proxy_socket/abstract.dart b/cw_core/lib/utils/proxy_socket/abstract.dart new file mode 100644 index 000000000..b4b628f74 --- /dev/null +++ b/cw_core/lib/utils/proxy_socket/abstract.dart @@ -0,0 +1,47 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:cw_core/utils/proxy_socket/insecure.dart'; +import 'package:cw_core/utils/proxy_socket/secure.dart'; +import 'package:cw_core/utils/proxy_socket/socks.dart'; +import 'package:cw_core/utils/proxy_wrapper.dart'; +import 'package:socks_socket/socks_socket.dart'; + +class ProxyAddress { + final String host; + final int port; + + ProxyAddress({required this.host, required this.port}); +} + +abstract class ProxySocket { + static Future connect(bool sslEnabled, ProxyAddress address, {Duration? connectionTimeout}) async { + if (CakeTor.instance.started) { + var socksSocket = await SOCKSSocket.create( + proxyHost: InternetAddress.loopbackIPv4.address, + proxyPort: CakeTor.instance.port, + sslEnabled: sslEnabled, + ); + await socksSocket.connect(); + await socksSocket.connectTo(address.host, address.port); + return ProxySocketSocks(socksSocket); + } + if (sslEnabled == false) { + return ProxySocketInsecure(await Socket.connect(address.host, address.port, timeout: connectionTimeout)); + } else { + return ProxySocketSecure(await SecureSocket.connect( + address.host, + address.port, + timeout: connectionTimeout, + onBadCertificate: (_) => true, + )); + } + } + + Future close(); + Future destroy(); + Future write(String data); + StreamSubscription> listen(Function(Uint8List event) onData, {Function (Object error)? onError, Function ()? onDone, bool cancelOnError = true}); + ProxyAddress get address; +} \ No newline at end of file diff --git a/cw_core/lib/utils/proxy_socket/insecure.dart b/cw_core/lib/utils/proxy_socket/insecure.dart new file mode 100644 index 000000000..aeac474d7 --- /dev/null +++ b/cw_core/lib/utils/proxy_socket/insecure.dart @@ -0,0 +1,34 @@ + +import 'package:cw_core/utils/proxy_socket/abstract.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'dart:io'; + +class ProxySocketInsecure implements ProxySocket { + final Socket socket; + + ProxySocketInsecure(this.socket); + + ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort); + + @override + Future close() => socket.close(); + + @override + Future destroy() async => socket.destroy(); + + @override + Future write(String data) async => socket.write(data); + + @override + StreamSubscription> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { + return socket.listen( + (data) { + onData(Uint8List.fromList(data)); + }, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} \ No newline at end of file diff --git a/cw_core/lib/utils/proxy_socket/secure.dart b/cw_core/lib/utils/proxy_socket/secure.dart new file mode 100644 index 000000000..2efd13ee4 --- /dev/null +++ b/cw_core/lib/utils/proxy_socket/secure.dart @@ -0,0 +1,34 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:cw_core/utils/proxy_socket/abstract.dart'; + +class ProxySocketSecure implements ProxySocket { + final SecureSocket socket; + + ProxySocketSecure(this.socket); + + ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort); + + @override + Future close() => socket.close(); + + @override + Future destroy() async => socket.destroy(); + + @override + Future write(String data) async => socket.write(data); + + @override + StreamSubscription> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { + return socket.listen( + (data) { + onData(Uint8List.fromList(data)); + }, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} diff --git a/cw_core/lib/utils/proxy_socket/socks.dart b/cw_core/lib/utils/proxy_socket/socks.dart new file mode 100644 index 000000000..a4e5ddeb6 --- /dev/null +++ b/cw_core/lib/utils/proxy_socket/socks.dart @@ -0,0 +1,36 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:cw_core/utils/proxy_socket/abstract.dart'; +import 'package:socks_socket/socks_socket.dart'; + +class ProxySocketSocks implements ProxySocket { + final SOCKSSocket socket; + + ProxySocketSocks(this.socket); + + @override + ProxyAddress get address => ProxyAddress(host: socket.proxyHost, port: socket.proxyPort); + + @override + Future close() => socket.close(); + + @override + Future destroy() => close(); + + @override + Future write(String data) async => socket.write(data); + + @override + StreamSubscription> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { + return socket.listen( + (data) { + onData(Uint8List.fromList(data)); + }, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} + diff --git a/cw_core/lib/utils/proxy_wrapper.dart b/cw_core/lib/utils/proxy_wrapper.dart index f2c6e55ed..8e61702d1 100644 --- a/cw_core/lib/utils/proxy_wrapper.dart +++ b/cw_core/lib/utils/proxy_wrapper.dart @@ -1,14 +1,20 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; +import 'package:cw_core/utils/proxy_socket/abstract.dart'; import 'package:socks5_proxy/socks_client.dart'; +import 'package:socks_socket/socks_socket.dart'; import 'package:tor/tor.dart'; import 'package:http/io_client.dart' as ioc; - - class ProxyWrapper { ProxyWrapper(); + Future getSocksSocket(bool sslEnabled, String host, int port, {Duration? connectionTimeout}) async { + return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port), connectionTimeout: connectionTimeout); + } + ioc.IOClient getHttpIOClient() { final httpClient = ProxyWrapper().getHttpClient(); return ioc.IOClient(httpClient); diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock index 00f237f5c..1c704bee8 100644 --- a/cw_core/pubspec.lock +++ b/cw_core/pubspec.lock @@ -641,6 +641,15 @@ packages: url: "https://github.com/cake-tech/socks_dart.git" source: git version: "1.0.4" + socks_socket: + dependency: "direct main" + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -717,7 +726,7 @@ packages: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 3afb2d82d..4cc612baf 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -39,6 +39,10 @@ dependencies: # url: https://github.com/cake-tech/tor.git # ref: main tor: any + socks_socket: + git: + url: https://github.com/sneurlax/socks_socket + ref: e6232c53c1595469931ababa878759a067c02e94 dev_dependencies: flutter_test: diff --git a/cw_decred/pubspec.lock b/cw_decred/pubspec.lock index f1d4dd57a..3a8da7fb8 100644 --- a/cw_decred/pubspec.lock +++ b/cw_decred/pubspec.lock @@ -666,11 +666,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: transitive + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -751,6 +761,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + tor: + dependency: transitive + description: + name: tor + sha256: eeed80e5c912a1806c2f81825c12e84f4dc5a0b50aebedea59e3a8ba53df3142 + url: "https://pub.dev" + source: hosted + version: "0.0.8" tuple: dependency: transitive description: diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index b2f144b6b..fd1bb6e03 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -779,11 +779,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: transitive + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -860,7 +870,7 @@ packages: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index 62484f855..f34243a27 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -784,11 +784,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: transitive + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -865,7 +875,7 @@ packages: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index d61b26be9..2d7f9ba22 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -683,11 +683,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: transitive + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: @@ -764,7 +774,7 @@ packages: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" diff --git a/cw_zano/pubspec.lock b/cw_zano/pubspec.lock index 7f6e5f347..da94e96c4 100644 --- a/cw_zano/pubspec.lock +++ b/cw_zano/pubspec.lock @@ -680,11 +680,21 @@ packages: socks5_proxy: dependency: transitive description: - name: socks5_proxy - sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" - url: "https://pub.dev" - source: hosted - version: "1.0.6" + path: "." + ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + resolved-ref: d304fcfcc97cb7212bcd347aeb5d96792c128ff3 + url: "https://github.com/cake-tech/socks_dart.git" + source: git + version: "1.0.4" + socks_socket: + dependency: transitive + description: + path: "." + ref: e6232c53c1595469931ababa878759a067c02e94 + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 + url: "https://github.com/sneurlax/socks_socket" + source: git + version: "1.1.1" source_gen: dependency: transitive description: