What changed, and why it matters
This commit adds a 'demo mode' to the wallet app. When the app is built with a special environment flag and the user types 'demo' as the server address, the app skips the real network connection test and pretends it succeeded. This is a development/testing convenience, but it could let someone bypass the actual connection check if they can trigger or build the app in demo mode.
Ensure demo mode is only enabled in debug/test builds and never in production releases. Consider gating it behind a build flavor or `kDebugMode` check, and add a prominent UI indicator when demo mode is active so users cannot mistake a demo connection for a real one.
Security signals we found
Conditional bypass of connection-success validation
Compile-time feature flag controlling security-relevant behavior
Hardcoded magic string ('demo') used as a trust signal
Early return before Tor/proxy initialization and HTTP health check
Evidence from the diff
The change introduces a compile-time constant isDemoMode read from the DEMO_MODE environment variable. In ConnectionSetupScreen, before performing the real Tor/proxy connection test to /get_address_info, it checks isDemoMode and whether the user-entered daemonAddress equals the literal string ‘demo’. If both are true, it sets _hasTested = true and _connectionSuccess = true and returns early, bypassing the actual network validation. The patch also moves _isLoading = true into the same setState block as _hasTested = true.
Changed components
lib/screens/connection_setup.dartConnection setup / daemon validation flowInspect captured patch +14 / −4
diff --git a/lib/screens/connection_setup.dart b/lib/screens/connection_setup.dart
index 4c88e74..2cdb98a 100644
--- a/lib/screens/connection_setup.dart
+++ b/lib/screens/connection_setup.dart
@@ -8,6 +8,8 @@ import 'package:skylight_wallet/l10n/app_localizations.dart';
import 'package:skylight_wallet/models/wallet_model.dart';
import 'package:skylight_wallet/services/tor_service.dart';
+const isDemoMode = String.fromEnvironment('DEMO_MODE') == 'true';
+
class ConnectionSetupScreen extends StatefulWidget {
const ConnectionSetupScreen({super.key});
@@ -114,6 +116,17 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
final customProxyPort = _customProxyPortController.text;
String torProxyPort = '';
+ // Handle demo mode
+ if (isDemoMode) {
+ if (daemonAddress == 'demo') {
+ setState(() {
+ _hasTested = true;
+ _connectionSuccess = true;
+ });
+ return;
+ }
+ }
+
if (_useTor) {
await TorService.sharedInstance.start();
await TorService.sharedInstance.waitUntilConnected();
@@ -124,14 +137,11 @@ class _ConnectionSetupScreenState extends State<ConnectionSetupScreen> {
setState(() {
_hasTested = true;
+ _isLoading = true;
});
final url = '$proto://$daemonAddress/get_address_info';
- setState(() {
- _isLoading = true;
- });
-
try {
if (_useTor) {
final proxyInfo = TorService.sharedInstance.getProxyInfo();
Why this scored 27/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.