mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-24 03:26:38 +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:
|
// the proxywrapper class wraps all of the complexity of retrying on clearnet / settings handling:
|
||||||
try {
|
try {
|
||||||
httpResponse = await proxy.get(
|
httpResponse = await proxy.get(
|
||||||
onionUri,
|
onionUri: onionUri,
|
||||||
|
clearnetUri: clearnetUri,
|
||||||
portOverride: mainThreadProxyPort,
|
portOverride: mainThreadProxyPort,
|
||||||
torOnly: torOnly,
|
torOnly: torOnly,
|
||||||
clearnetUri: clearnetUri,
|
|
||||||
);
|
);
|
||||||
responseBody = await utf8.decodeStream(httpResponse);
|
responseBody = await utf8.decodeStream(httpResponse);
|
||||||
statusCode = httpResponse.statusCode;
|
statusCode = httpResponse.statusCode;
|
||||||
|
@ -71,7 +71,15 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
|
||||||
|
|
||||||
Future<double> _fetchPriceAsync(
|
Future<double> _fetchPriceAsync(
|
||||||
CryptoCurrency crypto, FiatCurrency fiat, bool torOnly, bool onionOnly) async =>
|
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(),
|
'fiat': fiat.toString(),
|
||||||
'crypto': crypto.toString(),
|
'crypto': crypto.toString(),
|
||||||
'torOnly': torOnly,
|
'torOnly': torOnly,
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||||
import 'package:cake_wallet/core/key_service.dart';
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/entities/preferences_key.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/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:cake_wallet/view_model/settings/tor_view_model.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:tor/tor.dart';
|
|
||||||
|
|
||||||
class WalletLoadingService {
|
class WalletLoadingService {
|
||||||
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/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||||
import 'package:cake_wallet/utils/payment_request.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/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.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';
|
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.registerFactory(() => TrocadorProvidersViewModel(getIt.get<SettingsStore>()));
|
||||||
|
|
||||||
getIt.registerSingleton(TorViewModel(getIt.get<SettingsStore>()));
|
getIt.registerSingleton(TorViewModel(getIt.get<SettingsStore>()));
|
||||||
|
getIt.registerSingleton(ProxyWrapper(settingsStore: getIt.get<SettingsStore>()));
|
||||||
|
|
||||||
if (DeviceInfo.instance.isMobile && settingsStore.shouldStartTorOnLaunch) {
|
if (DeviceInfo.instance.isMobile && settingsStore.shouldStartTorOnLaunch) {
|
||||||
getIt.get<TorViewModel>().startTor();
|
getIt.get<TorViewModel>().startTor();
|
||||||
|
|
|
@ -309,6 +309,10 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
ProxyWrapper proxy = await getIt.get<ProxyWrapper>();
|
ProxyWrapper proxy = await getIt.get<ProxyWrapper>();
|
||||||
Uri onionUri = Uri.http(onionApiAuthority, path, queryParams);
|
Uri onionUri = Uri.http(onionApiAuthority, path, queryParams);
|
||||||
Uri clearnetUri = 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:socks5_proxy/socks.dart';
|
||||||
import 'package:tor/tor.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 {
|
class ProxyWrapper {
|
||||||
ProxyWrapper({
|
ProxyWrapper({
|
||||||
required this.settingsStore,
|
required this.settingsStore,
|
||||||
|
@ -14,16 +24,11 @@ class ProxyWrapper {
|
||||||
|
|
||||||
HttpClient? _torClient;
|
HttpClient? _torClient;
|
||||||
|
|
||||||
// Factory method to get the singleton instance of TorSingleton
|
|
||||||
// static ProxyWrapper get instance => _instance;
|
|
||||||
|
|
||||||
static int get port => Tor.instance.port;
|
static int get port => Tor.instance.port;
|
||||||
|
|
||||||
static bool get enabled => Tor.instance.enabled;
|
static bool get enabled => Tor.instance.enabled;
|
||||||
|
|
||||||
bool started = false;
|
bool started = false;
|
||||||
// bool torEnabled = false;
|
|
||||||
// bool torOnly = false;
|
|
||||||
|
|
||||||
// Method to get or create the Tor proxy instance
|
// Method to get or create the Tor proxy instance
|
||||||
Future<HttpClient> getProxyHttpClient({int? portOverride}) async {
|
Future<HttpClient> getProxyHttpClient({int? portOverride}) async {
|
||||||
|
@ -44,113 +49,166 @@ class ProxyWrapper {
|
||||||
return _torClient!;
|
return _torClient!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<HttpClientResponse> get(
|
Future<HttpClientResponse> makeGet({
|
||||||
Uri uri, {
|
required HttpClient client,
|
||||||
Map<String, String>? headers,
|
required Uri uri,
|
||||||
int? portOverride,
|
required Map<String, String>? headers,
|
||||||
bool torOnly = false,
|
|
||||||
Uri? clearnetUri,
|
|
||||||
}) async {
|
}) async {
|
||||||
HttpClient? client;
|
final request = await client.getUrl(uri);
|
||||||
late bool torEnabled;
|
if (headers != null) {
|
||||||
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
|
headers.forEach((key, value) {
|
||||||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
|
request.headers.add(key, value);
|
||||||
client = await getProxyHttpClient(portOverride: portOverride);
|
});
|
||||||
torEnabled = true;
|
|
||||||
} else {
|
|
||||||
client = HttpClient();
|
|
||||||
torEnabled = false;
|
|
||||||
}
|
}
|
||||||
|
return await request.close();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<HttpClientResponse> post(
|
Future<HttpClientResponse> makePost({
|
||||||
Uri uri, {
|
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,
|
Map<String, String>? headers,
|
||||||
int? portOverride,
|
int? portOverride,
|
||||||
bool torOnly = false,
|
bool torOnly = false,
|
||||||
Uri? clearnetUri,
|
Uri? clearnetUri,
|
||||||
|
Uri? onionUri,
|
||||||
}) async {
|
}) async {
|
||||||
HttpClient? client;
|
HttpClient? torClient;
|
||||||
late bool torEnabled;
|
late bool torEnabled;
|
||||||
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
|
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly ||
|
||||||
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
|
settingsStore.torConnectionMode == TorConnectionMode.enabled) {
|
||||||
client = await getProxyHttpClient(portOverride: portOverride);
|
torClient = await getProxyHttpClient(portOverride: portOverride);
|
||||||
torEnabled = true;
|
torEnabled = true;
|
||||||
} else {
|
} else {
|
||||||
client = HttpClient();
|
|
||||||
torEnabled = false;
|
torEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
|
if (settingsStore.torConnectionMode == TorConnectionMode.onionOnly) {
|
||||||
if (!uri.path.contains(".onion")) {
|
if (onionUri == null) {
|
||||||
throw Exception("Cannot connect to clearnet");
|
throw Exception("Cannot connect to clearnet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClientResponse? response;
|
// if tor is enabled, try to connect to the onion url first:
|
||||||
|
if (torEnabled) {
|
||||||
try {
|
if (onionUri != null) {
|
||||||
final request = await client.postUrl(uri);
|
try {
|
||||||
if (headers != null) {
|
return makeGet(
|
||||||
headers.forEach((key, value) {
|
client: torClient!,
|
||||||
request.headers.add(key, value);
|
uri: onionUri,
|
||||||
});
|
headers: headers,
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
response = await request.close();
|
|
||||||
} catch (e) {
|
if (clearnetUri != null && settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
|
||||||
if (!torOnly &&
|
try {
|
||||||
torEnabled &&
|
return makeGet(
|
||||||
settingsStore.torConnectionMode != TorConnectionMode.onionOnly) {
|
client: torClient!,
|
||||||
// try again without tor:
|
uri: clearnetUri,
|
||||||
client = HttpClient();
|
headers: headers,
|
||||||
final request = await client.postUrl(clearnetUri ?? uri);
|
);
|
||||||
if (headers != null) {
|
} catch (_) {}
|
||||||
headers.forEach((key, value) {
|
|
||||||
request.headers.add(key, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
response = await request.close();
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/tor_connection.dart';
|
import 'package:cake_wallet/view_model/settings/tor_connection.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:socks5_proxy/socks_client.dart';
|
||||||
import 'package:tor/tor.dart';
|
import 'package:tor/tor.dart';
|
||||||
|
|
||||||
part 'tor_view_model.g.dart';
|
part 'tor_view_model.g.dart';
|
||||||
|
@ -44,13 +45,26 @@ abstract class TorViewModelBase with Store {
|
||||||
Future<void> startTor() async {
|
Future<void> startTor() async {
|
||||||
try {
|
try {
|
||||||
torConnectionStatus = TorConnectionStatus.connecting;
|
torConnectionStatus = TorConnectionStatus.connecting;
|
||||||
|
|
||||||
await Tor.init();
|
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;
|
_settingsStore.shouldStartTorOnLaunch = true;
|
||||||
|
|
||||||
torConnectionStatus = TorConnectionStatus.connected;
|
torConnectionStatus = TorConnectionStatus.connected;
|
||||||
|
|
||||||
|
SocksTCPClient.setProxy(proxies: [
|
||||||
|
ProxySettings(
|
||||||
|
InternetAddress.loopbackIPv4,
|
||||||
|
Tor.instance.port,
|
||||||
|
password: null,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
// connect to node through the proxy:
|
// connect to node through the proxy:
|
||||||
final appStore = getIt.get<AppStore>();
|
final appStore = getIt.get<AppStore>();
|
||||||
if (appStore.wallet != null) {
|
if (appStore.wallet != null) {
|
||||||
|
@ -70,5 +84,6 @@ abstract class TorViewModelBase with Store {
|
||||||
Tor.instance.disable();
|
Tor.instance.disable();
|
||||||
_settingsStore.shouldStartTorOnLaunch = false;
|
_settingsStore.shouldStartTorOnLaunch = false;
|
||||||
torConnectionStatus = TorConnectionStatus.disconnected;
|
torConnectionStatus = TorConnectionStatus.disconnected;
|
||||||
|
SocksTCPClient.setProxy(proxies: null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,11 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/tor.git
|
url: https://github.com/cake-tech/tor.git
|
||||||
ref: main
|
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
|
flutter_svg: ^2.0.9
|
||||||
polyseed: ^0.0.2
|
polyseed: ^0.0.2
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue