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>
Apps Script source
Three deploy-ready Apps Script files live here. They all speak the same {k, m, u, h, b, ct, r} wire protocol with mhrv-rs, so the client just points its script_id at whichever deployment you want — no mode change required.
Variants and origins
-
Code.gs— standard relay. Verbatim mirror of upstream. Apps Script does the outbound fetch itself. This is the default choice for most users.- Upstream: https://github.com/masterking32/MasterHttpRelayVPN/blob/python_testing/apps_script/Code.gs
- Credit: @masterking32. We do not modify this file.
- The mirror lives here so that (a) users on networks where
raw.githubusercontent.comis unreachable can still deploy from agit clone/ ZIP, and (b) we have a snapshot to diff against if upstream changes silently break the informal relay protocol.
-
CodeFull.gs— superset ofCode.gsthat additionally proxies raw-TCP / UDP viatunnel-node(used bymode: "full"). Maintained in this repo — written for this Rust port and not present upstream. Deploy this if you want full-tunnel mode; details in the file's header comment. -
Code.cfw.gs— Apps Script becomes a thin auth+forward layer; the actual outbound fetch happens on a Cloudflare Worker you also deploy (assets/cloudflare/). Derivative work — not unmodified upstream. The pattern of forwarding through a Cloudflare Worker came from denuitt1/mhr-cfw; this file inherits hardening fromCode.gs(decoy-on-bad-auth, fail-closed sentinels) and adds chunked batch forwarding (Promise.allon the Worker side,ceil(N/40)GAS calls per batch) that the upstreammhr-cfwdoes not have. Faster per-call latency, worse YouTube long-form, no fix for Cloudflare anti-bot. Readassets/cloudflare/README.mdbefore choosing this one.
What you must edit before deploying
For every variant: change AUTH_KEY from its placeholder to a strong secret, and use that same string in your mhrv-rs config's auth_key. Code.cfw.gs additionally requires setting WORKER_URL to your deployed Cloudflare Worker URL; CodeFull.gs additionally requires TUNNEL_SERVER_URL and TUNNEL_AUTH_KEY for the tunnel-node leg.