mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-27 06:18:50 +01:00
Upstream reformatted its whole tree in 16ddc0837. Matching it removes
formatting from the conflict surface of this and every later sync.
442 lines
11 KiB
Dart
442 lines
11 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
import 'package:cw_core/utils/proxy_logger/abstract.dart';
|
|
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
|
import 'package:cw_core/utils/tor/abstract.dart';
|
|
import 'package:http/http.dart';
|
|
import 'package:socks5_proxy/socks_client.dart';
|
|
import 'package:http/io_client.dart' as ioc;
|
|
|
|
class ProxyWrapper {
|
|
static final ProxyWrapper _proxyWrapper = ProxyWrapper._internal();
|
|
static ProxyLogger? logger;
|
|
|
|
factory ProxyWrapper() {
|
|
return _proxyWrapper;
|
|
}
|
|
|
|
ProxyWrapper._internal();
|
|
Future<ProxySocket> getSocksSocket(bool sslEnabled, String host, int port,
|
|
{Duration? connectionTimeout}) async {
|
|
logger?.log(
|
|
uri: Uri(
|
|
scheme: sslEnabled ? "https" : "http",
|
|
host: host,
|
|
port: port,
|
|
),
|
|
method: RequestMethod.newProxySocket,
|
|
body: Uint8List(0),
|
|
response: null,
|
|
network: requestNetwork(),
|
|
error: null);
|
|
return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port),
|
|
connectionTimeout: connectionTimeout);
|
|
}
|
|
|
|
RequestNetwork requestNetwork() {
|
|
return CakeTor.instance!.started ? RequestNetwork.tor : RequestNetwork.clearnet;
|
|
}
|
|
|
|
ioc.IOClient getHttpIOClient({int? portOverride, bool internal = false}) {
|
|
if (!internal) {
|
|
logger?.log(
|
|
uri: null,
|
|
method: RequestMethod.newHttpIOClient,
|
|
body: Uint8List(0),
|
|
response: null,
|
|
network: requestNetwork(),
|
|
error: null,
|
|
);
|
|
}
|
|
// ignore: deprecated_member_use_from_same_package
|
|
final httpClient = ProxyWrapper().getHttpClient(portOverride: portOverride, internal: true);
|
|
return ioc.IOClient(httpClient);
|
|
}
|
|
|
|
int getPort() => CakeTor.instance!.port;
|
|
|
|
@Deprecated(
|
|
'Use ProxyWrapper().get/post/put methods instead, and provide proper clearnet and onion uri.')
|
|
HttpClient getHttpClient({int? portOverride, bool internal = false}) {
|
|
if (!internal) {
|
|
logger?.log(
|
|
uri: null,
|
|
method: RequestMethod.newProxySocket,
|
|
body: Uint8List(0),
|
|
response: null,
|
|
network: requestNetwork(),
|
|
error: null);
|
|
}
|
|
if (CakeTor.instance!.started) {
|
|
// Assign connection factory.
|
|
final client = HttpClient();
|
|
SocksTCPClient.assignToHttpClient(client, [
|
|
ProxySettings(
|
|
InternetAddress.loopbackIPv4,
|
|
CakeTor.instance!.port,
|
|
password: null,
|
|
),
|
|
]);
|
|
return client;
|
|
} else {
|
|
return HttpClient();
|
|
}
|
|
}
|
|
|
|
Future<Response> _make({
|
|
required RequestMethod method,
|
|
required ioc.IOClient client,
|
|
required Uri uri,
|
|
required Map<String, String>? headers,
|
|
String? body,
|
|
}) async {
|
|
Object? error;
|
|
Response? resp;
|
|
try {
|
|
switch (method) {
|
|
case RequestMethod.get:
|
|
resp = await client.get(
|
|
uri,
|
|
headers: headers,
|
|
);
|
|
break;
|
|
case RequestMethod.delete:
|
|
resp = await client.delete(
|
|
uri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
break;
|
|
case RequestMethod.post:
|
|
resp = await client.post(
|
|
uri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
break;
|
|
case RequestMethod.put:
|
|
resp = await client.put(
|
|
uri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
break;
|
|
case RequestMethod.newHttpClient:
|
|
case RequestMethod.newHttpIOClient:
|
|
case RequestMethod.newProxySocket:
|
|
throw UnimplementedError();
|
|
}
|
|
return resp;
|
|
} catch (e) {
|
|
error = e;
|
|
rethrow;
|
|
} finally {
|
|
logger?.log(
|
|
uri: uri,
|
|
method: RequestMethod.get,
|
|
body: utf8.encode(body ?? ''),
|
|
response: resp,
|
|
network: requestNetwork(),
|
|
error: error?.toString(),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<Response> get({
|
|
Map<String, String>? headers,
|
|
int? portOverride,
|
|
Uri? clearnetUri,
|
|
Uri? onionUri,
|
|
}) async {
|
|
ioc.IOClient? torClient;
|
|
bool torEnabled = CakeTor.instance!.started;
|
|
|
|
if (CakeTor.instance!.started) {
|
|
torEnabled = true;
|
|
} else {
|
|
torEnabled = false;
|
|
}
|
|
|
|
// if tor is enabled, try to connect to the onion url first:
|
|
if (torEnabled) {
|
|
try {
|
|
// ignore: deprecated_member_use_from_same_package
|
|
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
|
|
if (onionUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.get,
|
|
client: torClient,
|
|
uri: onionUri,
|
|
headers: headers,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.get,
|
|
client: torClient,
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return HttpOverrides.runZoned(
|
|
() async {
|
|
return await _make(
|
|
method: RequestMethod.get,
|
|
client: ioc.IOClient(),
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
);
|
|
},
|
|
);
|
|
} catch (_) {
|
|
// we weren't able to get a response:
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
throw Exception("Unable to connect to server");
|
|
}
|
|
|
|
Future<Response> post({
|
|
Map<String, String>? headers,
|
|
int? portOverride,
|
|
Uri? clearnetUri,
|
|
Uri? onionUri,
|
|
String? body,
|
|
bool allowMitmMoneroBypassSSLCheck = false,
|
|
}) async {
|
|
HttpClient? torHttpClient;
|
|
HttpClient cleatnetHttpClient = HttpClient();
|
|
if (allowMitmMoneroBypassSSLCheck) {
|
|
cleatnetHttpClient.badCertificateCallback =
|
|
((X509Certificate cert, String host, int port) => true);
|
|
}
|
|
|
|
ioc.IOClient clearnetClient = ioc.IOClient(cleatnetHttpClient);
|
|
|
|
bool torEnabled = CakeTor.instance!.started;
|
|
|
|
if (torEnabled) {
|
|
try {
|
|
// ignore: deprecated_member_use_from_same_package
|
|
torHttpClient = await getHttpClient(portOverride: portOverride);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
if (allowMitmMoneroBypassSSLCheck) {
|
|
torHttpClient.badCertificateCallback =
|
|
((X509Certificate cert, String host, int port) => true);
|
|
}
|
|
if (onionUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.post,
|
|
client: ioc.IOClient(torHttpClient),
|
|
uri: onionUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.post,
|
|
client: ioc.IOClient(torHttpClient),
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return HttpOverrides.runZoned(
|
|
() async {
|
|
return await _make(
|
|
method: RequestMethod.post,
|
|
client: clearnetClient,
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
},
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
throw Exception("Unable to connect to server");
|
|
}
|
|
|
|
Future<Response> put({
|
|
Map<String, String>? headers,
|
|
int? portOverride,
|
|
Uri? clearnetUri,
|
|
Uri? onionUri,
|
|
String? body,
|
|
}) async {
|
|
ioc.IOClient? torClient;
|
|
bool torEnabled = CakeTor.instance!.started;
|
|
|
|
if (torEnabled) {
|
|
try {
|
|
// ignore: deprecated_member_use_from_same_package
|
|
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
|
} catch (_) {}
|
|
|
|
if (onionUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.put,
|
|
client: torClient!,
|
|
uri: onionUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.put,
|
|
client: torClient!,
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return HttpOverrides.runZoned(
|
|
() async {
|
|
return await _make(
|
|
method: RequestMethod.put,
|
|
client: ioc.IOClient(),
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
body: body,
|
|
);
|
|
},
|
|
);
|
|
} catch (_) {
|
|
// we weren't able to get a response:
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
throw Exception("Unable to connect to server");
|
|
}
|
|
|
|
Future<Response> delete({
|
|
Map<String, String>? headers,
|
|
int? portOverride,
|
|
Uri? clearnetUri,
|
|
Uri? onionUri,
|
|
}) async {
|
|
ioc.IOClient? torClient;
|
|
bool torEnabled = CakeTor.instance!.started;
|
|
|
|
if (CakeTor.instance!.started) {
|
|
torEnabled = true;
|
|
} else {
|
|
torEnabled = false;
|
|
}
|
|
|
|
// if tor is enabled, try to connect to the onion url first:
|
|
if (torEnabled) {
|
|
try {
|
|
// ignore: deprecated_member_use_from_same_package
|
|
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
|
|
if (onionUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.delete,
|
|
client: torClient,
|
|
uri: onionUri,
|
|
headers: headers,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return await _make(
|
|
method: RequestMethod.delete,
|
|
client: torClient,
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
);
|
|
} catch (_) {
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clearnetUri != null) {
|
|
try {
|
|
return HttpOverrides.runZoned(
|
|
() async {
|
|
return await _make(
|
|
method: RequestMethod.delete,
|
|
client: ioc.IOClient(),
|
|
uri: clearnetUri,
|
|
headers: headers,
|
|
);
|
|
},
|
|
);
|
|
} catch (_) {
|
|
// we weren't able to get a response:
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
throw Exception("Unable to connect to server");
|
|
}
|
|
}
|
|
|
|
class CakeTor {
|
|
static CakeTorInstance? instance;
|
|
}
|