Commit Graph

307 Commits

Author SHA1 Message Date
therealaleph 8273325e4c docs(maintainer): add maintainer knowledge base for contributors and automated agents 2026-04-29 04:53:52 +03:00
therealaleph 61196ea6e6 Revert "docs(maintainer): add skill knowledge base for cloud-scheduled DOPR agents"
This reverts commit 9f821cc7580c8fe012346c451c86891b8b185485.
2026-04-29 04:45:25 +03:00
therealaleph 69d9317d35 docs(maintainer): add skill knowledge base for cloud-scheduled DOPR agents
Mirror of ~/.claude/skills/mhrv-rs-maintainer/ — SKILL.md plus eight reference
files plus assets. Cloud-scheduled agents clone the repo fresh on each fire
and have no access to the maintainer's local home directory; embedding the
skill in docs/maintainer/ lets them read the same canonical context as the
local maintainer and produce replies indistinguishable from a local DOPR
session.

The local copy at ~/.claude/skills/mhrv-rs-maintainer/ remains the source of
truth; this directory mirrors it.
2026-04-29 04:44:29 +03:00
github-actions[bot] 4e47d244bf chore(releases): refresh prebuilt binaries for v1.8.4
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-28 22:54:57 +00:00
therealaleph 434ad19b9d chore: v1.8.4 — adaptive batch coalescing + tunnel-node long-poll fixes
Two PRs from @yyoyoian-pixel field-tested in Iran:

- #448: adaptive batch coalescing replaces fixed 8ms window. P75 RTT
  6.2s → 3.0s in Iran network testing. Configurable via
  coalesce_step_ms / coalesce_max_ms.

- #446: tunnel-node long-poll 5s → 15s for Telegram/Google Push
  persistent connection stability. Adaptive 40ms-step / 500ms-max
  straggler settle replaces fixed 30ms.

