Two changes addressing user-reported issues today:
1. Exit-node feature ported from upstream masterking32@464a6e1d, with
hardening. Cloudflare-protected sites (chatgpt.com, claude.ai,
grok.com, x.com, openai.com) flag Google datacenter IPs as bots and
return Turnstile / CAPTCHA / 502 challenges. Apps Script's UrlFetchApp
exits from those IPs, so v1.9.3 surfaces these as "Relay error: json:
key must be a string..." with no apps_script-mode workaround.
Now a small TypeScript HTTP endpoint (assets/exit_node/valtown.ts)
deployed on val.town / Deno Deploy sits between Apps Script and the
destination. Chain: client → Apps Script (Google IP) → val.town
(non-Google IP) → destination. Destination sees val.town's IP, no
CF challenge.
Config:
"exit_node": {
"enabled": true,
"relay_url": "https://...web.val.run",
"psk": "<openssl rand -hex 32>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
Hardening over upstream: PSK fail-closed if still placeholder (fresh
deploy can't be open relay), loop guard (refuses fetch of own host),
explicit 503 on misconfigured. Fallback to direct Apps Script on exit
node failure (CF-affected sites fail, others keep working). Setup
docs in English + Persian at assets/exit_node/README*.md. Example
config at config.exit-node.example.json.
2. Removed the legacy `telegram` job from release.yml. With
TELEGRAM_NOTIFY_ENABLED repo var set to true, every release was
producing two duplicate APK posts on the main Telegram channel: the
old bundled-APK-on-main job AND the newer per-file files-channel
posts (telegram-publish-files.yml). Only the per-file flow is wanted.
Legacy job and its helper telegram_release_notify.py are gone.
Recoverable from git log if anyone needs the bundled pattern back.
169 mhrv-rs lib tests + 33 tunnel-node tests + UI build clean.
6.3 KiB
• exit node اختیاری برای دور زدن CF anti-bot روی ChatGPT / Claude / Grok / X (port از upstream masterking32/MasterHttpRelayVPN@464a6e1d, با hardening): سایتهای پشت Cloudflare مانند chatgpt.com، claude.ai، grok.com، x.com، openai.com traffic از Google datacenter IPs (Apps Script's outbound IP space) رو بهعنوان bot flag میکنن + Turnstile / CAPTCHA / 502 challenge برمیگردونن. تا v1.9.3 این "Relay error: json: key must be a string at line 2 column 1" یا 502 generic میداد + هیچ workaround در apps_script mode نبود. حالا یک endpoint TypeScript کوچک (assets/exit_node/valtown.ts) روی val.town / Deno Deploy / fly.io deploy میشه + بین Apps Script + destination قرار میگیره. مسیر traffic: client → SNI rewrite → Apps Script (Google IP) → val.town (non-Google IP) → destination. destination IP val.town رو میبینه، نه Google datacenter — heuristic anti-bot CF نمیسوزه + صفحه واقعی برمیگرده. leg user-side (Iran ISP → Apps Script) بدون تغییر — second hop کاملاً درون outbound Apps Script اجرا میشه، invisible از شبکهی کاربر. config جدید:
"exit_node": {
"enabled": true,
"relay_url": "https://your-handle-mhrv.web.val.run",
"psk": "<openssl rand -hex 32>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
دو mode: selective (default — فقط hosts مشخص از طریق exit node میرن) و full (همه میرن). در صورت failure exit node fallback اتومات به Apps Script direct (سایتهای CF affected fail میگیرن، بقیه کار میکنن). hardening over upstream: PSK fail-closed اگر همچنان placeholder باشه (در fresh deploy نمیتونه بهعنوان open relay accidentally سرو بشه)، loop guard (refuse fetch host خود)، 503 explicit برای misconfigured deploys. setup walkthrough در assets/exit_node/README.fa.md. config مثال در config.exit-node.example.json.
• حذف legacy telegram job در release.yml — قبلاً وقتی TELEGRAM_NOTIFY_ENABLED repo variable روی true set بود (در حال حاضر بود)، هر release دو پست duplicate APK روی main channel ایجاد میکرد: یکی قدیمی (universal APK + changelog) از release.yml و یکی جدید (cross-link به files channel) از telegram-publish-files.yml. فقط cross-link جدید رو میخواستیم. legacy job + helper script .github/scripts/telegram_release_notify.py حذف شدن. telegram-publish-files.yml (per-platform per-file posts با SHA-256 captions) تنها مسیر باقی مونده.
• Optional exit node to bypass CF anti-bot on ChatGPT / Claude / Grok / X (ported from upstream masterking32/MasterHttpRelayVPN@464a6e1d, with hardening): Cloudflare-fronted services like chatgpt.com, claude.ai, grok.com, x.com, openai.com flag traffic from Google datacenter IPs (Apps Script's outbound IP space) as bots and return Turnstile / CAPTCHA / 502 challenges. Through v1.9.3 this surfaced as "Relay error: json: key must be a string at line 2 column 1" or generic 502 with no apps_script-mode workaround. Now a small TypeScript HTTP endpoint (assets/exit_node/valtown.ts) deployed on val.town / Deno Deploy / fly.io sits between Apps Script and the destination. Traffic chain: client → SNI rewrite → Apps Script (Google IP) → val.town (non-Google IP) → destination. The destination sees val.town's IP, not Google datacenter — CF's anti-bot heuristic doesn't fire and the real page comes back. The user-side leg (Iran ISP → Apps Script) is unchanged — the second hop happens entirely inside Apps Script's outbound, invisible from the user's network, so the DPI evasion property mhrv-rs is built around stays intact. New config:
"exit_node": {
"enabled": true,
"relay_url": "https://your-handle-mhrv.web.val.run",
"psk": "<openssl rand -hex 32>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
Two modes: selective (default, only listed hosts route via exit node, recommended) or full (everything via exit node, slower). On exit-node failure, mhrv-rs falls back to direct Apps Script automatically — CF-affected sites fail in that case but everything else keeps working, so a down exit node doesn't take you fully offline. Hardening over upstream: PSK fail-closed if still the placeholder (fresh val.town deploy can't accidentally serve as open relay until the user replaces the placeholder), loop guard (refuses to fetch its own host), explicit 503 on misconfigured deploys. Setup walkthrough in assets/exit_node/README.md (English) and README.fa.md (Persian). Complete example config at config.exit-node.example.json.
• Removed the legacy telegram job from release.yml. Previously, with the TELEGRAM_NOTIFY_ENABLED repo variable flipped to true (which it had been), every release produced two duplicate APK posts on the main Telegram channel: the old release.yml job (universal APK + bundled changelog) and the newer telegram-publish-files.yml workflow (per-platform per-file posts to the files channel + a single cross-link to the main channel). Only the cross-link was wanted. The legacy job and its helper script .github/scripts/telegram_release_notify.py are gone. telegram-publish-files.yml is now the only Telegram path. The legacy bundled-on-main pattern is recoverable from git log if anyone ever wants it back.