Document the client routing, secure SOCKS5, runtime resilience, lifecycle, notification and migration changes so reviewers can compare the 3.3.1 release against 3.3.0 without reconstructing the behavior from implementation commits.
14 KiB
14 KiB
Changelog
All notable changes to the ReVoltVPN Flutter app. Versions follow semver: MAJOR.MINOR.PATCH
[3.3.1] — 2026-08-31
Added
- Explicit TUN and SOCKS5 connection modes. The previous Auto mode is removed so routing behavior is selected deliberately instead of inferred at runtime.
- Per-app routing with All apps, Exclude apps and Selected only policies. Android
enumerates launcher applications without requesting
QUERY_ALL_PACKAGES. - Authenticated per-session Local SOCKS5. Every connection creates a loopback-only
SOCKS ingress with a random high port plus fresh username/password credentials.
Credentials stay in memory and the diagnostic test uses the active session instead
of fixed
10807/10808ports. - Network resilience controls with Standard and Extreme profiles plus Android physical-network monitoring that ignores VPN-created network callback loops.
- Native Android bridges for installed-app discovery, network state and haptic feedback.
- Regression tests for legacy Auto/ASS migrations, secure SOCKS session generation and the patched stock Xray SOCKS authentication schema.
Changed
- Legacy
autopreferences migrate to TUN. Legacyasspreferences migrate to SOCKS5 while preserving selected-app package lists. - Keep the hosted
flutter_vless_android1.1.5 runtime instead of restoring the experimental vendored Android service. Required routing, recovery and authenticated SOCKS behavior is applied by idempotent build-time patchers. - Session countdown reconciliation now uses elapsed wall-clock time, re-syncs immediately on resume and preserves the existing 5 s foreground / 30 s background poll policy.
- Haptic feedback is initialized at startup and routed through a native Android channel; duplicate toggle feedback is removed and the setting remains persistent.
- VPN notification uses a dedicated 24 dp status icon, remains ongoing/no-clear while the foreground service is active and keeps session metadata out of public lock-screen previews.
- Hivemind session parsing is split into typed validation steps and nonce generation uses
Random.secure()without logging nonce values. - Increase Gradle release-build heap to 4 GiB and cap workers at two so Flutter/Jetifier transforms do not fail on the release classpath under constrained CI runners.
- App version is now
3.3.1+27.
Fixed
- Recoverable Xray/tun2socks startup and readiness failures no longer follow the unstable vendored-runtime self-stop path used during development.
- SOCKS5 readiness checks authenticate against the exact active session instead of merely checking whether a fixed local port accepts connections.
- Returning from Android background state reconciles the session timer and server status,
reducing stale countdowns and false
Syncing…presentation after Dart throttling. - Sidebar update checks retain valid navigator/messenger handles after the drawer closes.
- Settings startup uses the persistent haptic manager instead of the removed legacy loader.
Security & privacy
- Local SOCKS5 listens only on
127.0.0.1, requires per-session authentication and does not persist or log generated credentials. - The app picker relies on launcher-app queries rather than broad package visibility.
- Session time/speed notification metadata is marked private for lock-screen previews.
- Existing AdMob bypass/callback behavior is intentionally unchanged by this release.
- Server, nginx and Reality configuration are not modified by this client-side release.
Validation
flutter analyzecompleted without fatal warnings or infos.- All four Flutter regression tests passed.
- Android release Kotlin compilation passed.
- The 3.3.1 release APK built successfully and the packaged VPN runtime verification passed.
[3.3.0] — 2026-08-30
Added
- Session countdown in the VPN notification, updated each second while connected.
Fixed
- Session-expiry desync — the app could show "Online" with no internet after the server ended the session. The countdown no longer freezes when a poll fails.
- Notification Disconnect button disappeared a second after connecting. Re-posting the foreground notification replaces it wholesale, so the action, colour and tap-intent flutter_vless sets are now rebuilt rather than dropped.
- Speed readout divided the byte delta by the nominal poll interval instead of the real time between polls — wrong by up to 6x around every background switch.
- Settings toggles now apply at launch. Rain, lightning and haptics were only read from disk when Settings mounted, so an effect turned off came back — ticker and all — on every relaunch, and haptic feedback did nothing until Settings had been opened at least once.
- Haptic feedback now fires
mediumImpact()instead oflightImpact()(which is imperceptible on many Android devices), wrapped best-effort so a platform vibration failure cannot fail a connect/disconnect, with a preview tap when the toggle is switched on. - First-launch disclosure dialog said data was linked to "your account". It is linked to a randomly generated device ID, and the policy is in the sidebar, not on a website.
- Sidebar "Settings" and "Check for updates" used the drawer's context after
Navigator.pop()— a defunct context. They now capture the root navigator (and messenger) before closing the drawer. (Fix ported from Naveax's review.)
Performance
- Rain overlay ticks only while enabled, repaints through a scoped
Listenableinstead of rebuilding every frame, and precomputes drop colours. - Lightning no longer fires strikes while disabled.
- Connect button pulse pauses when backgrounded; brand image hoisted out of the per-frame rebuild.
- Server poll drops to 30 s while backgrounded (5 s foreground), with an immediate re-sync on resume. The 1 s countdown keeps running.
- Health probe runs only while disconnected, and pauses in the background.
- Speed and support widgets rebuild on value change instead of every second.
- Notification channel is created once per process, not once per second.
Changed
- VLESS engine initializes under the splash screen; the intro waits on
VpnConnection.ready(8 s cap) before showing the main screen. - AdMob SDK init moved off the blocking pre-
runApp()path so startup cannot hang on an unreachable Google endpoint. app_config.example.dartdrops the dead bootstrap fields and documentshivemindApiPublicin their place..gitignorereorganized around type and directory rules; the enumerated filename list is gone (redundant with the type rules) and.claude/is now ignored.
Security
- Update checker pins the release URL to this repo's path on
github.com, not just the host. Anything else falls back to the releases page. - Notification timer updates are gated on a live tunnel, so a late tick cannot leave an ongoing notification with no foreground service behind it.
- Dropped
READ_EXTERNAL_STORAGE, whichflutter_vlesspulls in but the app never uses (least privilege). - Pinned the Gradle 8.14 distribution SHA-256;
validateDistributionUrlenabled (supply-chain integrity).
Build & tooling (ported from Naveax)
- Removed the deprecated
android.enableR8flag. - Added
analysis_options.yaml(flutter_lints,local_packages/**excluded,avoid_print). - Added
.gitattributesto pin LF line endings repo-wide. - Credit: reviewed and ported from Naveax.
Docs
- Privacy policy: disclosed that the server sees the connecting IP, corrected the "stored in memory" claim, and documented consent being changeable from the sidebar.
[3.2.2] — 2026-08-08
Fixed
- Updated Discord invite link.
[3.2.1] — 2026-08-08
Google Play compliance
- Added first-launch data disclosure dialog ("Before you connect") explaining that connection duration and data usage are logged for quota enforcement, and that traffic content is never monitored.
[3.2.0] — 2026-08-08
DPI hardening
- Spoof Chrome-on-Android User-Agent on all API calls instead of
Dart/3.x. - Renamed domain from
getrevolt.apptouserevolt.app.
Branding
- App name changed from "REVOLT VPN" to "Revolt VPN" across manifest, splash, notification, and VLESS URL remark.
Notification
- Removed duplicate
flutter_local_notificationsnotification. Only the Android VPN foreground-service notification remains — non-swipeable. - Patched
flutter_vlessnative code to use custom notification icon (@drawable/notification_icon) with dark background (#0D1117).
Connection reliability
- Merged five separate disconnect paths into a single idempotent
_doDisconnect()gate. Eliminated race between timer ticks and VPN teardown where the countdown could briefly show -1. stopVless()timeout (5 s) now correctly shows an error instead of silently pretending the VPN disconnected while the tunnel was still alive.
AdMob bypass
kDebugModeguard removed — the debug AdMob callback now fires in release builds so release APKs can create sessions without real ads during testing. The real gate isADMOB_BYPASSon the server.
Fixed
- Notification icon: Replaced five density-specific
ic_launcher.pngfiles withnotification_icon.png, then reverted to avoid changing the home-screen icon. The custom icon is now injected through flutter_vless'sinitializeVless()parameters.
[3.1.0] — 2026-08-06
Architecture — domain-free client
- Zero domain strings in APK. RKN has nothing to DNS-block. API calls go
through the Reality tunnel to
10.254.254.1:5000, redirected to Flask by Xray'sapifreedom outbound (redirect: 127.0.0.1:5000). - Bootstrap tunnel. Bundled Reality config in APK → connect → fetch real
per-session VLESS URL from inside the tunnel → reconnect. Bootstrap client
permanently in
xray_config_reality.json, restricted by Xray routing to internal API only. serverDomainremoved fromAppConfig.fetchConfigThroughTunnel()replacesfetchConfigWithPolling().connect()rewritten.
Protocol — TCP to XHTTP
- Transport: TCP → XHTTP (H2 stream-up with Reality). No more XTLS-Vision,
no
flowfield. Path-hidden behind/revolt.
Fixed
- RenderFlex overflow — status bar text wrapped in
FlexiblewithTextOverflow.ellipsisto prevent overflow on narrow screens (≤360dp). - Circular import — removed
import 'package:revoltvpn/main.dart'fromsidebar_drawer.dart.SidebarDrawerconverted toStatefulWidget; version footer loaded viaPackageInfo.fromPlatform(). - Client hot-reload was silently broken —
xray api adino-op. Fixed:adu/rmucommands per Xray HandlerService spec. - Missing XHTTP
pathparam in VLESS URL — now readsxhttp_pathfrom/session/status. providerBundleIdentifierwascom.revoltvpn.app— must matchcom.paladinvpn.appfor VPN service registration.- Reality keypair generated (was placeholder). Throttle
uplinkOnly/downlinkOnlycorrected (seconds, not bytes/sec). Fallback rate limits removed (fingerprint).
Added
- Settings screen — reached from a new sidebar row (between Website and
Check for updates). Slide-from-right navigation via
PageRouteBuilder. Folder:lib/screens/settings/with one file per feature inin_settings/. - Haptic feedback toggle — on/off switch in Settings for
lightImpact()vibration on successful connect/disconnect. Default: off. Uses sync-bool pattern (no await on tap, no SharedPreferences in connect button). - Rain/Lightning effect toggles — two switches in Settings to control the animated background effects. Default: on. Effects detect the toggle within one frame (no Provider/notifier needed).
Changed
- Timer box spinner removed — the "Connecting…"/"Syncing…" spinner under the countdown was redundant with the connect button's spinner. Timer card is now a clean countdown only (gray '00:00:00' when idle).
- Sidebar now has 7 rows (added Settings).
FRONTEND_POLISH_REVIEW.mdfully triaged: 4 items fixed, 11 skipped.
Server
apioutbound + 3 routing rules inxray_config_reality.json(bootstrap isolation + API routing). Permanent bootstrap client. Hivemind unchanged.xhttp_pathin/session/statusresponse.- Full deployment guide:
SERVER_DEPLOYMENT.md.
[2.0.7] — 2026-07-31
Fixed
- Notification bug —
SessionTimer.stop()now cancels the persistent Android notification on user-initiated disconnect. - Concurrent sync guard —
_syncInProgressflag prevents duplicate HTTP requests from overlapping in_syncWithHivemind(). - Debug bypass gate —
AppConfig.enableAdBypassreplaceskDebugModefor fake AdMob callback. Tree-shaken in release builds.
Changed
- Responsive layout — main screen uses
LayoutBuilderwith proportional fractions. Scales to any screen size. - Dynamic version — sidebar footer reads from
PackageInfoinstead of hardcoded string. - Swarm/log blocked — nginx returns 404 for
/api/swarmand/api/log. Monitoring runs locally viaswarm_watch.py.
Added
- Update checker in sidebar — polls GitHub Releases API.
- Website button in sidebar → opens
https://userevolt.app. - Timer syncing indicator — spinner during handshake.
- Dependency:
package_info_plus.
Server
/session/stopfetches stats BEFORE popping session (race fix).XrayManager._stats_lockfor diagnostic counter thread safety.ManagementLoop._start_lockprevents TOCTOU on daemon startup.
[1.0.6] — 2026-06
- Initial VLESS + Xray Reality tunnel
- 60 min session, 4 GB throttle, support top-up
- Server health dot, speed display, countdown timer
- Persistent Android notification
- Glass-morphism dark UI with yellow accent
- Right-edge sidebar with Ad Consent, Privacy, About, Discord