mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
WIP proxied sockets
This commit is contained in:
parent
ec5ae60a61
commit
281cd98390
3 changed files with 199 additions and 40 deletions
|
@ -15,6 +15,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:stackwallet/electrumx_rpc/rpc.dart';
|
import 'package:stackwallet/electrumx_rpc/rpc.dart';
|
||||||
import 'package:stackwallet/exceptions/electrumx/no_such_transaction.dart';
|
import 'package:stackwallet/exceptions/electrumx/no_such_transaction.dart';
|
||||||
|
import 'package:stackwallet/networking/tor_service.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/prefs.dart';
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
@ -71,6 +72,8 @@ class ElectrumX {
|
||||||
|
|
||||||
final Duration connectionTimeoutForSpecialCaseJsonRPCClients;
|
final Duration connectionTimeoutForSpecialCaseJsonRPCClients;
|
||||||
|
|
||||||
|
({String host, int port})? proxyInfo;
|
||||||
|
|
||||||
ElectrumX({
|
ElectrumX({
|
||||||
required String host,
|
required String host,
|
||||||
required int port,
|
required int port,
|
||||||
|
@ -80,6 +83,7 @@ class ElectrumX {
|
||||||
JsonRPC? client,
|
JsonRPC? client,
|
||||||
this.connectionTimeoutForSpecialCaseJsonRPCClients =
|
this.connectionTimeoutForSpecialCaseJsonRPCClients =
|
||||||
const Duration(seconds: 60),
|
const Duration(seconds: 60),
|
||||||
|
({String host, int port})? proxyInfo,
|
||||||
}) {
|
}) {
|
||||||
_prefs = prefs;
|
_prefs = prefs;
|
||||||
_host = host;
|
_host = host;
|
||||||
|
@ -92,14 +96,38 @@ class ElectrumX {
|
||||||
required ElectrumXNode node,
|
required ElectrumXNode node,
|
||||||
required Prefs prefs,
|
required Prefs prefs,
|
||||||
required List<ElectrumXNode> failovers,
|
required List<ElectrumXNode> failovers,
|
||||||
}) =>
|
({String host, int port})? proxyInfo,
|
||||||
ElectrumX(
|
}) {
|
||||||
|
if (Prefs.instance.useTor) {
|
||||||
|
if (proxyInfo == null) {
|
||||||
|
// TODO await tor / make sure it's running
|
||||||
|
proxyInfo = (
|
||||||
|
host: InternetAddress.loopbackIPv4.address,
|
||||||
|
port: TorService.sharedInstance.port
|
||||||
|
);
|
||||||
|
Logging.instance.log(
|
||||||
|
"ElectrumX.batchRequest(): no tor proxy info, read $proxyInfo",
|
||||||
|
level: LogLevel.Warning);
|
||||||
|
}
|
||||||
|
return ElectrumX(
|
||||||
host: node.address,
|
host: node.address,
|
||||||
port: node.port,
|
port: node.port,
|
||||||
useSSL: node.useSSL,
|
useSSL: node.useSSL,
|
||||||
prefs: prefs,
|
prefs: prefs,
|
||||||
failovers: failovers,
|
failovers: failovers,
|
||||||
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return ElectrumX(
|
||||||
|
host: node.address,
|
||||||
|
port: node.port,
|
||||||
|
useSSL: node.useSSL,
|
||||||
|
prefs: prefs,
|
||||||
|
failovers: failovers,
|
||||||
|
proxyInfo: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> _allow() async {
|
Future<bool> _allow() async {
|
||||||
if (_prefs.wifiOnly) {
|
if (_prefs.wifiOnly) {
|
||||||
|
@ -121,12 +149,24 @@ class ElectrumX {
|
||||||
throw WifiOnlyException();
|
throw WifiOnlyException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Prefs.instance.useTor) {
|
||||||
|
if (proxyInfo == null) {
|
||||||
|
// TODO await tor / make sure Tor is running
|
||||||
|
proxyInfo = (
|
||||||
|
host: InternetAddress.loopbackIPv4.address,
|
||||||
|
port: TorService.sharedInstance.port
|
||||||
|
);
|
||||||
|
Logging.instance.log(
|
||||||
|
"ElectrumX.batchRequest(): no tor proxy info, read $proxyInfo",
|
||||||
|
level: LogLevel.Warning);
|
||||||
|
}
|
||||||
if (currentFailoverIndex == -1) {
|
if (currentFailoverIndex == -1) {
|
||||||
_rpcClient ??= JsonRPC(
|
_rpcClient ??= JsonRPC(
|
||||||
host: host,
|
host: host,
|
||||||
port: port,
|
port: port,
|
||||||
useSSL: useSSL,
|
useSSL: useSSL,
|
||||||
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_rpcClient = JsonRPC(
|
_rpcClient = JsonRPC(
|
||||||
|
@ -134,8 +174,28 @@ class ElectrumX {
|
||||||
port: failovers![currentFailoverIndex].port,
|
port: failovers![currentFailoverIndex].port,
|
||||||
useSSL: failovers![currentFailoverIndex].useSSL,
|
useSSL: failovers![currentFailoverIndex].useSSL,
|
||||||
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (currentFailoverIndex == -1) {
|
||||||
|
_rpcClient ??= JsonRPC(
|
||||||
|
host: host,
|
||||||
|
port: port,
|
||||||
|
useSSL: useSSL,
|
||||||
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_rpcClient = JsonRPC(
|
||||||
|
host: failovers![currentFailoverIndex].address,
|
||||||
|
port: failovers![currentFailoverIndex].port,
|
||||||
|
useSSL: failovers![currentFailoverIndex].useSSL,
|
||||||
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final requestId = requestID ?? const Uuid().v1();
|
final requestId = requestID ?? const Uuid().v1();
|
||||||
|
@ -221,12 +281,25 @@ class ElectrumX {
|
||||||
throw WifiOnlyException();
|
throw WifiOnlyException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Prefs.instance.useTor) {
|
||||||
|
// TODO await tor / make sure Tor is initialized
|
||||||
|
if (proxyInfo == null) {
|
||||||
|
proxyInfo = (
|
||||||
|
host: InternetAddress.loopbackIPv4.address,
|
||||||
|
port: TorService.sharedInstance.port
|
||||||
|
);
|
||||||
|
Logging.instance.log(
|
||||||
|
"ElectrumX.batchRequest(): no tor proxy info, read $proxyInfo",
|
||||||
|
level: LogLevel.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentFailoverIndex == -1) {
|
if (currentFailoverIndex == -1) {
|
||||||
_rpcClient ??= JsonRPC(
|
_rpcClient ??= JsonRPC(
|
||||||
host: host,
|
host: host,
|
||||||
port: port,
|
port: port,
|
||||||
useSSL: useSSL,
|
useSSL: useSSL,
|
||||||
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_rpcClient = JsonRPC(
|
_rpcClient = JsonRPC(
|
||||||
|
@ -234,8 +307,28 @@ class ElectrumX {
|
||||||
port: failovers![currentFailoverIndex].port,
|
port: failovers![currentFailoverIndex].port,
|
||||||
useSSL: failovers![currentFailoverIndex].useSSL,
|
useSSL: failovers![currentFailoverIndex].useSSL,
|
||||||
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (currentFailoverIndex == -1) {
|
||||||
|
_rpcClient ??= JsonRPC(
|
||||||
|
host: host,
|
||||||
|
port: port,
|
||||||
|
useSSL: useSSL,
|
||||||
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_rpcClient = JsonRPC(
|
||||||
|
host: failovers![currentFailoverIndex].address,
|
||||||
|
port: failovers![currentFailoverIndex].port,
|
||||||
|
useSSL: failovers![currentFailoverIndex].useSSL,
|
||||||
|
connectionTimeout: connectionTimeoutForSpecialCaseJsonRPCClients,
|
||||||
|
proxyInfo: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final List<String> requestStrings = [];
|
final List<String> requestStrings = [];
|
||||||
|
|
|
@ -14,7 +14,11 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
|
import 'package:socks5_proxy/socks.dart';
|
||||||
|
import 'package:socks5_proxy/src/client/socks_client.dart';
|
||||||
|
import 'package:stackwallet/networking/tor_service.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
|
||||||
// Json RPC class to handle connecting to electrumx servers
|
// Json RPC class to handle connecting to electrumx servers
|
||||||
class JsonRPC {
|
class JsonRPC {
|
||||||
|
@ -23,11 +27,13 @@ class JsonRPC {
|
||||||
required this.port,
|
required this.port,
|
||||||
this.useSSL = false,
|
this.useSSL = false,
|
||||||
this.connectionTimeout = const Duration(seconds: 60),
|
this.connectionTimeout = const Duration(seconds: 60),
|
||||||
|
required ({String host, int port})? proxyInfo,
|
||||||
});
|
});
|
||||||
final bool useSSL;
|
final bool useSSL;
|
||||||
final String host;
|
final String host;
|
||||||
final int port;
|
final int port;
|
||||||
final Duration connectionTimeout;
|
final Duration connectionTimeout;
|
||||||
|
({String host, int port})? proxyInfo;
|
||||||
|
|
||||||
final _requestMutex = Mutex();
|
final _requestMutex = Mutex();
|
||||||
final _JsonRPCRequestQueue _requestQueue = _JsonRPCRequestQueue();
|
final _JsonRPCRequestQueue _requestQueue = _JsonRPCRequestQueue();
|
||||||
|
@ -152,6 +158,62 @@ class JsonRPC {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Prefs.instance.useTor) {
|
||||||
|
if (proxyInfo == null) {
|
||||||
|
// TODO await tor / make sure it's running
|
||||||
|
proxyInfo = (
|
||||||
|
host: InternetAddress.loopbackIPv4.address,
|
||||||
|
port: TorService.sharedInstance.port
|
||||||
|
);
|
||||||
|
Logging.instance.log(
|
||||||
|
"ElectrumX.connect(): no tor proxy info, read $proxyInfo",
|
||||||
|
level: LogLevel.Warning);
|
||||||
|
}
|
||||||
|
// TODO connect to proxy socket...
|
||||||
|
// https://github.com/LacticWhale/socks_dart/blob/master/lib/src/client/socks_client.dart#L50C46-L50C56
|
||||||
|
|
||||||
|
// TODO implement ssl over tor
|
||||||
|
// if (useSSL) {
|
||||||
|
// _socket = await SecureSocket.connect(
|
||||||
|
// host,
|
||||||
|
// port,
|
||||||
|
// timeout: connectionTimeout,
|
||||||
|
// onBadCertificate: (_) => true,
|
||||||
|
// ); // TODO do not automatically trust bad certificates
|
||||||
|
// final _client = SocksSocket.protected(_socket, type);
|
||||||
|
// } else {
|
||||||
|
// _socket = await Socket.connect(
|
||||||
|
// proxyInfo!.host,
|
||||||
|
// proxyInfo!.port,
|
||||||
|
// timeout: connectionTimeout,
|
||||||
|
// );
|
||||||
|
// final _client = SocksSocket.protected(
|
||||||
|
// _socket!, SocksConnectionType.connect
|
||||||
|
// );
|
||||||
|
final InternetAddress _host =
|
||||||
|
await InternetAddress.lookup(host).then((value) => value.first);
|
||||||
|
var _socket = await SocksSocket.initialize(
|
||||||
|
[
|
||||||
|
ProxySettings(
|
||||||
|
InternetAddress.loopbackIPv4,
|
||||||
|
proxyInfo!.port,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
_host,
|
||||||
|
port,
|
||||||
|
SocksConnectionType.connect,
|
||||||
|
);
|
||||||
|
if (_socket == null) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"JsonRPC.connect(): failed to connect to $host over tor proxy at $proxyInfo",
|
||||||
|
level: LogLevel.Error);
|
||||||
|
throw Exception("JsonRPC.connect(): failed to connect to tor proxy");
|
||||||
|
} else {
|
||||||
|
Logging.instance.log(
|
||||||
|
"JsonRPC.connect(): connected to $host over tor proxy at $proxyInfo",
|
||||||
|
level: LogLevel.Info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (useSSL) {
|
if (useSSL) {
|
||||||
_socket = await SecureSocket.connect(
|
_socket = await SecureSocket.connect(
|
||||||
host,
|
host,
|
||||||
|
@ -166,6 +228,7 @@ class JsonRPC {
|
||||||
timeout: connectionTimeout,
|
timeout: connectionTimeout,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_subscription = _socket!.listen(
|
_subscription = _socket!.listen(
|
||||||
_dataHandler,
|
_dataHandler,
|
||||||
|
|
|
@ -11,6 +11,7 @@ void main() {
|
||||||
port: DefaultNodes.bitcoin.port,
|
port: DefaultNodes.bitcoin.port,
|
||||||
useSSL: true,
|
useSSL: true,
|
||||||
connectionTimeout: const Duration(seconds: 40),
|
connectionTimeout: const Duration(seconds: 40),
|
||||||
|
proxyInfo: null, // TODO test for proxyInfo
|
||||||
);
|
);
|
||||||
|
|
||||||
const jsonRequestString =
|
const jsonRequestString =
|
||||||
|
@ -27,7 +28,8 @@ void main() {
|
||||||
final jsonRPC = JsonRPC(
|
final jsonRPC = JsonRPC(
|
||||||
host: "some.bad.address.thingdsfsdfsdaf",
|
host: "some.bad.address.thingdsfsdfsdaf",
|
||||||
port: 3000,
|
port: 3000,
|
||||||
connectionTimeout: Duration(seconds: 10),
|
connectionTimeout: const Duration(seconds: 10),
|
||||||
|
proxyInfo: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const jsonRequestString =
|
const jsonRequestString =
|
||||||
|
@ -47,6 +49,7 @@ void main() {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
useSSL: false,
|
useSSL: false,
|
||||||
connectionTimeout: const Duration(seconds: 1),
|
connectionTimeout: const Duration(seconds: 1),
|
||||||
|
proxyInfo: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const jsonRequestString =
|
const jsonRequestString =
|
||||||
|
|
Loading…
Reference in a new issue