vpn/docs/architecture.md

4.9 KiB
Raw Permalink Blame History

Архитектура

Scope

Текущий продукт — Android + desktop. iOS исключён. macOS не собирается в первом MVP; если платформа вернётся, на ней разрешён только proxy-only до отдельного native review.

В приложении две верхние вкладки: VPN и Белые списки.

  • VPN использует SignBox как один движок для стратегий Основная (VLESS) и Усиленная (AmneziaWG 3.1).
  • Белые списки использует отдельный FreeTurn runtime. FreeTurn не является VPN-стратегией SignBox.

Boundaries

Flet/Python
  models, profiles, UI, theme, payment banner, settings registry
        |
        | versioned idempotent commands
        v
Flet service extension / MethodChannel
        |
        v
Android native services (separate lifetime from Activity)
  VpnRuntimeService (VpnService + foreground)
  ProxyRuntimeService (foreground + proxy/hotspot)
        |
  +-----+--------------------+
  | SignBox/libbox adapter   | FreeTurn mobile adapter
  | TUN/proxy/stats          | Start/StartTunnel/Stop/Captcha

Python does not start an Android subprocess and does not own VPN lifetime. On desktop, the SignBox adapter may own a configured executable with asyncio process management; FreeTurn desktop is explicitly unsupported.

Android state is authoritative in native SharedPreferences. Reopening the Flet UI must call get_runtime_state; missing Python state never implies that a service is stopped. The native bridge has this contract. sing-box-lx is pinned and runs in-process; the service owns CommandServer, while CommandClient is its local management channel.

Engine abstraction

app/core/interface.py defines the common lifecycle. BackendRegistry and EngineManager select adapters by registry and enforce one active engine. Capabilities are checked before start. Unsupported combinations raise UnsupportedEngineError and are rendered as Недоступно, not as connected.

Internals remain different:

  • SignBox exposes VLESS and AmneziaWG packet/TUN plus sing-box SOCKS/HTTP inbounds. PlatformInterface.openTun is the only creator of the Android TUN; Python and the Activity never own its fd.
  • FreeTurn uses its own mobile binding and event/CAPTCHA lifecycle. Its Start API is not a generic SOCKS5/HTTP listener; standard sharing remains unsupported until a separately implemented listener reports actual bound addresses.
  • VOID is an Android VPN data-path policy and must be enforced before an engine or direct fallback. It must never be implemented as addDisallowedApplication, because Android then sends that app directly.

Modes and sharing

Desktop is proxy-only in the first release. Android supports VPN, proxy-only, and local Both with one sing-box instance. Hotspot proxy-only is implemented. Both + LocalOnlyHotspot remains explicitly unsupported until hotspot discovery and VpnService startup are coordinated around the same core.

Proxy defaults to 127.0.0.1; Wi-Fi sharing uses LocalOnlyHotspot, discovers its actual interface address, and binds listeners only after the hotspot callback. It never assumes 192.168.43.1, does not use 0.0.0.0 as a user default, and does not use system tethering/NAT. SOCKS5 and HTTP CONNECT share one optional credential pair.

Backend and devices

The backend has separate operator and device authentication:

  • operator CRUD uses one configured admin Bearer token;
  • each device gets a UUID4 and a separate random credential, stored server-side only as SHA-256 hash;
  • enrollment is one-time via an admin-created URL; the first request must use vpnapp/vMAJOR.MINOR/DEVICE_UUID and binds that User-Agent;
  • subsequent requests use X-Device-Token over HTTPS and the same bound User-Agent;
  • UUID/User-Agent alone are not secrets and cannot authenticate.

Secrets in SQLite are Fernet-encrypted with VPNAPP_SECRET_KEY. The admin HTML never lists secret fields after creation. A stronger future option is a hardware-backed key and signed requests with replay protection.

Theme and UI

The accent is derived from active top-level/strategy context: neutral gray for FreeTurn, light blue for Basic, red for Enhanced, while ThemeMode.SYSTEM respects the device light/dark mode. Screens register their settings sections in SettingsRegistry, so the settings screen can grow without a universal nullable profile.

Deliberate non-goals

  • iOS, Personal Hotspot automation and iOS per-app routing.
  • DIRECT uses Android package exclusion. VOID remains unavailable until native UID ownership and the fail-closed packet drop path are implemented and device-tested.
  • bundled native cores without pinned source, license, ABI and API evidence.
  • management/debug listeners exposed by SignBox.