Skip to content

LxBox v1.3.0

Choose a tag to compare

@github-actions github-actions released this 19 Apr 00:21
· 3761 commits to main since this release

L×Box v1.3.0

Android VPN client powered by sing-box.

Большой релиз: parser v2 переписан с нуля, автообновление подписок, AntiDPI mixed-case SNI, haptic feedback.

✨ Highlights

  • Parser v2 — полностью переписан под sealed NodeSpec, 3-слойный pipeline, 9 протоколов включая новый TUIC v5.
  • Автообновление подписок — 4 триггера (app start, VPN connected +2мин, каждый час, VPN stopped) с жёсткими гейтами против спама.
  • Mixed-case SNI — новый AntiDPI трюк для обхода наивного exact-match DPI.
  • Haptic feedback — вибро-отклик на VPN события (default on).
  • Restart warning теперь sticky — не пропадает при отмене Stop-диалога.

🔧 Parser v2 (spec 026, 5 фаз)

Полная переработка внутреннего pipeline:

  • Типизированная sealed-иерархия NodeSpec — 9 протоколов: VLESS, VMess, Trojan, Shadowsocks, Hysteria2, TUIC v5 (новый), SSH, SOCKS, WireGuard.
  • Полиморфный emit(vars) — WireGuard эмитится в Endpoint, остальные в Outbound, без runtime-проверок типа. Компилятор гарантирует exhaustive switch.
  • Round-trip invariant — parseUri(spec.toUri()) ≈ spec протестирован для каждого варианта.
  • XHTTP fallback через sealed TransportSpec — компилятор не даёт забыть fallback.
  • ServerList (sealed) — SubscriptionServers (fetch по URL) vs UserServers (paste/file/qr/manual). Одноразовая миграция proxy_sources → server_lists при первом чтении.
  • Функциональный pipeline — parseFromSource(source) → buildConfig(lists, settings) → BuildResult(config, validation, warnings).
  • ValidationResult с типизированными ValidationIssue: dangling outbound refs, empty urltest, invalid selector default.
  • Удалено ~2700 LOC v1 — node_parser, config_builder, source_loader, subscription_decoder/fetcher, xray_json_parser, parsed_node, proxy_source.
  • 116 тестов покрывают модели, парсер, round-trip, builder, validator, migration, subscription pipeline, e2e.

🔄 Subscription auto-update (spec 027)

  • 4 триггера автообновления: app start · через 2 мин после VPN connected · раз в час · сразу по VPN disconnected. Manual refresh (⟳) — пятый, force.
  • Жёсткие gates против спама: minRetryInterval=15min (persisted через lastUpdateAttempt), maxFailsPerSession=5 (in-memory, размораживается на рестарт app), perSubscriptionDelay=10s ± 2s между подписками, _running/_inFlight dedup-флаги, inProgress guard от двойных кликов.
  • Crash-safe init sweep — зависший inProgress на диске (kill -9) сбрасывается в failed, fetch возможен после 15-min cooldown.
  • UI в строках подписок — 124 nodes · 🔄 24h · 🕐 3h ago · (2 fails) с interval/ago/failcount.
  • Subscription block в detail screen — URL (tap=copy), Update interval picker (1/3/6/12/24/48/72/168h), Status row, Refresh now кнопка.
  • Rebuild config НЕ триггерит HTTP — только локальная сборка из уже-загруженных nodes.

🛡️ AntiDPI: Mixed-case SNI (spec 028)

Новый toggle в Settings → DPI Bypass. Рандомизирует регистр букв в server_name (WwW.gOoGle.CoM). По RFC 6066 SNI case-insensitive — сервер обязан принять любой регистр; трюк ломает наивный exact-match DPI у региональных провайдеров.

  • First-hop only, per-outbound независимая рандомизация, punycode-метки (xn--…) не трогаем.
  • Default off. Honest help-text: Bypasses simple exact-match DPI; ineffective against GFW-class filtering.

📳 Haptic feedback (spec 029)

Toggle в App Settings → Feedback, default on. Респектит системную настройку Android Touch feedback.

Событие Интенсивность
Tap Start/Stop Лёгкий tick
VPN connected Средний impact
User disconnect Лёгкий impact
Revoked / heartbeat fail (первый только) Тяжёлый impact
Manual subscription fetch success/fail Лёгкий / средний

Auto-триггеры (periodic update, ping, scroll) — не вибрируют. Throttle 100мс защищает от спама.

🔔 Restart warning — sticky flag

Розовая плашка «Config changed — restart VPN to apply» под Stop теперь показывается надёжно после любого сценария (Routing Apply, settings change, Debug import, manual rebuild) и не пропадает при отмене Stop-диалога.

Реализовано через derived getter _needsRestart поверх sticky-флага state.configStaleSinceStart в HomeState — сбрасывается только на реальном tunnel up↔down.

📝 Прочее

  • Subscription title fallback — если нет profile-title header, имя берётся из Content-Disposition: filename=... (RFC 5987 support, стрип .txt/.yaml/.json/.conf).
  • User-Agent для HTTP к подпискам → LxBox Android subscription client (был SubscriptionParserClient).
  • DNS rules — inline domain_suffix: [ru, xn--p1ai, su] для Yandex DoH, без промежуточного ruleset reference.
  • Local build marker — scripts/build-local-apk.sh собирает APK с git describe; About screen показывает розовую плашку «🧪 LOCAL BUILD · N commits since vX.Y.Z». CI builds чистые.

📦 Install

Скачай APK ниже, установи на Android (8.0+). При первом запуске разреши VPN-permission.

128/128 тестов · debug + release APK собираются чисто (71.3 MB).