mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-21 06:18:42 +02:00
CW-519 Enable built-in Tor (#1950)
* tor wip * Enable tor on iOS * Prevent app lag when node is exceptionally slow (usually over tor) * fix: logic in daemonBlockchainHeight refresh fix: storing tor state * Pin ledger_flutter_plus dependency to fix builds * bump arti version * wip * add single httpclient * route everything I was able to catch trough the built-in tor node * Enable proxy for http.Client [run tests] * add tor proxy support to cw_evm, cw_tron and cw_polygon [run tests] * remove log pollution, cleanup [skip slack] * fix tests not working in latest main [skip slack] [run tests] * remove cw_wownero import * fix build issues * migrate all remaining calls to use ProxyWrapper add a CI action to enforce using ProxyWrapper instead of http/http.dart to prevent leaks * fix tor background sync (will work on test builds after #2142 is merged and this PR is rebased on top) * wip [skip ci] * relicense to GPLv3 add socks5 license, build fixes * use ProxyWrapper instead of http in robinhood * Revert "relicense to GPLv3" * feat(cw_bitcoin): support socks proxy and CakeTor * fix(tor): migrate OCP and EVM over to ProxyWrapper() * chore: cleanup fix: show tor loading screen when app is starting * fix: tor switch properly dismisses fullscreen loading dialog fix: connectToNode after tor startup on app start * fix(tor): status check for xmr/wow/zano * fix(tor): onramper request fix * fix(api): ServicesResponse is now being cached and doesn't fetch data everytime DashboardViewModel is being rebuilt fix(tor): do not fallback to clearnet when tor failed. fix(tor): do not leak connections during app startup chore: refactor bootstrap() function to be separated into bootstrapOffline and bootstrapOnline fix(cw_bitcoin): migrate payjoin to use ProxyWrapper * [skip ci] remove print * address comments from review * fix: derusting tor implementation Instead of rust-based Arti I've moved back to the OG C++ tor implementation. This fixed all issues we had with Tor. - onion services now work - all requests are going through without random errors - we don't have to navigate a maze of multiple forks of multiple packages - fully working `torrc` config file (probably will be needed for Tari). - logging for Tor client - and so on. feat: network logging tab feat: use built-in proxy on Tails - this should resolve all issues for Tails users (needs testing though) * fix conflicts with main bump https to fix build issue relax store() call * fix(cw_wownero): tor connection fix(tor): connection issues * fix(cw_evm): add missing chainId fix(cw_core): solana rpc fix * feat: mark tor as experimental fix: drop anonpay onion authority fix: drop fiatapi onion authority fix: drop trocador onion authority fix: disable networkimage when tor is enabled fix: handle cakepay errors gracefully * fix re-formatting [skip ci] * changes from review * Delete android/.kotlin/sessions/kotlin-compiler-2468481326039681181.salive * fix missing imports * Update pubspec_base.yaml --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/view_model/dev/network_requests_view_model.dart';
|
||||
import 'package:cw_core/utils/proxy_logger/abstract.dart';
|
||||
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class DevNetworkRequests extends BasePage {
|
||||
final NetworkRequestsViewModel viewModel = NetworkRequestsViewModel();
|
||||
|
||||
DevNetworkRequests() {
|
||||
viewModel.loadLogs();
|
||||
}
|
||||
|
||||
@override
|
||||
String? get title => "[dev] network requests";
|
||||
|
||||
@override
|
||||
Widget? trailing(BuildContext context) {
|
||||
return IconButton(
|
||||
icon: Icon(Icons.refresh),
|
||||
onPressed: () => viewModel.loadLogs(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
if (viewModel.logs.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text("No logs loaded"),
|
||||
SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () => viewModel.loadLogs(),
|
||||
child: Text("Load Logs"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return ListView.builder(
|
||||
itemCount: viewModel.logs.length,
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
final item = viewModel.logs[i];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return DevRequestDetails(item);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: switch (item.network) {
|
||||
RequestNetwork.clearnet => Text("C"),
|
||||
RequestNetwork.tor => Text("T"),
|
||||
},
|
||||
trailing: switch (item.method) {
|
||||
RequestMethod.get => Text("GET"),
|
||||
RequestMethod.post => Text("POST"),
|
||||
RequestMethod.put => Text("PUT"),
|
||||
RequestMethod.delete => Text("DELETE"),
|
||||
RequestMethod.newHttpClient ||
|
||||
RequestMethod.newHttpIOClient ||
|
||||
RequestMethod.newProxySocket => null,
|
||||
},
|
||||
title: Text(item.time.toIso8601String()),
|
||||
subtitle: switch (item.method) {
|
||||
RequestMethod.get ||
|
||||
RequestMethod.post ||
|
||||
RequestMethod.put ||
|
||||
RequestMethod.delete => Text("${item.uri}"),
|
||||
RequestMethod.newHttpClient => Text("newHttpClient"),
|
||||
RequestMethod.newHttpIOClient => Text("newHttpIOClient"),
|
||||
RequestMethod.newProxySocket => Text("newProxySocket"),
|
||||
},
|
||||
tileColor: item.error != null ? Colors.red : null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DevRequestDetails extends BasePage {
|
||||
final MemoryProxyLoggerEntry req;
|
||||
DevRequestDetails(this.req);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: _body(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_sectionTitle("Time"),
|
||||
SelectableText(req.time.toString()),
|
||||
|
||||
_sectionTitle("Method"),
|
||||
SelectableText(req.method.toString()),
|
||||
|
||||
_sectionTitle("URI"),
|
||||
SelectableText(req.uri?.toString() ?? "null"),
|
||||
|
||||
_sectionTitle("Network"),
|
||||
SelectableText(req.network.toString()),
|
||||
|
||||
_sectionTitle("Body (as UTF-8)"),
|
||||
SelectableText(_tryDecodeBody(req.body)),
|
||||
|
||||
_sectionTitle("Response"),
|
||||
SelectableText(req.response?.body ?? "null"),
|
||||
|
||||
_sectionTitle("Error"),
|
||||
SelectableText(req.error ?? "No error"),
|
||||
|
||||
_sectionTitle("Stack Trace"),
|
||||
SelectableText(req.trace.toString()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _sectionTitle(String title) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _tryDecodeBody(Uint8List body) {
|
||||
try {
|
||||
return utf8.decode(body);
|
||||
} catch (_) {
|
||||
return 'Binary data (${body.length} bytes)';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,8 +196,27 @@ class NodeForm extends StatelessWidget {
|
||||
Observer(
|
||||
builder: (_) => Column(
|
||||
children: [
|
||||
if (nodeViewModel.usesEmbeddedProxy) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.usesEmbeddedProxy,
|
||||
gradientBackground: false,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: null,
|
||||
caption: 'Embedded Tor SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/wallet_connect_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
@@ -71,10 +72,28 @@ class ConnectionSyncPage extends BasePage {
|
||||
),
|
||||
],
|
||||
if (FeatureFlag.isInAppTorEnabled)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.tor_connection,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.torPage),
|
||||
),
|
||||
Observer(builder: (context) {
|
||||
return SettingsSwitcherCell(
|
||||
leading: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red.shade100,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
child: Text(
|
||||
'Alpha',
|
||||
style: TextStyle(
|
||||
color: Colors.red.shade700,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: S.current.enable_builtin_tor,
|
||||
value: dashboardViewModel.builtinTor,
|
||||
onValueChange: (_, bool value) => dashboardViewModel.setBuiltinTor(value, context),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -93,6 +93,12 @@ class OtherSettingsPage extends BasePage {
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs),
|
||||
),
|
||||
if (FeatureFlag.hasDevOptions)
|
||||
SettingsCellWithArrow(
|
||||
title: '[dev] network requests logs',
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.devNetworkRequests),
|
||||
),
|
||||
Spacer(),
|
||||
SettingsVersionCell(
|
||||
title: S.of(context).version(_otherSettingsViewModel.currentVersion)),
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/themes/utils/custom_theme_colors.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:tor/tor.dart';
|
||||
|
||||
class TorPage extends BasePage {
|
||||
final AppStore appStore;
|
||||
|
||||
TorPage(this.appStore);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return TorPageBody(appStore);
|
||||
}
|
||||
}
|
||||
|
||||
class TorPageBody extends StatefulWidget {
|
||||
final AppStore appStore;
|
||||
|
||||
const TorPageBody(this.appStore, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TorPageBody> createState() => _TorPageBodyState();
|
||||
}
|
||||
|
||||
class _TorPageBodyState extends State<TorPageBody> {
|
||||
bool torEnabled = false;
|
||||
bool connecting = false;
|
||||
|
||||
// Set the default text for the host input field.
|
||||
final hostController = TextEditingController(text: 'https://icanhazip.com/');
|
||||
|
||||
// https://check.torproject.org is another good option.
|
||||
|
||||
Future<void> startTor() async {
|
||||
setState(() {
|
||||
connecting = true; // Update flag
|
||||
});
|
||||
|
||||
// await Tor.init();
|
||||
//
|
||||
// // Start the proxy
|
||||
// await Tor.instance.start();
|
||||
//
|
||||
// // Toggle started flag.
|
||||
// setState(() {
|
||||
// torEnabled = Tor.instance.enabled; // Update flag
|
||||
// connecting = false;
|
||||
// });
|
||||
//
|
||||
// final node = widget.appStore.settingsStore.getCurrentNode(widget.appStore.wallet!.type);
|
||||
// if (node.socksProxyAddress?.isEmpty ?? true) {
|
||||
// node.socksProxyAddress = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
|
||||
// }
|
||||
// widget.appStore.wallet!.connectToNode(node: node);
|
||||
|
||||
printV('Done awaiting; tor should be running');
|
||||
}
|
||||
|
||||
Future<void> endTor() async {
|
||||
// // Start the proxy
|
||||
// Tor.instance.disable();
|
||||
//
|
||||
// // Toggle started flag.
|
||||
// setState(() {
|
||||
// torEnabled = Tor.instance.enabled; // Update flag
|
||||
// });
|
||||
//
|
||||
// printV('Done awaiting; tor should be stopped');
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
//
|
||||
// torEnabled = Tor.instance.enabled;
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Clean up the controller when the widget is disposed.
|
||||
hostController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: connecting
|
||||
? ConnectingScreen()
|
||||
: torEnabled
|
||||
? DisconnectScreen(disconnect: endTor)
|
||||
: ConnectScreen(connect: startTor),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConnectScreen extends StatelessWidget {
|
||||
final Function() connect;
|
||||
|
||||
const ConnectScreen({super.key, required this.connect});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.lock,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 48),
|
||||
Text(
|
||||
'Connect to Tor',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Your connection to the Tor network ensures privacy and security.',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 48),
|
||||
ElevatedButton(
|
||||
onPressed: connect,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Connect',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DisconnectScreen extends StatelessWidget {
|
||||
final Function() disconnect;
|
||||
|
||||
const DisconnectScreen({super.key, required this.disconnect});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: CustomThemeColors.syncGreen,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Connected to Tor',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'You are currently connected to the Tor network.',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
ElevatedButton(
|
||||
onPressed: disconnect,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Disconnect',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConnectingScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: CustomThemeColors.syncYellow,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.hourglass_bottom,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Connecting...',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/view_model/start_tor_view_model.dart';
|
||||
|
||||
class StartTorPage extends BasePage {
|
||||
StartTorPage(this.startTorViewModel);
|
||||
|
||||
final StartTorViewModel startTorViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.tor_connection;
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
startTorViewModel.startTor(context);
|
||||
return Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(width: double.maxFinite),
|
||||
if (startTorViewModel.isLoading) ...[
|
||||
CircularProgressIndicator(),
|
||||
SizedBox(height: 20),
|
||||
_buildWaitingText(context),
|
||||
],
|
||||
if (startTorViewModel.showOptions) ...[
|
||||
_buildOptionsButtons(context),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWaitingText(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
S.current.establishing_tor_connection,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (startTorViewModel.showOptions) _buildOptionsButtons(context),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOptionsButtons(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
S.current.tor_connection_timeout,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
PrimaryButton(
|
||||
onPressed: () => startTorViewModel.disableTor(context),
|
||||
text: S.current.disable_tor,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
PrimaryButton(
|
||||
onPressed: () => startTorViewModel.ignoreAndLaunchApp(context),
|
||||
text: S.current.ignor,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:eth_sig_util/eth_sig_util.dart';
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:reown_walletkit/reown_walletkit.dart';
|
||||
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
|
||||
@@ -41,7 +41,7 @@ class EvmChainServiceImpl {
|
||||
}) : ethClient = web3Client ??
|
||||
Web3Client(
|
||||
appStore.settingsStore.getCurrentNode(appStore.wallet!.type).uri.toString(),
|
||||
http.Client(),
|
||||
ProxyWrapper().getHttpIOClient(),
|
||||
) {
|
||||
for (final event in EventsConstants.allEvents) {
|
||||
walletKit.registerEventEmitter(
|
||||
@@ -563,14 +563,15 @@ class EvmChainServiceImpl {
|
||||
},
|
||||
);
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: uri,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"X-API-Key": secrets.moralisApiKey,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
|
||||
|
||||
final symbol = (decodedResponse['symbol'] ?? '') as String;
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_servic
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reown_walletkit/reown_walletkit.dart';
|
||||
|
||||
@@ -153,7 +154,10 @@ class WCCDetailsWidget extends BasePage {
|
||||
child: CircleAvatar(
|
||||
backgroundImage: (pairing.peerMetadata!.icons.isNotEmpty
|
||||
? NetworkImage(pairing.peerMetadata!.icons[0])
|
||||
: const AssetImage('assets/images/app_logo.png')) as ImageProvider<Object>,
|
||||
: AssetImage(
|
||||
CakeTor.instance.enabled
|
||||
? 'assets/images/tor_logo.svg'
|
||||
: 'assets/images/app_logo.png')) as ImageProvider<Object>,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
|
||||
@@ -126,9 +126,9 @@ class _WalletKeysPageBodyState extends State<WalletKeysPageBody>
|
||||
dividerColor: Colors.transparent,
|
||||
padding: EdgeInsets.zero,
|
||||
tabs: [
|
||||
Tab(text: S.of(context).widgets_seed),
|
||||
if (showKeyTab) Tab(text: S.of(context).keys),
|
||||
if (showLegacySeedTab) Tab(text: S.of(context).legacy),
|
||||
Tab(text: S.of(context).widgets_seed, key: ValueKey('wallet_keys_page_seed')),
|
||||
if (showKeyTab) Tab(text: S.of(context).keys, key: ValueKey('wallet_keys_page_keys'),),
|
||||
if (showLegacySeedTab) Tab(text: S.of(context).legacy, key: ValueKey('wallet_keys_page_seed_legacy')),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
@@ -265,7 +266,11 @@ class Badge extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget getImage(String imagePath, {double? height, double? width, Color? imageColor}) {
|
||||
final bool isNetworkImage = imagePath.startsWith('http') || imagePath.startsWith('https');
|
||||
bool isNetworkImage = imagePath.startsWith('http') || imagePath.startsWith('https');
|
||||
if (CakeTor.instance.enabled && isNetworkImage) {
|
||||
imagePath = "assets/images/tor_logo.svg";
|
||||
isNetworkImage = false;
|
||||
}
|
||||
final bool isSvg = imagePath.endsWith('.svg');
|
||||
final double imageHeight = height ?? 35;
|
||||
final double imageWidth = width ?? 35;
|
||||
|
||||
@@ -16,7 +16,7 @@ class StandardCheckbox extends StatelessWidget {
|
||||
final Color? borderColor;
|
||||
final Color? iconColor;
|
||||
final Color? captionColor;
|
||||
final Function(bool) onChanged;
|
||||
final Function(bool)? onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -40,7 +40,7 @@ class StandardCheckbox extends StatelessWidget {
|
||||
BoxDecoration(border: boxBorder, borderRadius: BorderRadius.all(Radius.circular(8.0)));
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => onChanged(!value),
|
||||
onTap: onChanged == null ? null : () => onChanged!(!value),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
||||
Reference in New Issue
Block a user