Includes desktop UI build fix: round-trip the new coalesce_* fields
through to_config(). Desktop UI sliders queued for v1.8.x batch.
v1.8.4
2026-04-29 01:37:14 +03:00
Shin (Former Aleph) 7c89772e6e feat(client): adaptive batch coalescing with configurable UI (#448)
Adaptive batch coalescing from @yyoyoian-pixel based on field testing in Iran.

Replace fixed 8ms batch coalesce with adaptive 40ms-step / 1000ms-max scheme. Apps Script adds ~1.5s overhead per HTTP call — packing more ops into each batch means fewer total calls. Field testing showed P75 RTT 6.2s → 3.0s, fast (<3s) batches 61% → 74-85%.

Both values configurable via config.json (coalesce_step_ms, coalesce_max_ms) and Android UI Advanced sliders (10-500ms / 100-2000ms).

Note: desktop UI's to_config() needs follow-up to round-trip the new fields. Filing immediately as a separate commit so v1.8.4 can ship both PRs together.
2026-04-29 01:34:13 +03:00
Shin (Former Aleph) 87ec804eba fix(tunnel-node): raise long-poll to 15s, adaptive straggler settle (#446)
Tunnel-node stability fix from @yyoyoian-pixel based on field testing in Iran.

- LONGPOLL_DEADLINE 5s → 15s: persistent connections (Telegram XMPP :5222, Google Push :5228) stay alive instead of forcing re-handshakes every 5s
- Replace fixed 30ms straggler settle with adaptive 40ms-step / 500ms-max — packs more session responses into each batch, breaks early when all ready

Local verification: tunnel-node 30/30 tests pass, main crate 160/160 tests pass, both build clean.
2026-04-29 01:32:26 +03:00
yyoyoian-pixel 0ca6f77dec feat(client): adaptive batch coalescing, configurable via Android UI
Replace the fixed 8ms batch coalesce window with an adaptive scheme:
after each new op arrives, wait another 40ms (step) for more ops.
The timer resets on every arrival, up to 1000ms (max) from the first
op. Both values are configurable via config JSON (coalesce_step_ms,
coalesce_max_ms) and two new sliders in the Android Advanced section.

Why this helps: Apps Script adds ~1.5s overhead per HTTP call. The
previous 8ms window barely caught any concurrent ops — most batches
carried just 1 op. With 40ms/1000ms, batches average 2-3 ops,
reducing total Apps Script calls for the same workload.

Tested on device in Iran:
  Before: P75=6.2s, 61% fast (<3s), ~1 op/batch
  After:  P75=3.0s, 74-85% fast, ~2-3 ops/batch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 22:02:17 +02:00
yyoyoian-pixel ca76fe91d0 fix(tunnel-node): raise long-poll to 15s, adaptive straggler settle up to 500ms
Apps like Telegram maintain persistent XMPP connections (:5222) and
Google Push uses :5228 — both rely on long-lived sessions with
periodic heartbeats. At the previous 5s long-poll deadline, the
tunnel-node returned empty responses frequently enough that Telegram
interpreted it as connection instability and rotated sessions. Each
reconnect costs a full TLS handshake (~4s through Apps Script),
causing visible video/voice interruptions and buffering.

Raising the long-poll deadline to 15s keeps these persistent
connections alive: the tunnel-node holds the response open until
server data actually arrives (push notification, chat message, media
chunk) rather than returning empty every 5s. Tested on censored
networks in Iran where users reported smoother Telegram video
playback and fewer session resets.

The straggler settle is now adaptive (40ms steps, 500ms max): after
the first session in a batch gets data, keep checking every 40ms
whether neighboring sessions also have data. Break early when all
sessions are ready — no fixed 500ms wait when data is already there.
On high-latency relays where each Apps Script call costs ~1.5s
overhead, packing more session responses into one batch saves quota
and reduces total round-trips.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 21:44:14 +02:00
github-actions[bot] 36e58be555 chore(releases): refresh prebuilt binaries for v1.8.3
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-28 19:03:40 +00:00
therealaleph 7e8e467d3d chore: v1.8.3 — sheet cache + DoH bypass + H1 keepalive + 431 + clearer errors
Three substantive PRs from contributors landed for this release:

- #443 by @euvel: optional spreadsheet-backed response cache in Code.gs.
  Implements all 5 review suggestions from the design discussion (#400):
  TTL-aware caching, 35 KB body-size gate, header rewriting on hit,
  circular buffer for O(1) writes, Vary-aware compound keys.

- #439 by @dazzling-no-more: bypass Apps Script tunnel for known DoH
  endpoints on TCP/443. Cloudflare/Google/Quad9/AdGuard/NextDNS/OpenDNS/
  CleanBrowsing/dns.sb/dns0.eu/AliDNS/doh.pub/Mullvad. Saves the ~2s
  UrlFetchApp roundtrip per name without losing privacy (DoH is
  already encrypted). Default on; users can opt out via tunnel_doh: true
  or extend the list via bypass_doh_hosts.

- #438 by @dazzling-no-more: H1 container keepalive + 431 oversized-
  headers + clearer port-collision message. Cherry-picks from upstream
  Python (Apr 23-26 window). Keepalive prevents Apps Script V8 cold
  starts (visible as YouTube stalls after pause); 431 replaces silent
  socket drops on >64 KB headers (which caused browser retry loops).
v1.8.3
2026-04-28 21:44:10 +03:00
Shin (Former Aleph) 84ea21c0bd feat(code.gs): optional spreadsheet-backed response cache with TTL (#443)
Adds optional Sheets-backed response cache to Code.gs. By @euvel.

All five review suggestions from #400 addressed:
- TTL-aware caching (Cache-Control max-age, no-cache, no-store, private)
- 35 KB body-size gate (under Sheets cell limit)
- Header rewriting on cache hit (Date, Age, Cache-Control, X-Cache, X-Cached-At)
- Circular buffer for O(1) writes (no appendRow/deleteRows reindexing)
- Vary-aware compound cache keys (Accept-Encoding, Accept-Language)

Opt-in via single constant. Zero overhead when disabled. No breaking changes.
2026-04-28 21:40:58 +03:00
Shin (Former Aleph) 554e51f3b6 feat: bypass Apps Script tunnel for DoH endpoints on TCP/443 (#439)
Routes browser DoH lookups (Cloudflare, Google, Quad9, AdGuard, NextDNS, OpenDNS, dns.sb, dns0.eu, AliDNS, doh.pub, Mullvad) around the Apps Script tunnel via plain TCP. By @dazzling-no-more.

DNS-over-HTTPS is already encrypted; tunneling it adds 2s UrlFetchApp roundtrip per name without privacy benefit. New `bypass_doh_hosts` config (default true) lets users opt out. Gated to TCP/443 — private DoH on :8443 should use `passthrough_hosts`.

Local verification: cargo build clean, cargo test --lib 160/160 passing (+6 new matches_doh_host tests).
2026-04-28 21:40:05 +03:00
Shin (Former Aleph) 92951e7e6f feat: H1 container keepalive + 431 oversized-headers (#438)
Cherry-picks of stability/hardening fixes from upstream Python (masterking32/MasterHttpRelayVPN), Apr 23-26 window. By @dazzling-no-more.

- 240s H1 container keepalive prevents Apps Script V8 cold-start stalls
- 64 KB header-block cap returns explicit HTTP/1.1 431 instead of socket drop  
- Clearer port-collision error message

Local verification: cargo build clean, cargo test --lib 154/154 passing.
2026-04-28 21:39:07 +03:00
Euvel 90433998cf revert(Code.gs): revert back HTML output i accidentally removed 2026-04-28 21:17:40 +03:30
dazzling-no-more a7115cb5bd feat: bypass Apps Script tunnel for DoH endpoints on TCP/443 2026-04-28 21:24:18 +04:00
Euvel 08b22bb961 feat(code.gs): optional spreadsheet-backed response cache with TTL 2026-04-28 20:17:58 +03:30
dazzling-no-more 3ce3d81c11 feat: H1 container keepalive + 431 oversized-headers 2026-04-28 20:31:35 +04:00
github-actions[bot] 4c7c90a069 chore(releases): refresh prebuilt binaries for v1.8.2
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-28 12:26:10 +00:00
therealaleph d8170286fa feat: v1.8.2 — UI tracing reads config.log_level + softer decoy detection
- src/bin/ui.rs: install_ui_tracing now takes config_level. Filter
  precedence is RUST_LOG > config.log_level > info,hyper=warn. The
  filter is wrapped in a reload::Layer; Save reinstalls it via
  apply_log_level so users don't need to restart for a level change.
  Fixes #401 (w0l4i) — config.log_level was previously dead on the
  UI binary even though the CLI honored it via init_logging.

- src/tunnel_client.rs: v1.8.1 asserted "AUTH_KEY mismatch" on the
  Apps Script placeholder body, but #404 (w0l4i) showed mixed
  success/failure on the same script_id, which rules that out. The
  body is also returned for Apps Script execution timeout, quota
  tear, internal hiccup, and ISP-side truncation. Error message now
  enumerates all four candidates and points to DIAGNOSTIC_MODE for
  disambiguation.
v1.8.2
2026-04-28 15:07:13 +03:00
github-actions[bot] fd865dfe9f chore(releases): refresh prebuilt binaries for v1.8.1
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-28 10:43:27 +00:00
therealaleph ce3030f6b3 feat: v1.8.1 — decoy detection + script_id in error logs + disable_padding flag
Three small, ship-able-now changes from the past day's issue triage:

1. Client-side detection of the v1.8.0 bad-auth decoy HTML
   (#404 w0l4i, #310 sina-b4hrm)

   When mhrv-rs gets back the decoy HTML body that v1.8.0's Code.gs/
   CodeFull.gs/tunnel-node return on bad AUTH_KEY, the client now
   string-matches the body's distinctive "The script completed but
   did not return anything" sentinel and emits an explicit ERROR
   line naming AUTH_KEY mismatch as the likely cause + walking the
   user through "redeploy as new version" + the DIAGNOSTIC_MODE
   escape hatch — instead of the previous cryptic "WARN batch
   failed: bad response: no json in batch response: <!DOCTYPE...".

   Saves users hours of debugging. Reported pattern hits everyone
   who edits Code.gs's AUTH_KEY without redeploying as a new version
   (Apps Script doesn't auto-pick-up that change).

2. script_id in every batch-failure log (#404 w0l4i)

   Previously WARN batch-failed lines didn't say which deployment
   failed. In multi-deployment setups (5–10 deployments where
   some have stale AUTH_KEY), users couldn't identify the culprit
   without the per-deployment curl probe loop.

   All four failure paths in tunnel_client::fire_batch — timeout,
   bad response, decoy detection, missing-response-in-batch — now
   include the script_id short prefix: `batch failed (script
   AKfycbz4): ...`. Combined with #1 above, this is the first
   reliable diagnostic for the "1 of 8 deployments has bad
   AUTH_KEY" pattern.

3. New disable_padding config flag (#391 EBRAHIM-AM)

   Default false (padding active = stronger DPI defense). For
   users on heavily-throttled ISPs where v1.8.0's ~25% bandwidth
   overhead from random padding compounds with the throttle and
   pushes borderline-working batches into timeouts, setting
   `"disable_padding": true` in config.json recovers headroom at
   the cost of losing length-distribution DPI defense.

   Don't flip on speculatively — only enable if you've measured
   actual throughput improvement on your specific ISP path. For
   users where Apps Script outbound flows freely, padding is free
   defense.

Tested:
- cargo build --release --bin mhrv-rs: clean
- cargo build --release --bin mhrv-rs-ui --features ui: clean
- cargo test --release --lib: 154 passed
- UI FormState round-trips disable_padding through save/load

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.8.1
2026-04-28 13:24:54 +03:00
therealaleph 0d54c5c6fb ci(telegram): use public mhrv_rs link in main-channel post + add invite
Two related changes to the main-channel cross-post (one message per
release that points at the files channel):

1. Post-link now uses the public-username form `t.me/mhrv_rs/<msg_id>`
   instead of the private `t.me/c/<chat_id>/<msg_id>`. The latter only
   resolves for channel members; the former works for everyone, so
   recipients seeing the main-channel announcement can click through
   to a specific release post even if they're not yet subscribed.

   Wired via the existing `FILES_CHANNEL_USERNAME` workflow env var,
   now defaulting to `mhrv_rs` (the channel's public username) if the
   `vars.FILES_CHANNEL_USERNAME` repo variable is unset. Override per
   repo if the channel is renamed.

2. Channel-join links rendered in the body of the main-channel post,
   below the post-link:

       لینک کانال:
       https://t.me/mhrv_rs
       و یا: https://t.me/+R1OyoHX2boA1ZDgx

   Two forms cover the cases where one or the other is filtered:
   - `t.me/mhrv_rs` — public username form, prettier, surfaces in
     Telegram search
   - `t.me/+<hash>` — invite link, the only join path that works for
     private/restricted channels and for users whose client doesn't
     resolve public usernames cleanly

   Wired via new `FILES_CHANNEL_INVITE` env var, defaulting to the
   current invite hash; override via `vars.FILES_CHANNEL_INVITE` if
   rotated.

Per user request — not running this against v1.8.0 retroactively,
just wiring it up for the next release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 03:30:37 +03:00
therealaleph 0669b9310c ci(telegram): add SHA-256 to file captions + cross-link main channel to files channel
Two changes on top of last commit:

1. SHA-256 ("تایید اصالت") now in every file caption. Each artifact's
   caption gets a `<code>...</code>` line with the file's SHA-256 hex
   so recipients can `sha256sum <file>` after download and verify it
   matches what the channel posted. Defends against modified copies
   if the channel ever gets relayed through a third party.

   For chunked uploads (file > 45 MB), each part shows BOTH:
   - SHA-256 of that specific part (verifies the chunk downloaded
     intact before bothering to reassemble)
   - SHA-256 of the full reassembled file (verifies the final result
     after `cat <name>.part_* > <name>`)

2. Main channel post is now a cross-link, not files.

   Previously the legacy `telegram` job in release.yml posted the
   universal APK + full changelog as one sendDocument + sendMessage
   pair to the main announcement channel.

   New behaviour: telegram-publish-files.yml's last step posts a short
   message to the main channel saying "v1.8.0 released, click here
   for files" with a t.me link pointing at the files channel's
   announcement anchor post. Recipients land on the anchor, scroll
   to find the platform-specific artifact they need.

   Link format: `t.me/c/<chat_id>/<msg>` for private channels (works
   for members), or `t.me/<username>/<msg>` if `FILES_CHANNEL_USERNAME`
   repo variable is set (works for everyone — useful if the files
   channel is later made public).

   Legacy telegram job in release.yml stays in source, dormant,
   gated on `vars.TELEGRAM_NOTIFY_ENABLED == 'true'` (default false).
   Comment updated to note the new workflow is the canonical path.
   If both are turned on at once, the main channel gets two posts
   per release.

Tested manually for syntax + caption rendering — actual SHA-256 values
will appear on the next workflow_dispatch run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 03:22:27 +03:00
therealaleph 7e5e2c7313 ci(telegram): publish each release file individually to channel
New workflow + script that posts every artifact (Android APKs, Windows
ZIP, macOS .app + CLI tarballs, Linux glibc + musl, OpenWRT, Raspbian)
to the Telegram channel as separate sendDocument calls, each with a
Persian caption naming the platform variant and a `#v<NNN>` hashtag
(e.g. `#v180`, `#v1810`, `#v200`) so users can find a specific release
later via the channel's hashtag search.

Files larger than 45 MB (the Bot API's effective ceiling after multipart
+ caption overhead) are split into byte chunks named `<name>.part_aa`,
`.part_ab`, ... and posted with reassembly instructions in the caption.
For the v1.8.0 file set everything is ≤41 MB so the split path is
defensive.

Decoupled from `release.yml` so it can be re-triggered for any past tag
via `workflow_dispatch` without rebuilding artifacts — downloads from
the GitHub Release page directly via `gh release download`. Also
auto-runs on each successful `release.yml` completion via
`workflow_run`.

Hard-codes the channel ID `-1003966234444` (one well-known channel,
auditable in source). Reuses `secrets.TELEGRAM_BOT_TOKEN` which already
has post permissions there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 03:15:26 +03:00
therealaleph 2c4c0a9a05 docs(tunnel-node): add Persian translation of README (#372)
Mirror of the English README with the same setup paths (Cloud Run /
Docker prebuilt / Docker source / direct binary), env-var table, and
protocol section, plus a Persian-language FAQ section answering the
specific questions users keep filing:

- bandwidth overhead (~25-30% from base64 + JSON envelope + v1.8.0
  random padding)
- whether all Android apps get tunneled (yes in Tunnel mode + VpnService;
  no in Proxy mode)
- realistic per-flow throughput (~50-200 KB/s, bound by Apps Script's
  per-roundtrip floor; horizontal-scale via more deployments)
- whether a VPS is required for Full mode (yes; not required for
  apps_script or google_only)
- which VPS to pick (Hetzner CX11 €4/mo for general use; Cloud Run
  free tier specifically for Iran users hit by #313 since destination
  IP stays Google-internal)

Adds an `MHRV_DIAGNOSTIC` env-var row to both the English and Persian
env-var tables — was added in v1.8.0 but never documented.

Closes #372.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 03:09:23 +03:00
github-actions[bot] 2afa563073 chore(releases): refresh prebuilt binaries for v1.8.0
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-27 22:55:09 +00: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>
v1.8.0
2026-04-28 01:39:47 +03:00
github-actions[bot] f7da4f01cc chore(releases): refresh prebuilt binaries for v1.7.11
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-27 21:57:54 +00:00
therealaleph d5e5dbb5d7 chore: bump versions to 1.7.11 + drop i686 + harden release artifact download
v1.7.10 release run shipped no assets due to two CI failures stacked:

1. The i686-pc-windows-msvc job (added in v1.7.7 for Win7 support per
   #318) failed because Rust 1.77.2 — the last stable that produces
   Win7-loadable binaries — can't parse modern transitive crate
   manifests (`time` 0.3.47 in this case). Pinning transitives across
   the dep tree at every MSRV bump in our deps isn't sustainable, so
   the target is removed from the release matrix. Win7 32-bit users
   self-build per #318's instructions.

2. The `release` job hit `actions/download-artifact@v4`'s 5-retries-
   exhausted error on multiple artifacts. Same flake we worked around
   in #288 for `commit-releases`. The `release` and `telegram` jobs
   now use `gh run download` wrapped in a 3-attempt retry loop, mirror-
   ing the working pattern.

v1.7.11 is the first full release after v1.7.9; ships #337 (Apps
Script gzip-decoded range probe) and #344 (Android Paste button) that
were tagged in v1.7.10 but never published as assets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.11
2026-04-28 00:44:23 +03:00
therealaleph 46a21b4f5b chore: bump versions to 1.7.10 (Cargo + Android) + fix Win7 i686 lockfile
Patch release for the changes shipped via #337 (Apps Script range
probe gzip-decoded body handling) and #344 (Android Paste button on
13+) plus a CI fix that restores the Win7 i686 binary missing from
v1.7.9 (Cargo.lock format mismatch with Rust 1.77).

The Cargo.lock version=4 (Rust 1.78+) wasn't readable by the pinned
1.77.2 toolchain on the i686 job. Workflow now regenerates the
lockfile with the pinned toolchain on that job only, leaving every
other target unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.10
2026-04-27 23:28:20 +03:00
yyoyoian-pixel f5bd82b64e fix(android): replace clipboard auto-detect with manual Paste button (#344)
Android 13+ restricts clipboard access for background-to-foreground
transitions — the auto-detect banner never appeared on resume.
Replace with a permanent Paste button that reads clipboard on tap
(user interaction grants clipboard permission).

Also: Export button is now icon-only (share icon) to save space.

Co-authored-by: yyoyoian-pixel <279225925+yyoyoian-pixel@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 23:22:52 +03:00
freeinternet865 915dba76cd Fix Apps Script decoded range probe handling (#337)
Accept a synthetic first range probe when Content-Range proves the whole entity was returned, even if Apps Script decoded the body and left compressed Content-Range metadata intact. The response is then rewritten to HTTP 200 with Content-Range removed and Content-Length based on the decoded body, avoiding an unnecessary fallback full GET.

Keep strict validation for real client Range requests and later chunks. Also recognize localized Apps Script bandwidth quota errors.

Co-authored-by: freeinternet865 <free@internet865.com>
2026-04-27 23:22:44 +03:00
github-actions[bot] 567937f29a chore(releases): refresh prebuilt binaries for v1.7.9
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-27 13:05:56 +00:00
therealaleph 11fbe3ebd8 chore: bump versions to 1.7.9 (Cargo + Android)
Patch release for the Win7 i686 binary fix shipped via #323.
No code changes; CI workflow change only — Cargo, Gradle, and
changelog bumps in lockstep so the release produces a fresh
i686 Windows binary built against Rust 1.77.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.9
2026-04-27 15:52:29 +03:00
Shin (Former Aleph) 501d54edec ci(release): pin i686-pc-windows-msvc to Rust 1.77.2 for Win7 compat (#323)
* ci(release): pin i686-pc-windows-msvc to Rust 1.77.2 for Win7 compat

Fixes #318. Rust 1.78 (May 2024) raised the std MSRV for Windows from
Win7 to Win10 by switching std::time to GetSystemTimePreciseAsFileTime,
a kernel32 export that doesn't exist on Win7 SP1. Building the i686
binary with stable Rust (currently 1.86+) produces an exe that fails
to load on Win7 with "the procedure entry point
GetSystemTimePreciseAsFile could not be located in the dynamic link
library kernel32.dll" — making the whole reason we ship i686 (legacy
Win7 32-bit boxes per #272) moot.

Add a per-matrix `rust_toolchain` knob; only i686-pc-windows-msvc uses
it, pinning to 1.77.2 (last stable that supports Win7). Other targets
remain on @stable and pick up regular Rust updates.

dtolnay/rust-toolchain switches from `@stable` to `@master` because
the per-tag aliases (`@stable`, `@1.77.2`) can't be selected via a
matrix variable — `@master` accepts the toolchain string as input.

Cache key gains a toolchain suffix so the 1.77.2 cache doesn't collide
with the stable cache for the same target, and a future toolchain bump
invalidates only the affected slot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(release): make i686-pc-windows-msvc continue-on-error

Companion to the Rust 1.77.2 pin: if the deps' MSRV ever moves above
1.77, the i686 target will fail to build, but we don't want it to
block the rest of the release. Mirror the mipsel-softfloat approach.
If/when this triggers, options are dropping i686 entirely or moving
to the tier-3 i686-win7-windows-msvc target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 15:51:13 +03:00
github-actions[bot] 8bc82d53b2 chore(releases): refresh prebuilt binaries for v1.7.8
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-27 11:35:03 +00:00
therealaleph fb206d415e chore: bump versions to 1.7.8 (Cargo + Android)
Patch release for the auto-blacklist of timeout-saturated deployments
shipped via #319. No new features; bugfix only — cargo, gradle, and
changelog bumps in lockstep so the release workflow can ship matching
artifacts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.8
2026-04-27 14:24:30 +03:00
dazzling-no-more d6d1006f32 feat(tunnel-client): blacklist deployments after sustained timeouts (#319) 2026-04-27 14:18:42 +03:00
github-actions[bot] 8758a75a27 chore(releases): refresh prebuilt binaries for v1.7.7
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-26 22:32:55 +00:00
therealaleph ae0a7c8fac chore: bump versions to 1.7.7 (Cargo + Android)
The v1.7.7 tag commit (6885800) only updated the changelog; the
version field edits failed earlier due to file-state-changed-mid-edit
race. Fixing forward — Cargo.toml + build.gradle.kts now show 1.7.7
properly.

Workflow will build from main HEAD on workflow_dispatch, so the
v1.7.7 release-page artifacts will have the correct internal version
even though the tag commit itself doesn't include the version bump.
2026-04-27 01:21:20 +03:00
therealaleph 6885800040 v1.7.7: i686-windows + per-deployment longpoll fallback
- #288 (@amiralishoja): adds i686-pc-windows-msvc to the release
  matrix. 32-bit Windows users get mhrv-rs-windows-i686.zip on
  every release.
- #290 (@dazzling-no-more): per-deployment longpoll fallback state
  with TTL-based auto-recovery. Replaces a global AtomicBool that
  one degraded deployment could permanently flip. Now the aggregate
  legacy gate only fires when every configured deployment is marked,
  and self-corrects on TTL expiry — upgraded tunnel-nodes rejoin
  the fast path automatically. 4 new tokio::test virtual-time tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.7
2026-04-27 01:20:15 +03:00
dazzling-no-more faa891b106 fix(tunnel): per-deployment legacy fallback with auto-recovery (#290) 2026-04-27 01:19:09 +03:00
github-actions[bot] c677590a3a chore(releases): refresh prebuilt binaries for v1.7.6
Auto-committed by release workflow so users behind GitHub-Releases-page filtering can download via the in-repo releases/ folder. The GitHub Release page itself still has the canonical versioned artifacts; this folder is the fallback path for users who can only reach the static source tree (Code → Download ZIP).
2026-04-26 21:50:51 +00:00
Amirali Shoja 35d2d91fa3 ci: add i686-pc-windows-msvc to release matrix (#272) (#288) 2026-04-27 00:47:53 +03:00
therealaleph a6db13bda5 ci: download release artifacts from GitHub Release page, not artifacts API
The commit-releases job's `actions/download-artifact@v4` step has
failed twice in a row (v1.7.5 retrigger, v1.7.6) with the same
shape: ~10 artifacts download successfully, then "Unable to
download artifact(s): Artifact download failed after 5 retries" on
the 11th-13th. The 10 that complete print their SHA256 digests
cleanly; the failure is unambiguously inside actions/download-
artifact, not on our side.

Workaround: pull from `gh release download` instead. The `release`
job populated the GitHub Release page a few seconds earlier with
the same artifacts; pulling from there reads from a different
CDN (Release-page blob store) with different retry / rate-limit
characteristics. Empirically more reliable for our 13-artifact
release size.

Filtered to *.tar.gz / *.zip / *.apk so we only fetch the user-
facing artifacts (skipping anything like checksum sidecars that
softprops/action-gh-release@v2 might add later).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 00:39:29 +03:00
therealaleph aba539395d v1.7.6: revert googlevideo.com SNI rewrite (#275, #281)
v1.7.4 added googlevideo.com to SNI_REWRITE_SUFFIXES on the theory
that video chunks should bypass the Apps Script relay. Multiple
users (#275 amirabbas117, #281 mrerf) reported total YouTube
breakage on v1.7.4: SNI-rewriting googlevideo.com:443 to a GFE IP
returned TLS handshake failure / wrong-cert error.

Root cause: googlevideo.com is served by Google's separate "EVA"
edge IPs, not the regular GFE IPs that the user's `google_ip`
typically points at. The SNI-rewrite tunnel TLS handshake against
a GFE IP for googlevideo.com SNI fails because the GFE IP doesn't
hold a googlevideo.com cert.

Pre-v1.7.4 behaviour restored: video chunks fall through to the
Apps Script relay path. Slower but reliable on every GFE IP.

The other v1.7.4 youtube_via_relay carve-out fixes (ytimg.com
correctly stays on SNI rewrite, youtubei.googleapis.com correctly
goes through relay) remain intact — those were a separate
improvement and still correct.

Future: if we want direct googlevideo.com routing, it needs a
separate `eva_edge_ip` config knob — users can populate from their
own EVA scan, defaulting to "use relay" if not configured.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.6
2026-04-27 00:34:40 +03:00
therealaleph 0bc7137e3c fix: add block_quic to UI form (E0063 in 4 of 10 builds)
v1.7.5's block_quic config field broke the UI binary build because
src/bin/ui.rs constructs Config{} explicitly and I forgot to add the
new field there. CLI binary loads from JSON via serde so it didn't
trip — only the 4 UI-building targets failed (linux-amd64-gnu,
windows-amd64, macos-amd64, macos-arm64).

block_quic is round-tripped through the form (config-only for now,
no UI control) so save doesn't drop a user-set true.
2026-04-27 00:18:30 +03:00
therealaleph 44854fad84 v1.7.5: block_quic config (#213) + auto-refresh releases/ folder
- Adds `block_quic = true` config flag for client-side QUIC drop.
  SOCKS5 UDP relay refuses UDP/443 datagrams; browsers fall back to
  TCP/HTTPS through the relay. Opt-in. Thanks @w0l4i
- Workflow now auto-refreshes the in-repo releases/ folder on each
  release tag, so Iranian users behind GitHub-Releases-page filtering
  can download via Code → Download ZIP. Practice was started before
  v1.1.0 then dropped; resumed at user request.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.7.5
2026-04-27 00:00:43 +03:00
therealaleph 109a02db4e ci: refresh in-repo releases/ folder on each release tag
Resume the practice (dropped after v1.1.0) of committing prebuilt
binaries to the repo's releases/ folder. Iranian users behind state
network filtering frequently can't reach the GitHub Releases page
(/releases/tag/...) but CAN reach the static source tree via
Code → Download ZIP — that pulls the in-repo releases/ folder along
with the source. Telegram channel feedback explicitly requested
this be resumed.

The new commit-releases job:
1. Runs after release+build+android succeed.
2. Wipes existing binary artifacts from releases/ (.apk, .tar.gz,
   .zip) but preserves README.md and .gitattributes.
3. Copies all desktop archives (which already have stable
   platform-suffixed names like mhrv-rs-linux-amd64.tar.gz).
4. Copies all per-ABI Android APKs (so users on slow connections
   can grab the ~37 MB arm64-v8a APK instead of the ~110 MB
   universal).
5. sed-updates the "Current version" line and APK filename refs
   in releases/README.md (both English and Persian copies).
6. Commits as github-actions[bot] and pushes to main.

The GitHub Release page itself keeps the canonical versioned
artifacts as before — this in-repo folder is the fallback for
users who can't reach that URL.

Tag protection rules don't apply to refs/heads/main so the push
isn't gated. release-drafter.yml triggers on push-to-main but only
updates the next-release draft, no cycle risk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:59:38 +03:00