Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
aac63e8
chore(config): add toml crate and define TOML intermediate structs
CaptainMirage May 16, 2026
f739f60
feat(config): implement Config::load_toml and Config<->TomlConfig con…
CaptainMirage May 17, 2026
3ff2599
feat(config): implement auto-migration from JSON to TOML on startup
CaptainMirage May 17, 2026
b5be6eb
refactor(config): update all call sites to unified Config::load, save…
CaptainMirage May 17, 2026
d6db623
chore(data_dir): update config paths from config.json to config.toml
CaptainMirage May 18, 2026
fd5bf92
chore(config): replaced JSON example configs with TOML, update string…
CaptainMirage May 18, 2026
fa814fa
test(config): add TOML loading and JSON migration tests
CaptainMirage May 18, 2026
3cd26e2
tests: clean up orphaned .toml files in rt_tests after JSON migration
CaptainMirage May 19, 2026
269b64f
docs: update all user-facing config.json references to config.toml
CaptainMirage May 19, 2026
d44c2fd
docs: update some leftover user-facing config.json references to conf…
CaptainMirage May 19, 2026
7c9d6da
fix: emit migration warning before tracing subscriber is initialised
CaptainMirage May 19, 2026
b598368
fix: defer migration warning until after tracing subscriber is initia…
CaptainMirage May 19, 2026
f32d916
fix: update ui.rs Config::load call site for new tuple return type
CaptainMirage May 19, 2026
da691a7
Merge remote-tracking branch 'upstream/main' into feat/toml-config-mi…
CaptainMirage May 19, 2026
898f453
fix: bench-pipeline.sh temp config and Python mutator TOML support
CaptainMirage May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ base64 = "0.22"
bytes = "1"
httparse = "1"
rand = "0.8"
toml = "0.8"
h2 = "0.4"
http = "1"
flate2 = "1"
Expand Down
8 changes: 4 additions & 4 deletions SF_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Click **Connect** (or **Start** on desktop). Done. Your browser, Telegram, etc.
### Common issues (most people hit at least one)

