Commit Graph

7 Commits

Author SHA1 Message Date
dazzling-no-more 4da0da7a27 perf(apps_script): batch CacheService getAll + edge-DNS hot-path wins (#958) 2026-05-15 16:47:04 +03:00
therealaleph cbb08468bc fix: v1.9.6 — Code.gs/CodeFull.gs hardening, goog.script.init unwrap, README rewrite
Server-side (Apps Script) fixes — users replace their Code.gs with assets/apps_script/Code.gs (or CodeFull.gs for full mode) and Manage deployments → ✏️ → New version → Deploy:
- Removed duplicate doGet in Code.gs (HtmlService one was overriding ContentService one due to JS hoisting → every GET to /exec returned a goog.script.init iframe instead of the placeholder HTML)
- CodeFull.gs doGet switched from HtmlService to ContentService (same reason)
- SKIP_HEADERS now strips X-Forwarded-* / Forwarded / Via family — second line of defense to v1.2.9's client-side stripping (#104), in case a misconfigured upstream proxy adds these
- _doBatch fallback when UrlFetchApp.fetchAll() throws as a whole — per-item fetch on safe methods so one bad URL no longer poisons the entire batch (port from masterking32@3094288)

Client-side (Rust) defense-in-depth:
- parse_relay_json now unwraps goog.script.init("...userHtml...") if any deployment returns the iframe-wrapped form (legacy Code.gs, or a redirect that GETs doGet). New extract_apps_script_user_html + decode_js_string_escapes helpers. Tested against a real deployment's doGet response.

Docs:
- README rewritten as short bilingual landing page (English + Persian RTL) targeting normal users; advanced reference moved to docs/guide.md + docs/guide.fa.md.

Tests: 3 new regression tests. 176 lib + 33 tunnel-node tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:00:32 +03:00
dazzling-no-more 72ed6d893a feat(codefull.gs): edge-cache DNS to skip tunnel-node round-trip 2026-04-29 19:10:19 +04:00
therealaleph cb3732f920 feat: v1.8.0 — DPI evasion, active-probing defense, full-mode usage counters
Five user-visible changes shipping together. Each is independently
useful + bounded; bundled because they're all "small architectural
hardening" that benefits from one release announcement.

1. Random payload padding (#313, #365 §1)

   Every outbound Apps Script JSON request now carries a `_pad` field
   of uniform-random length 0..1024 bytes (base64). Defeats DPI that
   fingerprints on the tight length distribution of mhrv-rs's previous
   per-mode-bound packet sizes. ~25% bandwidth on a typical 2 KB batch,
   negligible against Apps Script's per-call latency floor. Backward-
   compatible — old `Code.gs` deployments ignore the unknown field.
   Applied at all three payload-build sites: single relay, single
   tunnel op, batch tunnel.

2. Active-probing decoy: GAS bad-auth → 200 HTML (#365 §3)

   `Code.gs` and `CodeFull.gs` now return a benign Apps-Script-style
   placeholder HTML page on bad/missing AUTH_KEY instead of the JSON
   `{"e":"unauthorized"}`. To an active scanner the deployment looks
   like one of the millions of forgotten public Apps Script projects
   rather than an obvious API endpoint. New `DIAGNOSTIC_MODE` const
   restores JSON errors during setup; default false (production-strong).

3. Active-probing decoy: tunnel-node bad-auth → 404 nginx (#365 §3)

   `tunnel-node` returns an HTTP 404 with an nginx-style HTML body on
   bad auth instead of `{"e":"unauthorized"}`. Active scanners cataloging
   the host see "static web server, nothing tunnel-shaped here." New
   `MHRV_DIAGNOSTIC=1` env var restores verbose JSON during setup.

4. Fix: Full-mode usage counter stuck at zero (#230, #362)

   `today_calls` / `today_bytes` were only being incremented on the
   apps_script-mode relay path. Full-mode batches go through
   `tunnel_client::fire_batch` which never wired into the counter.
   Now `fire_batch` calls `record_today(response_bytes)` after each
   successful batch — bytes estimated from the `d` (TCP payload) and
   `pkts` (UDP datagrams) sizes in the BatchTunnelResponse. Full-mode
   users now see real usage numbers.

5. Fix: quota reset countdown was UTC, should be PT (#230, #362)

   Apps Script's UrlFetchApp daily quota resets at midnight Pacific
   Time, not UTC. We were displaying the countdown to UTC midnight,
   off by 7-8h depending on DST. New `current_pt_day_key()` and
   `seconds_until_pacific_midnight()` helpers with hand-rolled US DST
   detection (2nd Sunday March → 1st Sunday November = PDT, else PST)
   so we don't pull `chrono-tz` and a ~3 MB IANA tzdb just for one
   helper. UI label "UTC day" → "PT day". Tests pin DST window
   boundaries against March/November of 2024, 2026, 2027 to catch
   regressions in the day-of-week math.

Tested:
- cargo test --lib: 154 passed (was 152, +2 for DST window + day-of-week)
- cargo build --release: clean
- cargo build --release --bin mhrv-rs-ui --features ui: clean (macOS arm64)
- tunnel-node cargo test: 30 passed
- Android: ./gradlew assembleDebug succeeds; APK installs + launches
  on mhrv_test emulator (arm64-v8a), no UnsatisfiedLink, no crash

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 01:39:47 +03:00
dazzling-no-more 40c2b6c509 feat(udp): SOCKS5 UDP ASSOCIATE relay through full tunnel
Adds end-to-end UDP support: SOCKS5 client UDP ASSOCIATE → tunnel-mux
udp_open/udp_data ops → tunnel-node UDP sessions → real UDP to upstream.
QUIC/HTTP3, DNS, and STUN now traverse full mode without falling back to
TCP or leaking outside the tunnel.

Apps Script proxies the new ops opaquely through the existing batch
endpoint; CodeFull.gs only gets a doc-comment update.

Highlights:
- proxy_server.rs: SOCKS5 UDP ASSOCIATE handler with per-session task,
  bounded uplink mpsc channel, adaptive empty-poll backoff (500 ms → 30 s),
  source-IP validation against the control TCP peer, port-locking on
  first valid datagram, and self-removal from the dispatch map on eof.
- tunnel_client.rs: UdpOpen / UdpData / close_session mux variants
  alongside the existing TCP plumbing; pkts decoder helper.
- tunnel-node: UdpSessionInner with bounded VecDeque queue, drop-oldest
  on overflow with queue_drops counter and warn-then-throttled logs,
  last_active refreshed only on real activity (uplink send or upstream
  recv — empty polls do not refresh), independent TCP/UDP drain in
  handle_batch Phase 2, separate active-drain (150 ms) and retry
  (250 ms) windows for UDP, idle long-poll (5 s).
- Tests: SOCKS5 UDP packet parser (IPv4/IPv6/DOMAIN round-trips,
  truncation rejects, fragmented rejects), UDP queue overflow drop +
  counter, regression test that batch with both UDP and TCP-data ops
  still runs the TCP retry pass.

Docs: README + android.{md,fa.md} updated to reflect UDP availability
in full mode; tunnel-node/README documents the new ops.
2026-04-25 16:19:23 +04:00
dazzling-no-more 0a58943433 feat(tunnel): save one RTT per new HTTPS flow via connect_data op 2026-04-25 01:38:30 +04:00
vahidlazio 31ae569aa2 feat: tunnel-node service + CodeFull.gs (#93)
Standalone Rust/axum HTTP server + Apps Script-side CodeFull.gs for users who want to deploy a remote tunnel node. All new files; no changes to the main Rust crate. This is part 1 of 3 of the full-tunnel feature — it adds scaffolding that users can opt into once the Rust-side Mode::Full lands in #94.
2026-04-23 23:34:51 +03:00