What changed, and why it matters
This commit changes how a wallet app connects to its backend server. It adds automatic detection of IP addresses, Tor onion addresses, and regular domain names, and adjusts security settings (Tor and SSL) based on what the user types. It also adds a 10-second timeout for Tor connection tests and prevents the 'Continue' button from appearing until a successful test has completed. The changes appear aimed at preventing users from accidentally using insecure combinations, such as SSL over Tor or clearnet HTTP without SSL.
Review the regular expressions for correctness and edge cases (e.g., IPv6, non-standard onion addresses, internationalized domains, ports). Verify that forcing SSL for all domain names is intended and does not break local-network or self-signed deployments. Confirm the 10-second timeout is appropriate and does not leak timing information. Test that the mutual exclusion of Tor and SSL cannot be bypassed via race conditions or state inconsistencies.
Security signals we found
Automatic protocol selection based on address type (IP, onion, domain)
Mutual exclusion of Tor and SSL toggles
10-second timeout added to Tor SOCKS HTTP request
Continue button now gated on _hasTested and !_isLoading
Proxy port field disabled when Tor is active
Evidence from the diff
The patch modifies lib/screens/connection_setup.dart. It introduces onAddressChange(), which uses three regular expressions to classify the daemon address as an IPv4 address, a .onion address, or a domain name, and then toggles _useTor and _useSsl accordingly. It refactors _setUseTor into setUseTor and adds setUseSsl, both of which reset _hasTested. It adds a 10-second timeout to the Tor SOCKS HTTP request in _testConnection. It also makes the proxy port field always visible but disabled when Tor is enabled, and only enables the save/continue button when _connectionSuccess && _hasTested && !_isLoading. The Tor and SSL checkboxes are now mutually exclusive.
Changed components
lib/screens/connection_setup.dartConnection setup UITor/SSL toggle logicConnection testing flowInspect captured patch +68 / −25
diff --git a/lib/screens/connection_setup.dart b/lib/screens/connection_setup.dart
index 5fc1206..55ce8db 100644
--- a/lib/screens/connection_setup.dart
+++ b/lib/screens/connection_setup.dart
@@ -50,16 +50,58 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
});
}
- void _setUseTor(bool? newValue) {
+ void onAddressChange(String value) {
+ final ipAddressRegex = RegExp(
+ r'^(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$',
+ );
+ final onionAddressRegex = RegExp(
+ r'^[a-z2-7]{56}|[a-z2-7]{16}.onion(:\d{1,5})?$',
+ );
+ final domainAddressRegex = RegExp(
+ r'^(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}(?::\d{1,5})?$',
+ );
+
+ if (ipAddressRegex.hasMatch(value)) {
+ setUseTor(false);
+ setUseSsl(false);
+ } else if (onionAddressRegex.hasMatch(value)) {
+ setUseSsl(false);
+ setUseTor(true);
+ } else if (domainAddressRegex.hasMatch(value)) {
+ setUseTor(false);
+ setUseSsl(true);
+ }
+
+ setState(() {
+ _hasTested = false;
+ });
+ }
+
+ void onProxyPortChange(String value) {
+ setState(() {
+ _hasTested = false;
+ });
+ }
+
+ void setUseTor(bool? value) {
setState(() {
- _useTor = newValue ?? false;
+ _useTor = value ?? false;
+ _useSsl = false;
+ _hasTested = false;
});
- if (newValue == true) {
+ if (value == true) {
_customProxyPortController.text = '';
}
}
+ void setUseSsl(bool? value) {
+ setState(() {
+ _useSsl = value ?? false;
+ _hasTested = false;
+ });
+ }
+
Future _testConnection() async {
final proto = _useSsl ? 'https' : 'http';
final daemonAddress = _addressController.text;
@@ -87,7 +129,11 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
try {
if (_useTor) {
final proxyInfo = TorService.sharedInstance.getProxyInfo();
- final response = await makeSocksHttpRequest('POST', url, proxyInfo);
+ final response = await makeSocksHttpRequest(
+ 'POST',
+ url,
+ proxyInfo,
+ ).timeout(Duration(seconds: 10));
setState(() {
_connectionSuccess =
@@ -170,6 +216,7 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
children: [
TextFormField(
controller: _addressController,
+ onChanged: onAddressChange,
decoration: InputDecoration(
labelText: i18n.address,
hintText: i18n.connectionSetupAddressHint,
@@ -189,37 +236,33 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
),
keyboardType: TextInputType.url,
),
- if (!_useTor)
- TextFormField(
- controller: _customProxyPortController,
- decoration: InputDecoration(
- labelText: i18n.connectionSetupProxyPortLabel,
- hintText: i18n.connectionSetupProxyPortHint,
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(8.0),
- ),
+ TextFormField(
+ controller: _customProxyPortController,
+ onChanged: onProxyPortChange,
+ enabled: !_useTor,
+ decoration: InputDecoration(
+ labelText: i18n.connectionSetupProxyPortLabel,
+ hintText: i18n.connectionSetupProxyPortHint,
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8.0),
),
- keyboardType: TextInputType.number,
- inputFormatters: <TextInputFormatter>[
- FilteringTextInputFormatter.digitsOnly,
- ],
),
+ keyboardType: TextInputType.number,
+ inputFormatters: <TextInputFormatter>[
+ FilteringTextInputFormatter.digitsOnly,
+ ],
+ ),
CheckboxListTile(
title: Text(i18n.connectionSetupUseTorLabel),
value: _useTor,
- onChanged: _setUseTor,
+ onChanged: !_useSsl ? setUseTor : null,
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
),
-
CheckboxListTile(
title: Text(i18n.connectionSetupUseSslLabel),
value: _useSsl,
- onChanged: (bool? newValue) {
- setState(() {
- _useSsl = newValue ?? false;
- });
- },
+ onChanged: !_useTor ? setUseSsl : null,
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
),
@@ -251,7 +294,7 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
],
),
),
- if (_connectionSuccess)
+ if (_connectionSuccess && _hasTested && !_isLoading)
FilledButton(
onPressed: _saveConnection,
child: Text(i18n.connectionSetupContinueButton),
Why this scored 38/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.