Commit Graph
4 Commits
Author SHA1 Message Date
esefxdzandClaude Opus 5 62e968f133 fix(app): stop probing the control plane while disconnected
Android CI / android (push) Canceled after 0s
VpnConnection._init() started a 30 s /health poll from the constructor
with no lifecycle gating, so it ran for the life of the app process -
backgrounded, and whether or not the user ever connected. The app is
excluded from its own tunnel, so those requests left in the clear. A
periodic request that fires while the user is deliberately not connected
is an avoidable fingerprint, and rule 60 already ruled probes out:
reachability is meant to be passive.

All it bought was the status dot before the first connect, and it got
that wrong in both directions - "Offline" on a transient resolver
failure against a server that was fine.

Reachability now comes from a session sync that succeeded. serverHealthy
is isConnected && hasSyncedOnce, so a green dot means a working session
rather than a check made beforehand; while disconnected the bar reads
"Ready" and claims nothing either way.

checkHealth() goes with it. Nothing calls it, and leaving a probe helper
in place invites its reuse.

Pinned in test/session_lifecycle_regression_test.dart so it cannot come
back as a tidy-up. flutter analyze clean, 10/10 tests pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-17 21:17:17 +03:00
esefxdzandClaude Opus 5 571c07bca8 feat(session): every reconnect starts a fresh session
Android CI / android (push) Canceled after 0s
SOCKS5 Reconnect re-attached to the session the device already held. It
was the only path where a session began without an ad and without a
nonce binding it to one, and supporting it cost three parameters -
resume, release, resetSupportClaim - plus a carve-out in rule 4 that let
_fetchActiveSession accept whatever nonce the server happened to return.

It also wasn't the kindness it looked like. _handle_main calls
create_or_replace with a fresh full window, so a new session hands the
user *more* time, not less; re-attaching only preserved the remainder of
a session whose proxy had just died.

Reconnect now disconnects and connects again exactly as the button does,
ad included. All four special cases are deleted and the nonce check is
unconditional.

Costs one rewarded ad to repair an orphaned proxy once ads are enabled.
esef's call, and it buys a single way to start a session.

Also fixes the 3.3.7 regression where Reconnect released the session and
then asked for it back: there is no longer a path that does either.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-17 18:53:42 +03:00
esefxdzandClaude Opus 5 e751a9d6e4 fix(session): don't release the session on a SOCKS5 Reconnect
Android CI / android (push) Canceled after 0s
Regression from e67f0b9, shipped in 3.3.7.

Reconnect repairs an orphaned proxy by tearing the runtime down and
re-attaching to the session the device already holds. It does that
through SessionTimer.disconnect(), which e67f0b9 taught to hand the
session back to the server - so it destroyed the very session the
following connect(resume: true) then asked for. Unawaited, so it raced:
the resume either found the session already gone or removed moments
later, surfacing as "Session not activated".

disconnect() now takes release, and the Reconnect path passes false.
Every other caller still hands the session back.

Narrow in practice: SOCKS5 mode only, only the Settings Reconnect
button, and the main-screen connect was unaffected because it mints a
new session anyway.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-17 17:17:29 +03:00
esefxdzandClaude Opus 5 52e8cd8ca1 test: pin the session-lifecycle fixes against silent regression
Source assertions, in the style of the existing release-verification
test. Every behaviour here was found broken on a device and fixed today;
none can be covered by an ordinary Dart test, because they live in the
vendored Android runtime or need a live tunnel. They all regress
silently, and each one looks like tidying when it does - inlining a
CountDownTimer, dropping a Handler callback, restoring a friendlier
notification string.

Checked that they fail without the fixes, not just that they pass with
them: restoring the "disconnects in 5 minutes" wording and moving
releaseSession() out of disconnect() both turn them red.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-17 16:37:41 +03:00