mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-23 19:16:09 +00:00
tor updates
This commit is contained in:
parent
8644ba2069
commit
df8057986e
7 changed files with 184 additions and 97 deletions
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue