tor updates

This commit is contained in:
fosse 2024-01-12 14:53:19 -05:00
parent 8644ba2069
commit df8057986e
7 changed files with 184 additions and 97 deletions

View file

@ -40,10 +40,10 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
// the proxywrapper class wraps all of the complexity of retrying on clearnet / settings handling:
try {
httpResponse = await proxy.get(
onionUri,
onionUri: onionUri,
clearnetUri: clearnetUri,
portOverride: mainThreadProxyPort,
torOnly: torOnly,
clearnetUri: clearnetUri,
);
responseBody = await utf8.decodeStream(httpResponse);
statusCode = httpResponse.statusCode;
@ -71,7 +71,15 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
Future<double> _fetchPriceAsync(
CryptoCurrency crypto, FiatCurrency fiat, bool torOnly, bool onionOnly) async =>
compute(_fetchPrice, {
// compute(_fetchPrice, {
// 'fiat': fiat.toString(),
// 'crypto': crypto.toString(),
// 'torOnly': torOnly,
// 'onionOnly': onionOnly,
// 'port': ProxyWrapper.port,
// 'torEnabled': ProxyWrapper.enabled,
// });
_fetchPrice({
'fiat': fiat.toString(),
'crypto': crypto.toString(),
'torOnly': torOnly,

View file

@ -1,17 +1,13 @@
import 'dart:io';
import 'package:cake_wallet/core/generate_wallet_password.dart';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/settings/tor_connection.dart';
import 'package:cake_wallet/view_model/settings/tor_view_model.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tor/tor.dart';
class WalletLoadingService {
WalletLoadingService(

View file

@ -61,6 +61,7 @@ import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/proxy_wrapper.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
@ -726,6 +727,7 @@ Future<void> setup({
getIt.registerFactory(() => TrocadorProvidersViewModel(getIt.get<SettingsStore>()));
getIt.registerSingleton(TorViewModel(getIt.get<SettingsStore>()));
getIt.registerSingleton(ProxyWrapper(settingsStore: getIt.get<SettingsStore>()));
if (DeviceInfo.instance.isMobile && settingsStore.shouldStartTorOnLaunch) {
getIt.get<TorViewModel>().startTor();

View file

@ -309,6 +309,10 @@ class TrocadorExchangeProvider extends ExchangeProvider {
ProxyWrapper proxy = await getIt.get<ProxyWrapper>();
Uri onionUri = Uri.http(onionApiAuthority, path, queryParams);
Uri clearnetUri = Uri.http(onionApiAuthority, path, queryParams);
return await proxy.get(onionUri, torOnly: useTorOnly, clearnetUri: clearnetUri);
return await proxy.get(
onionUri: onionUri,
clearnetUri: clearnetUri,
torOnly: useTorOnly,
);
}
}

View file

@ -5,6 +5,16 @@ import 'package:cake_wallet/view_model/settings/tor_connection.dart';
import 'package:socks5_proxy/socks.dart';
import 'package:tor/tor.dart';
// 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);
}
}
class ProxyWrapper {
ProxyWrapper({
required this.settingsStore,
@ -14,16 +24,11 @@ class ProxyWrapper {
HttpClient? _torClient;
// Factory method to get the singleton instance of TorSingleton
// static ProxyWrapper get instance => _instance;
static int get port => Tor.instance.port;
static bool get enabled => Tor.instance.enabled;
bool started = false;
// bool torEnabled = false;
// bool torOnly = false;
// Method to get or create the Tor proxy instance
Future<HttpClient> getProxyHttpClient({int? portOverride}) async {
@ -44,113 +49,166 @@ class ProxyWrapper {
return _torClient!;
}
Future<HttpClientResponse> get(
Uri uri, {
Map<String, String>? headers,
int? portOverride,
bool torOnly = false,
Uri? clearnetUri,
Future<HttpClientResponse> makeGet({
required HttpClient client,
required Uri uri,
required Map<String, String>? headers,
}) async {
HttpClient? client;
late bool torEnabled;
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
client = await getProxyHttpClient(portOverride: portOverride);
torEnabled = true;
} else {
client = HttpClient();
torEnabled = false;
final request = await client.getUrl(uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
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 &&
settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
// try again without tor:
client = HttpClient();
final request = await client.getUrl(clearnetUri ?? uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
} else {
throw e;
}
}
return response;
return await request.close();
}
Future<HttpClientResponse> post(
Uri uri, {
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,
Uri? onionUri,
}) async {
HttpClient? client;
HttpClient? torClient;
late bool torEnabled;
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
client = await getProxyHttpClient(portOverride: portOverride);
torClient = await getProxyHttpClient(portOverride: portOverride);
torEnabled = true;
} else {
client = HttpClient();
torEnabled = false;
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
if (!uri.path.contains(".onion")) {
if (onionUri == null) {
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);
});
// 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 (_) {}
}
response = await request.close();
} catch (e) {
if (!torOnly &&
torEnabled &&
settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
// try again without tor:
client = HttpClient();
final request = await client.postUrl(clearnetUri ?? uri);
if (headers != null) {
headers.forEach((key, value) {
request.headers.add(key, value);
});
}
response = await request.close();
} else {
throw e;
if (clearnetUri != null && settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
try {
return makeGet(
client: torClient!,
uri: clearnetUri,
headers: headers,
);
} catch (_) {}
}
}
return response;
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;
}
}
throw Exception("Unable to connect to server");
}
Future<HttpClientResponse> post({
Map<String, String>? headers,
int? portOverride,
bool torOnly = false,
Uri? clearnetUri,
Uri? onionUri,
}) async {
HttpClient? torClient;
late bool torEnabled;
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
torClient = await getProxyHttpClient(portOverride: portOverride);
torEnabled = true;
} else {
torEnabled = false;
}
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
if (onionUri == null) {
throw Exception("Cannot connect to clearnet");
}
}
// 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 (_) {}
}
if (clearnetUri != null && settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
try {
return makePost(
client: torClient!,
uri: clearnetUri,
headers: headers,
);
} catch (_) {}
}
}
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;
}
}
throw Exception("Unable to connect to server");
}
}

View file

@ -5,6 +5,7 @@ import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/settings/tor_connection.dart';
import 'package:mobx/mobx.dart';
import 'package:socks5_proxy/socks_client.dart';
import 'package:tor/tor.dart';
part 'tor_view_model.g.dart';
@ -44,13 +45,26 @@ abstract class TorViewModelBase with Store {
Future<void> startTor() async {
try {
torConnectionStatus = TorConnectionStatus.connecting;
await Tor.init();
await Tor.instance.enable();
// start only if not already running:
if (Tor.instance.port == -1) {
await Tor.instance.enable();
}
_settingsStore.shouldStartTorOnLaunch = true;
torConnectionStatus = TorConnectionStatus.connected;
SocksTCPClient.setProxy(proxies: [
ProxySettings(
InternetAddress.loopbackIPv4,
Tor.instance.port,
password: null,
),
]);
// connect to node through the proxy:
final appStore = getIt.get<AppStore>();
if (appStore.wallet != null) {
@ -70,5 +84,6 @@ abstract class TorViewModelBase with Store {
Tor.instance.disable();
_settingsStore.shouldStartTorOnLaunch = false;
torConnectionStatus = TorConnectionStatus.disconnected;
SocksTCPClient.setProxy(proxies: null);
}
}

View file

@ -102,7 +102,11 @@ dependencies:
git:
url: https://github.com/cake-tech/tor.git
ref: main
socks5_proxy: ^1.0.4
# socks5_proxy: ^1.0.4
socks5_proxy:
git:
url: https://github.com/perishllc/socks_dart.git
ref: main
flutter_svg: ^2.0.9
polyseed: ^0.0.2