diff --git a/Cargo.toml b/Cargo.toml index 8f5adc4..e2cd516 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mhrv-rs" -version = "1.2.8" +version = "1.2.9" edition = "2021" description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting" license = "MIT" diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 8545c96..5bca342 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "com.therealaleph.mhrv" minSdk = 24 // Android 7.0 — covers 99%+ of live devices. targetSdk = 34 - versionCode = 128 - versionName = "1.2.8" + versionCode = 129 + versionName = "1.2.9" // Ship all four mainstream Android ABIs: // - arm64-v8a — 95%+ of real-world Android phones since 2019 diff --git a/docs/changelog/v1.2.8.md b/docs/changelog/v1.2.9.md similarity index 84% rename from docs/changelog/v1.2.8.md rename to docs/changelog/v1.2.9.md index ff657c1..64b8caa 100644 --- a/docs/changelog/v1.2.8.md +++ b/docs/changelog/v1.2.9.md @@ -3,8 +3,10 @@ • گزینهٔ ‫`youtube_via_relay`‬ (issue #102): پورت شده از ‫Python‬ بالادست. وقتی فعال شود، ترافیک یوتیوب از مسیر ‫SNI-rewrite‬ خارج می‌شود و از طریق ‫Apps Script‬ می‌رود تا فیلتر ‫SafeSearch-on-SNI‬ گوگل دور زده شود. ترید-آف: ‫User-Agent‬ ثابت می‌شود روی ‫Google-Apps-Script‬ و سهمیهٔ روزانهٔ شما مصرف می‌شود. پیش‌فرض خاموش • رفع دستور ‫scan-sni‬ (PR #97): پاسخ‌های ‫dns.google‬ با ‫Transfer-Encoding: chunked‬ برمی‌گردند و قبل از JSON decode باید ‫unchunk‬ شوند. بدون این پچ هیچ دامنه‌ای کشف نمی‌شد • اعتبارسنجی ‫TLS‬ در ‫scan-sni‬ (PR #98): درخواست ‫DoH‬ به ‫dns.google‬ از ‫NoVerify‬ به ‫webpki roots‬ سوئیچ شد تا یک ‫on-path MITM‬ نتواند ‫PTR‬های جعلی برگرداند و pool ‫SNI‬ را مسموم کند +• رفع کامپایل ‫UI‬ برای ‫`youtube_via_relay`‬: اضافه کردن فیلد به ‫`FormState`‬ و ‫`ConfigWire`‬ در ‫`src/bin/ui.rs`‬ که ‫v1.2.8‬ در ‫CI‬ سقوط کرده بود چون در ‫mhrv-rs-ui‬ فراموش شده بود --- • Real-IP leak fix (issue #104): extended the forwarded-headers filter in the Apps Script relay path to strip every identity-revealing header (`X-Forwarded-For`, `X-Real-IP`, `Forwarded`, `Via`, `CF-Connecting-IP`, `True-Client-IP`, `Fastly-Client-IP` and 10 more) before we ship the request to Apps Script. If a user sits behind a local proxy (xray/v2rayNG) or a browser extension that inserts any of these, the real IP no longer leaks through the relay path to the origin • `youtube_via_relay` config toggle (issue #102): ported from upstream Python. When enabled, YouTube traffic opts out of the SNI-rewrite tunnel and goes through Apps Script instead, bypassing Google's SafeSearch-on-SNI filter that sometimes marks normal videos as "restricted." Trade-off: adds the fixed `Google-Apps-Script` User-Agent and counts YouTube against your daily quota. Off by default • scan-sni chunked-DoH fix (PR #97): `dns.google` replies with `Transfer-Encoding: chunked`; the raw payload was going to serde_json with chunk framing still embedded, so every PTR parse failed and scan-sni discovered nothing. Proper HTTP-body parsing now (chunked + Content-Length), plus unit tests • scan-sni TLS verification (PR #98): the DoH client to `dns.google` was using `NoVerify` — an on-path MITM could forge PTR answers and poison the discovered SNI pool. Switched to the normal webpki root store; the rest of the scan flow is unchanged +• UI build fix for `youtube_via_relay`: the new config field was added to `Config` but not propagated to `FormState` / `ConfigWire` in `src/bin/ui.rs`, so v1.2.8's CI failed compiling `mhrv-rs-ui` with `missing field youtube_via_relay in initializer of Config`. v1.2.8 tag exists but no Release assets — v1.2.9 is the clean cut. diff --git a/src/bin/ui.rs b/src/bin/ui.rs index b745bee..58aa400 100644 --- a/src/bin/ui.rs +++ b/src/bin/ui.rs @@ -212,6 +212,7 @@ struct FormState { scan_batch_size:usize, google_ip_validation: bool, normalize_x_graphql: bool, + youtube_via_relay: bool, } #[derive(Clone, Debug)] @@ -289,6 +290,7 @@ fn load_form() -> (FormState, Option) { google_ip_validation: c.google_ip_validation, scan_batch_size:c.scan_batch_size, normalize_x_graphql: c.normalize_x_graphql, + youtube_via_relay: c.youtube_via_relay, } } else { FormState { @@ -314,6 +316,7 @@ fn load_form() -> (FormState, Option) { google_ip_validation:true, scan_batch_size:500, normalize_x_graphql: false, + youtube_via_relay: false, } }; (form, load_err) @@ -449,6 +452,10 @@ impl FormState { google_ip_validation:self.google_ip_validation, scan_batch_size:self.scan_batch_size, normalize_x_graphql: self.normalize_x_graphql, + // UI form doesn't expose youtube_via_relay yet — it's a + // config-only flag for now. Passed through from the loaded + // config if set, otherwise defaults to false. + youtube_via_relay: self.youtube_via_relay, }) } } @@ -487,6 +494,8 @@ struct ConfigWire<'a> { sni_hosts: Option>, #[serde(skip_serializing_if = "is_false")] normalize_x_graphql: bool, + #[serde(skip_serializing_if = "is_false")] + youtube_via_relay: bool, // IP-scan knobs. These used to be missing from the wire struct, so // every Save-config silently dropped them — the user would toggle // "fetch from API" on, save, reopen, and find it off again. Add @@ -538,6 +547,7 @@ impl<'a> From<&'a Config> for ConfigWire<'a> { .as_ref() .map(|v| v.iter().map(String::as_str).collect()), normalize_x_graphql: c.normalize_x_graphql, + youtube_via_relay: c.youtube_via_relay, fetch_ips_from_api: c.fetch_ips_from_api, max_ips_to_scan: c.max_ips_to_scan, scan_batch_size: c.scan_batch_size,