fix(app): fail closed on invalid connection mode state
Restore SOCKS5 only from the current proxy value and keep UI state unchanged when persistence fails.
This commit is contained in:
1 parent
9ac236a981
commit
8cd450d5b1
2 files changed
+22
-16
No files matched your search
@@ -18,23 +18,32 @@ abstract final class ConnectionSettings {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final storedMode = prefs.getString(_modeKey);
|
||||
|
||||
// Any unrecognized value (including the pre-V3 'auto') is TUN. 'proxy' is
|
||||
// the only persisted value that selects the SOCKS5 mode.
|
||||
// Only the explicit current proxy value restores SOCKS5. Unknown and
|
||||
// obsolete values, including the former 'auto'/'ass' labels, fail closed
|
||||
// to full-tunnel TUN instead of silently selecting a weaker route.
|
||||
_mode = storedMode == ConnectionMode.proxy.name
|
||||
? ConnectionMode.proxy
|
||||
: ConnectionMode.tun;
|
||||
|
||||
if (storedMode != _mode.name) {
|
||||
await prefs.setString(_modeKey, _mode.name);
|
||||
final migrated = await prefs.setString(_modeKey, _mode.name);
|
||||
if (!migrated) {
|
||||
throw StateError('Could not persist migrated connection mode.');
|
||||
}
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
static Future<void> setMode(ConnectionMode mode) async {
|
||||
static Future<bool> setMode(ConnectionMode mode) async {
|
||||
if (_initialized && _mode == mode) return true;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final saved = await prefs.setString(_modeKey, mode.name);
|
||||
if (!saved) return false;
|
||||
|
||||
_mode = mode;
|
||||
_initialized = true;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_modeKey, mode.name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,14 @@ class _ConnectionModeTileState extends State<ConnectionModeTile> {
|
||||
return;
|
||||
}
|
||||
|
||||
await ConnectionSettings.setMode(next);
|
||||
final saved = await ConnectionSettings.setMode(next);
|
||||
if (!mounted) return;
|
||||
if (!saved) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Could not save connection mode.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_mode = next;
|
||||
@@ -61,10 +67,6 @@ class _ConnectionModeTileState extends State<ConnectionModeTile> {
|
||||
widget.onChanged?.call(next);
|
||||
}
|
||||
|
||||
/// Recovers from an orphaned proxy: tear the runtime down and start a fresh
|
||||
/// session so a readable set of credentials exists again. No rewarded ad —
|
||||
/// the user is repairing a connection they already paid for, not opening a
|
||||
/// new one.
|
||||
Future<void> _reconnect() async {
|
||||
if (_reconnecting) return;
|
||||
final vpn = context.read<VpnConnection>();
|
||||
@@ -168,11 +170,6 @@ class _ConnectionModeTileState extends State<ConnectionModeTile> {
|
||||
builder: (context, vpn, _) {
|
||||
final session = vpn.activeSocksSession;
|
||||
if (session == null) {
|
||||
// The proxy can be running while this session is unknown:
|
||||
// Android killed the app process, the foreground service kept
|
||||
// the listener alive, and its credentials existed only in the
|
||||
// memory that died with it. Saying "Connect" there would be a
|
||||
// lie — the user is already connected.
|
||||
final orphaned = vpn.status == VpnStatus.connected &&
|
||||
vpn.adoptedRunningRuntime;
|
||||
if (orphaned) {
|
||||
|
||||
Reference in new issue
Block a user