cake_wallet/lib/utils/proxy_wrapper.dart

134 lines
3.6 KiB
Dart
Raw Normal View History

2023-12-07 16:44:07 +00:00
import 'dart:io';
2024-01-08 17:33:04 +00:00
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/settings/tor_connection.dart';
2023-12-07 16:44:07 +00:00
import 'package:socks5_proxy/socks.dart';
import 'package:tor/tor.dart';
class ProxyWrapper {
// Private constructor
2024-01-08 17:33:04 +00:00
ProxyWrapper._privateConstructor(this.settingsStore);
2023-12-07 16:44:07 +00:00
// Static private instance of Tor
static final ProxyWrapper _instance = ProxyWrapper._privateConstructor();
2024-01-08 17:33:04 +00:00
final SettingsStore settingsStore;
2023-12-07 16:44:07 +00:00
2024-01-08 17:33:04 +00:00
HttpClient? _torClient;
2023-12-07 16:44:07 +00:00
// Factory method to get the singleton instance of TorSingleton
static ProxyWrapper get instance => _instance;
2023-12-11 19:34:34 +00:00
static int get port => Tor.instance.port;
2023-12-12 20:29:06 +00:00
static bool get enabled => Tor.instance.enabled;
2024-01-08 17:33:04 +00:00
bool started = false;
bool torEnabled = false;
bool torOnly = false;
2023-12-12 20:29:06 +00:00
2023-12-07 16:44:07 +00:00
// Method to get or create the Tor instance
2023-12-11 19:34:34 +00:00
Future<HttpClient> getProxyInstance({int? portOverride}) async {
2023-12-07 16:44:07 +00:00
if (!started) {
started = true;
2024-01-08 17:33:04 +00:00
_torClient = HttpClient();
2023-12-07 16:44:07 +00:00
// Assign connection factory.
2024-01-08 17:33:04 +00:00
SocksTCPClient.assignToHttpClient(_torClient!, [
2023-12-07 16:44:07 +00:00
ProxySettings(
InternetAddress.loopbackIPv4,
2023-12-11 19:34:34 +00:00
portOverride ?? Tor.instance.port,
2023-12-07 16:44:07 +00:00
password: null,
),
]);
}
2024-01-08 17:33:04 +00:00
return _torClient!;
}
Future<HttpClientResponse> get(Uri uri, {Map<String, String>? headers, int? portOverride}) async {
HttpClient? client;
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
client = await getProxyInstance(portOverride: portOverride);
} else {
client = HttpClient();
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
if (!uri.path.contains(".onion")) {
throw Exception("Cannot connect to clearnet");
}
}
HttpClientResponse? response;
try {
final request = await client.getUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
} catch (e) {
if (!torOnly && torEnabled) {
// try again without tor:
client = HttpClient();
final request = await client.getUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
}
}
return response!;
}
Future<HttpClientResponse> post(Uri uri,
{Map<String, String>? headers, int? portOverride}) async {
HttpClient? client;
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
client = await getProxyInstance(portOverride: portOverride);
} else {
client = HttpClient();
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
if (!uri.path.contains(".onion")) {
throw Exception("Cannot connect to clearnet");
}
}
HttpClientResponse? response;
try {
final request = await client.postUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
} catch (e) {
if (!torOnly && torEnabled) {
// try again without tor:
client = HttpClient();
final request = await client.postUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
}
}
return response!;
2023-12-07 16:44:07 +00:00
}
}