**YouTube videos look "restricted" or comments are missing? ([#61](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/61))**
Turn on **"Send YouTube through relay (no SNI rewrite)"** in the desktop UI's Advanced section, or set `youtube_via_relay: true` in `config.json`. YouTube then goes through the Apps Script relay instead of the direct Google tunnel, which avoids YouTube's SafeSearch-on-SNI behaviour. Trade-off: slightly slower video, and it counts against your daily quota.
Turn on **"Send YouTube through relay (no SNI rewrite)"** in the desktop UI's Advanced section, or set `youtube_via_relay = true` in `config.toml`. YouTube then goes through the Apps Script relay instead of the direct Google tunnel, which avoids YouTube's SafeSearch-on-SNI behaviour. Trade-off: slightly slower video, and it counts against your daily quota.

**"Verify you are human" loop on Cloudflare-protected sites?**
This can't be fixed in this app. Every Apps Script request comes from a different Google datacenter IP, and Cloudflare's challenge cookie is locked to one IP — so the next request fails the check and re-challenges you. Sites that only check once per session work fine. Sites that check every page won't.
Expand All @@ -58,7 +58,7 @@ This can't be fixed in this app. Every Apps Script request comes from a differen
Your Apps Script deployment isn't responding. Go back to <https://script.google.com>, **Deploy → Manage deployments → Edit (pencil)**, change "Version" to **New version**, click Deploy. Copy the **new** Deployment ID and paste it into the app.

**Hit your daily limit?**
Free Google accounts get **20,000 relay requests per day**. The desktop and Android apps show a "Usage today" card with how many you've used. Add multiple Deployment IDs (one per line in the UI, or a JSON array in `config.json`) — each ID has its own quota and they're rotated automatically. You can also click "View quota on Google" to see the official number on Google's dashboard.
Free Google accounts get **20,000 relay requests per day**. The desktop and Android apps show a "Usage today" card with how many you've used. Add multiple Deployment IDs (one per line in the UI, or an array in `config.toml`) — each ID has its own quota and they're rotated automatically. You can also click "View quota on Google" to see the official number on Google's dashboard.

**App says it's connected but websites don't load?**
- Open the **SNI pool** section and click **Test all**. If everything fails, your `google_ip` value is unreachable from your network — click **Auto-detect google_ip** to fix.
Expand Down Expand Up @@ -120,7 +120,7 @@ This project is free and run by volunteers. If it helped you and you can spare a
### مشکلات رایج (اکثر کاربران حداقل یکی از این‌ها را می‌بینند)

**ویدیوهای یوتیوب «محدود» نشان داده می‌شوند یا کامنت‌ها دیده نمی‌شوند؟ ([#61](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/61))**
در بخش Advanced دسکتاپ گزینهٔ **«Send YouTube through relay (no SNI rewrite)»** را روشن کنید، یا در `config.json` مقدار `youtube_via_relay: true` بگذارید. در این حالت یوتیوب از مسیر ریلهٔ Apps Script رد می‌شود و فیلتر SafeSearch-on-SNI گوگل دور می‌خورد. تریدآف: ویدیو کمی کندتر و مصرف از سهمیهٔ روزانه.
در بخش Advanced دسکتاپ گزینهٔ **«Send YouTube through relay (no SNI rewrite)»** را روشن کنید، یا در `config.toml` مقدار `youtube_via_relay = true` بگذارید. در این حالت یوتیوب از مسیر ریلهٔ Apps Script رد می‌شود و فیلتر SafeSearch-on-SNI گوگل دور می‌خورد. تریدآف: ویدیو کمی کندتر و مصرف از سهمیهٔ روزانه.

**روی سایت‌های پشت Cloudflare loop «Verify you are human» می‌خورد؟**
این مشکل در این ابزار قابل حل نیست. هر درخواست Apps Script از یک IP متفاوت دیتاسنتر گوگل خارج می‌شود و کوکی challenge کلودفلر به یک IP خاص قفل است — درخواست بعدی از IP دیگر دوباره چالش می‌خورد. سایت‌هایی که فقط یک‌بار در ابتدای session چک می‌کنند درست کار می‌کنند. سایت‌هایی که هر صفحه چک می‌کنند، نه.
Expand All @@ -129,7 +129,7 @@ This project is free and run by volunteers. If it helped you and you can spare a
Apps Script شما پاسخ نمی‌دهد. به <https://script.google.com> برگردید، **Deploy → Manage deployments → Edit (آیکن مداد)** را بزنید، گزینهٔ "Version" را روی **New version** بگذارید و Deploy کنید. **آی‌دی جدید** Deployment را کپی کنید و در برنامه جای‌گذاری کنید.

**سهمیهٔ روزانه تمام شده؟**
هر حساب گوگل رایگان روزانه **۲۰٬۰۰۰ درخواست ریله** دارد. کارت «مصرف امروز» در دسکتاپ و اندروید مقدار مصرف فعلی را نشان می‌دهد. می‌توانید چند Deployment ID (هر کدام در یک خط، یا به‌صورت JSON array در `config.json`) اضافه کنید — هر آی‌دی سهمیهٔ خودش را دارد و به‌صورت چرخشی استفاده می‌شوند. دکمهٔ «مشاهدهٔ سهمیه در گوگل» شما را به داشبورد رسمی گوگل می‌برد.
هر حساب گوگل رایگان روزانه **۲۰٬۰۰۰ درخواست ریله** دارد. کارت «مصرف امروز» در دسکتاپ و اندروید مقدار مصرف فعلی را نشان می‌دهد. می‌توانید چند Deployment ID (هر کدام در یک خط، یا در `config.toml`) اضافه کنید — هر آی‌دی سهمیهٔ خودش را دارد و به‌صورت چرخشی استفاده می‌شوند. دکمهٔ «مشاهدهٔ سهمیه در گوگل» شما را به داشبورد رسمی گوگل می‌برد.

**برنامه می‌گوید وصل است ولی سایت‌ها باز نمی‌شوند؟**
- بخش **SNI pool** را باز کنید و **Test all** بزنید. اگر همه fail شدند، یعنی `google_ip` فعلی از شبکهٔ شما در دسترس نیست — روی **Auto-detect google_ip** بزنید تا اصلاح شود.
Expand Down
2 changes: 1 addition & 1 deletion assets/apps_script/Code.cfw.gs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
* 6. Set WORKER_URL to your *.workers.dev URL (must include https://).
* 7. Deploy → New deployment → Web app
* Execute as: Me | Who has access: Anyone
* 8. Copy the Deployment ID into mhrv-rs config.json as "script_id".
* 8. Copy the Deployment ID into mhrv-rs config.toml as "script_id".
* mhrv-rs does not need to know about Cloudflare; it talks to
* Apps Script the same way it always has.
*
Expand Down
2 changes: 1 addition & 1 deletion assets/apps_script/Code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* 4. (Optional) Set CACHE_SPREADSHEET_ID to enable caching
* 5. Click Deploy → New deployment
* 6. Type: Web app | Execute as: Me | Who has access: Anyone
* 7. Copy the Deployment ID into config.json as "script_id"
* 7. Copy the Deployment ID into config.toml as "script_id"
*
* CHANGE THE AUTH KEY BELOW TO YOUR OWN SECRET!
*/
Expand Down
17 changes: 8 additions & 9 deletions assets/cloudflare/README.fa.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mhrv-rs ──► Apps Script (Code.cfw.gs) ──► Cloudflare Worker ──
▲ فقط احراز هویت و فوروارد ▲ گرفتن داده + base64
```

پشتیبان استاندارد ([`assets/apps_script/Code.gs`](../apps_script/Code.gs)) خودِ `Apps Script` کار `fetch` به مقصد را انجام می‌دهد. این نسخه‌ٔ جایگزین، `Apps Script` را به یک رلهٔ نازک تبدیل می‌کند و کارِ اصلی را به لبهٔ `Cloudflare` می‌سپارد. **خود `mhrv-rs` تغییر نمی‌کند** — همان پاکت `JSON` روی سیم، همان `mode: "apps_script"` در `config.json`، همان `script_id`. تنها تفاوت این است که `Apps Script` مستقر شدهٔ شما بعد از احراز هویت چه می‌کند.
پشتیبان استاندارد ([`assets/apps_script/Code.gs`](../apps_script/Code.gs)) خودِ `Apps Script` کار `fetch` به مقصد را انجام می‌دهد. این نسخه‌ٔ جایگزین، `Apps Script` را به یک رلهٔ نازک تبدیل می‌کند و کارِ اصلی را به لبهٔ `Cloudflare` می‌سپارد. **خود `mhrv-rs` تغییر نمی‌کند** — همان پاکت `JSON` روی سیم، همان `mode = "apps_script"` در `config.toml`، همان `script_id`. تنها تفاوت این است که `Apps Script` مستقر شدهٔ شما بعد از احراز هویت چه می‌کند.

ایدهٔ اصلی: <https://github.com/denuitt1/mhr-cfw>. این کپی یک بررسی `AUTH_KEY` روی خود `Worker` اضافه می‌کند، رفتار «صفحهٔ تقلبی برای کلید نامعتبر» را از `Code.gs` به ارث می‌برد، و یک محافظ در برابر حلقه‌شدن دارد.

Expand All @@ -33,7 +33,7 @@ mhrv-rs ──► Apps Script (Code.cfw.gs) ──► Cloudflare Worker ──

## راه‌اندازی

سه رشتهٔ هم‌خوان نیاز دارید: یک `AUTH_KEY` که بین `worker.js`، `Code.cfw.gs` و `config.json` خود `mhrv-rs` مشترک است. یک رمز تصادفی قوی انتخاب کنید و در هر سه جا paste کنید.
سه رشتهٔ هم‌خوان نیاز دارید: یک `AUTH_KEY` که بین `worker.js`، `Code.cfw.gs` و `config.toml` خود mhrv-rs مشترک است. یک رمز تصادفی قوی انتخاب کنید و در هر سه جا paste کنید.

### ۱. استقرار `Worker`

Expand All @@ -58,14 +58,13 @@ mhrv-rs ──► Apps Script (Code.cfw.gs) ──► Cloudflare Worker ──

### ۳. اشاره دادن `mhrv-rs` به این `Apps Script`

در `config.json` (یا از طریق فرم `UI`):
در `config.toml` (یا از طریق فرم `UI`):

```json
{
"mode": "apps_script",
"script_id": "PASTE_DEPLOYMENT_ID_HERE",
"auth_key": "SAME_SECRET_AS_BOTH_FILES_ABOVE"
}
```toml
[relay]
mode = "apps_script"
auth_key = "YOUR_SHARED_SECRET"
script_ids = ["YOUR_DEPLOYMENT_ID"]
```

تمام. `mhrv-rs` لازم نیست بداند `Cloudflare` در کار است؛ از نگاه او این `script_id` مثل هر `Deployment` دیگری رفتار می‌کند. اگر چند `Deployment` دارید (بعضی استاندارد، بعضی `CFW`)، می‌توانید همه را در `script_ids: [...]` بگذارید — `round-robin` و `parallel-relay` همچنان روی همه‌شان کار می‌کند.
Expand Down
17 changes: 8 additions & 9 deletions assets/cloudflare/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mhrv-rs ──► Apps Script (Code.cfw.gs) ──► Cloudflare Worker ──
▲ thin auth + forward ▲ outbound fetch + base64
```

The standard backend (`assets/apps_script/Code.gs`) does the outbound fetch from inside Apps Script directly. This variant makes Apps Script a thin relay and pushes the actual fetch to Cloudflare's edge. **mhrv-rs itself is unchanged** — same JSON envelope on the wire, same `mode: "apps_script"` in `config.json`, same `script_id`. The only thing that's different is what your deployed Apps Script does after it authenticates the request.
The standard backend (`assets/apps_script/Code.gs`) does the outbound fetch from inside Apps Script directly. This variant makes Apps Script a thin relay and pushes the actual fetch to Cloudflare's edge. **mhrv-rs itself is unchanged** — same JSON envelope on the wire, same `mode = "apps_script"` in `config.toml`, same `script_id`. The only thing that's different is what your deployed Apps Script does after it authenticates the request.

Original idea: <https://github.com/denuitt1/mhr-cfw>. This copy adds an `AUTH_KEY` check on the Worker, the decoy-on-bad-auth treatment from `Code.gs`, and a hop-loop guard.

Expand All @@ -26,7 +26,7 @@ Original idea: <https://github.com/denuitt1/mhr-cfw>. This copy adds an `AUTH_KE

## Setup

You need three matching strings: an `AUTH_KEY` shared between `worker.js`, `Code.cfw.gs`, and your `mhrv-rs` `config.json`. Pick a strong random secret once and paste it into all three.
You need three matching strings: an `AUTH_KEY` shared between `worker.js`, `Code.cfw.gs`, and your mhrv-rs `config.toml`. Pick a strong random secret once and paste it into all three.

### 1. Deploy the Worker

Expand All @@ -47,14 +47,13 @@ You need three matching strings: an `AUTH_KEY` shared between `worker.js`, `Code

### 3. Point mhrv-rs at the Apps Script

In `config.json` (or via the UI's config form):
In `config.toml` (or via the UI's config form):

```json
{
"mode": "apps_script",
"script_id": "PASTE_DEPLOYMENT_ID_HERE",
"auth_key": "SAME_SECRET_AS_BOTH_FILES_ABOVE"
}
```toml
[relay]
mode = "apps_script"
auth_key = "YOUR_SHARED_SECRET"
script_ids = ["YOUR_DEPLOYMENT_ID"]
```

That's it. mhrv-rs doesn't need to know Cloudflare exists; from its perspective, the `script_id` deployment behaves like any other. If you have multiple deployments (some plain, some CFW), `script_ids: [...]` round-robins across all of them and the parallel-relay fan-out still works.
Expand Down
2 changes: 1 addition & 1 deletion assets/cloudflare/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
* 1. Cloudflare dashboard → Workers & Pages → Create → Hello World
* 2. Edit code → delete the template, paste this entire file
* 3. Change AUTH_KEY below to the same value you set in Code.cfw.gs
* AND in your mhrv-rs config.json (auth_key). All three must match.
* AND in your mhrv-rs config.toml (auth_key). All three must match.
* 4. Deploy. Note the *.workers.dev URL; paste it into Code.cfw.gs as
* WORKER_URL.
*
Expand Down
21 changes: 10 additions & 11 deletions assets/exit_node/README.fa.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,14 @@ APIهای web-standard (`Request`، `Response`، `fetch`) استفاده می‌
جلوی serve شدن به‌عنوان open relay accidentally گرفته بشه.
۲. فایل رو روی host انتخابی **deploy** کنید (گزینه‌ها در ادامه).
۳. URL public deployment رو **copy** کنید.
۴. در `config.json` mhrv-rs، block `exit_node` اضافه کنید:
```json
"exit_node": {
"enabled": true,
"relay_url": "https://your-deployed-exit-node.example.com",
"psk": "<همان PSK که در گام ۱ گذاشتید>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
۴. در `config.toml` mhrv-rs، section `[exit_node]` اضافه کنید:
```toml
[exit_node]
enabled = true
relay_url = "https://your-deployed-exit-node.example.com"
psk = "<همان PSK که در گام ۱ گذاشتید>"
mode = "selective"
hosts = ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
```
۵. mhrv-rs رو **restart** کنید (Disconnect + Connect، یا `kill` +
restart binary).
Expand Down Expand Up @@ -127,7 +126,7 @@ PSK تنها چیز است که مانع می‌شه endpoint deployed یک publ
- **publicly share نکنید** PSK رو. هر کسی که هم URL هم PSK رو داره
می‌تونه quota host شما رو به‌عنوان proxy خود استفاده کنه.
- **rotate** اگر leak مشکوک هست. PSK رو در source deployed تغییر بدید،
redeploy کنید، سپس `psk` در `config.json` mhrv-rs رو update + restart.
redeploy کنید، سپس `psk` در `config.toml` mhrv-rs رو update + restart.

اسکریپت همچنین شامل **loop guard** هست (refuse می‌کنه fetch host خود)
+ **placeholder check** (در صورت `PSK === "CHANGE_ME_TO_A_STRONG_SECRET"`
Expand All @@ -147,7 +146,7 @@ Grok اهمیت می‌دن opt in؛ همه‌ی دیگران lighter اجرا
## Troubleshooting

**`exit node refused or errored: unauthorized`** — PSK mismatch.
بررسی کنید `psk` در `config.json` دقیقاً با `PSK` constant در source
بررسی کنید `psk` در `config.toml` دقیقاً با `PSK` constant در source
deployed match هست. whitespace + quoting مهم است.

**`exit node refused or errored: exit_node misconfigured: PSK is still
Expand Down
Loading
Loading