cake_wallet/lib/utils/proxy_wrapper.dart

215 lines
5.3 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';
2024-01-12 19:53:19 +00:00
// this is the only way to ensure we're making a non-tor connection:
class NullOverrides extends HttpOverrides {
NullOverrides();
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context);
}
}
2023-12-07 16:44:07 +00:00
class ProxyWrapper {
2024-01-08 23:18:13 +00:00
ProxyWrapper({
required this.settingsStore,
});
late 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
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;
2023-12-12 20:29:06 +00:00
2024-01-08 23:18:13 +00:00
// Method to get or create the Tor proxy instance
Future<HttpClient> getProxyHttpClient({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!;
}
2024-01-12 19:53:19 +00:00
Future<HttpClientResponse> makeGet({
required HttpClient client,
required Uri uri,
required Map<String, String>? headers,
}) async {
final request = await client.getUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
return await request.close();
}
Future<HttpClientResponse> makePost({
required HttpClient client,
required Uri uri,
required Map<String, String>? headers,
}) async {
final request = await client.postUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
return await request.close();
}
Future<HttpClientResponse> get({
Map<String, String>? headers,
int? portOverride,
bool torOnly = false,
Uri? clearnetUri,
2024-01-12 19:53:19 +00:00
Uri? onionUri,
}) async {
2024-01-12 19:53:19 +00:00
HttpClient? torClient;
late bool torEnabled;
2024-01-08 17:33:04 +00:00
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
2024-01-12 19:53:19 +00:00
torClient = await getProxyHttpClient(portOverride: portOverride);
torEnabled = true;
2024-01-08 17:33:04 +00:00
} else {
torEnabled = false;
2024-01-08 17:33:04 +00:00
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
2024-01-12 19:53:19 +00:00
if (onionUri == null) {
2024-01-08 17:33:04 +00:00
throw Exception("Cannot connect to clearnet");
}
}
2024-01-12 19:53:19 +00:00
// if tor is enabled, try to connect to the onion url first:
if (torEnabled) {
if (onionUri != null) {
try {
return makeGet(
client: torClient!,
uri: onionUri,
headers: headers,
);
} catch (_) {}
}
2024-01-08 17:33:04 +00:00
2024-01-12 19:53:19 +00:00
if (clearnetUri != null && settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
try {
return makeGet(
client: torClient!,
uri: clearnetUri,
headers: headers,
);
} catch (_) {}
2024-01-08 17:33:04 +00:00
}
2024-01-12 19:53:19 +00:00
}
if (!torOnly && clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() {
return makeGet(
client: HttpClient(),
uri: clearnetUri,
headers: headers,
);
},
createHttpClient: NullOverrides().createHttpClient,
);
} catch (_) {
// we weren't able to get a response:
rethrow;
2024-01-08 17:33:04 +00:00
}
}
2024-01-12 19:53:19 +00:00
throw Exception("Unable to connect to server");
2024-01-08 17:33:04 +00:00
}
2024-01-12 19:53:19 +00:00
Future<HttpClientResponse> post({
Map<String, String>? headers,
int? portOverride,
bool torOnly = false,
Uri? clearnetUri,
2024-01-12 19:53:19 +00:00
Uri? onionUri,
}) async {
2024-01-12 19:53:19 +00:00
HttpClient? torClient;
late bool torEnabled;
2024-01-08 17:33:04 +00:00
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
2024-01-12 19:53:19 +00:00
torClient = await getProxyHttpClient(portOverride: portOverride);
torEnabled = true;
2024-01-08 17:33:04 +00:00
} else {
torEnabled = false;
2024-01-08 17:33:04 +00:00
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
2024-01-12 19:53:19 +00:00
if (onionUri == null) {
2024-01-08 17:33:04 +00:00
throw Exception("Cannot connect to clearnet");
}
}
2024-01-12 19:53:19 +00:00
// if tor is enabled, try to connect to the onion url first:
if (torEnabled) {
if (onionUri != null) {
try {
return makePost(
client: torClient!,
uri: onionUri,
headers: headers,
);
} catch (_) {}
}
2024-01-08 17:33:04 +00:00
2024-01-12 19:53:19 +00:00
if (clearnetUri != null && settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
try {
return makePost(
client: torClient!,
uri: clearnetUri,
headers: headers,
);
} catch (_) {}
2024-01-08 17:33:04 +00:00
}
2024-01-12 19:53:19 +00:00
}
if (!torOnly && clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() {
return makePost(
client: HttpClient(),
uri: clearnetUri,
headers: headers,
);
},
createHttpClient: NullOverrides().createHttpClient,
);
} catch (_) {
// we weren't able to get a response:
rethrow;
2024-01-08 17:33:04 +00:00
}
}
2024-01-12 19:53:19 +00:00
throw Exception("Unable to connect to server");
2023-12-07 16:44:07 +00:00
}
}