| --- |
| title: MYPRO |
| emoji: ⚡ |
| colorFrom: blue |
| colorTo: indigo |
| sdk: gradio |
| sdk_version: 4.44.0 |
| app_file: app.py |
| pinned: false |
| --- |
| |
| # מעקף פרוקסי 2.0 (Etrog Bypass Proxy) |
|
|
| Reverse proxy מבוזר: **Cloudflare Worker** + **Service Worker** בדפדפן, לעקיפת סינון יתר (SNI/DPI/DNS) לצריכת תוכן חוקי (מנוי פעיל). |
|
|
| ## כתובת פרוסה |
|
|
| https://etrog-bypass-proxy.miriklain616.workers.dev |
|
|
| | נתיב | תפקיד | |
| |------|--------| |
| | `/` | דף בית + ניווט | |
| | `/ytp?v=VIDEO_ID` | נגן YouTube יציב (מומלץ) | |
| | `/websearch?q=…&t=web\|images\|videos\|news&p=N` | חיפוש נייטיב: רשת / תמונות / וידאו / חדשות | |
| | `/api/websearch?q=…&t=…&p=N` | אותן תוצאות כ-JSON | |
| | `/x/p?d=<token>` | פרוקסי תמונות כללי (אטום ב-XOR כשה-SW פעיל) | |
| | `/cdn/<token>` | פרוקסי מוצפן (XOR) לכתובת יעד | |
| | `/api/m?v=…&i=18` | זרם וידאו YouTube (same-isolate) | |
| | `/sw.js` | Service Worker | |
| | `/import-cookies` | ייבוא עוגיות (YouTube / אתרים אחרים) | |
| | `/api/health` | בדיקת חיים | |
|
|
| ### חיפוש — למה אין "אני לא רובוט" |
|
|
| הכלל היחיד: **המשתמש לעולם לא מגיע לדף של מנוע חיפוש זר.** כל תוצאה נאספת ב-Worker ומוצגת |
| בדף שלנו, ולכן אין CAPTCHA, אין באנר הסכמה ואין SPA שנשבר דרך הפרוקסי. |
| Google / Brave / Mojeek / Startpage / SearX מציגים אתגר ל-IP של דאטה-סנטר — ולכן **אינם בשימוש |
| כלל**, וגם הוסרו מהקיצורים בדף הבית. |
|
|
| | לשונית | מקור ראשי | גיבויים | |
| |--------|-----------|---------| |
| | רשת | Bing (עמוד 1) | Yahoo (עמודים 2+ — רק לו יש דפדוף אמין), DuckDuckGo | |
| | תמונות | Bing (לטינית) / DuckDuckGo (עברית ושאר כתבים) | Wikimedia Commons | |
| | וידאו | YouTube InnerTube → נגן `/ytp` הפנימי | Bing Videos | |
| | חדשות | Bing News RSS | — | |
|
|
| שתי מלכודות שהקוד מטפל בהן: |
|
|
| 1. **דפדוף של Bing מדומה.** `&first=` מתעלם ומחזיר שוב את עמוד 1, ולכן עמודים 2+ מגיעים מ-Yahoo |
| (`&b=`), שבו הדפדוף אמיתי. |
| 2. **Bing "חוטף" שאילתות שאינן לטיניות.** הוא מחזיר דף עם כותרת נכונה (`ירושלים - חיפוש תמונות`) |
| אבל תוצאות שאינן קשורות בכלל — בלי שום קוד שגיאה. `resultsLookRelevant()` פוסל סט כזה |
| וממשיך למנוע הבא; אם כולם נכשלים מוצג "לא נמצאו תוצאות" ולא זבל. הבדיקה חלה רק על מנועים |
| שנגרדים מ-HTML — לא על API מובנה (Commons/RSS/InnerTube), שם הכיתובים לגיטימית בשפה אחרת. |
|
|
| **תמונות** עוברות דרך `/x/p`: ה-Worker מאמת magic-bytes, וה-Service Worker מוסיף `X-Etrog-SW` |
| כדי לקבל אותן אטומות (XOR) — כך הפילטר לא מזהה JPEG ולא מטשטש. בלי SW הן מוגשות רגילות, |
| כך שגם טעינה ראשונה עובדת. |
|
|
| ## איך עוקפים את הסינון (ומה נכשל קודם) |
|
|
| הפילטר (Rimon/Etrog) **מסווג לפי גוף התשובה, לא לפי הכתובת**. הוא עושה MITM על החיבור |
| לוורקר, קורא את ה-HTML, ומחליף אותו בדף חסימה — מזוהה לפי `rimon: RWC_BLOCK` + |
| `server: lighttpd`. לכן ynet ו-mako נחסמו, למרות שהוורקר החזיר אותם תקין. |
|
|
| התשובה: **כל מה שניתן לסיווג נשלח אטום (XOR)**. הפילטר רואה בייטים חסרי-משמעות, |
| ה-Service Worker מפענח לפני שהדפדפן רואה. |
|
|
| | סוג | אטום? | למה | |
| |-----|-------|-----| |
| | מסמך HTML (ניווט + iframe) | ✅ | זה מה שהפילטר מסווג | |
| | XHR/JSON | ✅ | אתרי חדשות מגישים את הכתבה כ-JSON | |
| | תמונות | ✅ | אחרת הפילטר מטשטש אותן | |
| | JS | ❌ | אטימה שברה מודולים של YouTube (SyntaxError) | |
| | CSS | ❌ | לא מסווג, וסיכון מיותר | |
| | פונטים | ❌ | בקשה שתחמוק מה-SW תקבל בייטים אטומים ו-OTS יפסול | |
| | מדיה / Range | ❌ | שובר ניגון פרוגרסיבי | |
|
|
| **המלכודת שהייתה:** ה-Service Worker ויתר לגמרי על ניווטים |
| (`if (e.request.mode === 'navigate') return;`), ולכן המסמך הראשי — בדיוק מה שנחסם — עבר |
| בטקסט גלוי. בנוסף, ענף ה-HTML בוורקר החזיר תשובה לפני שהגיע לקוד האטימה, כך ש- |
| `X-Proxy-Obfuscate` פשוט לא נלקח בחשבון עבור HTML. שני החצאים תוקנו. |
|
|
| > אחרי ריווייט, **כל** משאבי המשנה של דף הם כתובות `/cdn/` באותו origin — ולכן הענף |
| > ה-same-origin ב-SW (ולא זה של cross-origin) הוא שקובע מה נשלח אטום. הוא אטם רק תמונות. |
|
|
| ## ניווט בין דפים (הבאג של "הדף הראשי נטען אבל אי אפשר להתקדם") |
|
|
| רוב הקישורים עוברים ריווייט ל-`/cdn/<token>` ולכן הם חד-משמעיים. אבל **כתובת "עירומה"** — |
| ניתוב SPA, קישור שנבנה ב-JS, או רענון של אחד מהם — מגיעה בלי יעד משלה, והוורקר חייב |
| להסיק לאיזה אתר היא שייכת. שני מקורות המידע לכך היו שבורים: |
|
|
| 1. **`__proxy_target` נדרס על ידי כל תשובת HTML** — כולל `<iframe>` ממקור אחר או XHR |
| שמחזיר HTML. מספיק ווידג'ט/פרסומת שמתארחת על S3 או CDN, והעוגיה של כל הסשן מצביעה |
| עליו. הכתובת העירומה הבאה נפתרה ל-`<bucket>/path`, ו-S3 החזיר `<Code>AccessDenied</Code>`. |
| **תוקן:** רק ניווט של מסמך ראשי מזיז את `__proxy_target`. iframe ו-XHR — לעולם לא. |
| 2. **`referrer-policy: no-referrer`** ביטל את הפתרון לפי Referer, שהוא דווקא המדויק, |
| והשאיר את העוגיה (הניתנת לזיהום) כאות היחיד. **תוקן:** `same-origin` — כל בקשת משנה |
| מפורקסטת היא same-origin ולכן שומרת Referer שימושי, ולאתרי יעד לא נשלח כלום. |
| (הוורקר ממילא דורס את ה-Referer שיוצא החוצה לכתובת של אתר היעד עצמו.) |
|
|
| בנוסף, טעינת **דף** בכתובת עירומה מקבלת עכשיו 302 לכתובת הקנונית `/cdn/<token>`, כך |
| שרענון, סימנייה או Back כבר לא תלויים במצב סשן שצד שלישי יכול להזיז. |
|
|
| ## ארכיטקטורה |
|
|
| 1. **Service Worker** מיירט Fetch/XHR/Media, מצפין כתובות (XOR + base64url, מפתח `antigravity`) ושולח ל-Worker. |
| 2. **Cloudflare Worker** מפענח, מביא מהיעד, משכתב HTML/M3U8/JSON, מחזיר תשובה (לעיתים מוצפנת). |
| 3. **YouTube**: נתיבי `/watch` מנותבים ל-`/ytp`; הזרם מגיע מ-`/api/m` באותו isolate של ה-Worker (מונע 403 IP mismatch). |
| 4. **מדיה (Scania וכו')**: זיהוי `isMedia` מדלג על HTMLRewriter כדי לא להשחית מקטעים בינאריים שמוסווים כ-`text/html`. |
|
|
| ## פריסה |
|
|
| ```bash |
| # Windows PowerShell |
| $env:CLOUDFLARE_API_TOKEN="your_token" |
| npx wrangler deploy |
| ``` |
|
|
| או: `npm run deploy` אחרי `npm install`. |
|
|
| ## אבטחה |
|
|
| - **אל תשימו API Token בקוד או ב-git.** השתמשו במשתנה סביבה `CLOUDFLARE_API_TOKEN`. |
| - אם הטוקן דלף — בטלו אותו ב-Cloudflare Dashboard וצרו חדש. |
|
|
| ### Secrets מומלצים (Cloudflare → Worker → Settings → Variables/Secrets) |
|
|
| הקוד קורא קודם מ-env ונופל לברירת-מחדל רק אם לא הוגדר. הגדירו כ-**Secret** (לא Plaintext): |
|
|
| | Secret | תפקיד | ברירת מחדל אם לא מוגדר | |
| |--------|-------|------------------------| |
| | `GATE_PASSWORD` | סיסמת השער | הערך המוטמע (מומלץ לדרוס) | |
| | `GATE_SECRET` | מפתח חתימת טוקן השער. **שינוי שלו מנתק מיד את כל הסשנים** (רוטציה) | מפתח מוטמע — מומלץ לדרוס | |
| | `NACHOTOY_SID` | סשן ה-VIP של Nachotoy (`connect.sid` בלבד, בלי השם) | ריק → האתר פשוט לא מחובר-אוטומטית | |
|
|
| ```bash |
| # דוגמה (PowerShell) |
| $env:CLOUDFLARE_API_TOKEN="…" |
| npx wrangler secret put GATE_SECRET |
| npx wrangler secret put GATE_PASSWORD |
| npx wrangler secret put NACHOTOY_SID |
| ``` |
|
|
| - **טוקן השער** אינו עוד ערך קבוע: הוא בפורמט `v2.<תפוגה>.<חתימה>`, פג אחרי 30 יום, וניתן |
| לביטול מיידי ע"י שינוי `GATE_SECRET`. |
| - **`connect.sid` של Nachotoy הוסר מהקוד.** הסשן הישן דלף ל-git history — **החליפו אותו** |
| (התנתקו והתחברו מחדש ב-Nachotoy כדי לפסול את הישן) והכניסו את החדש כ-Secret `NACHOTOY_SID`. |
| - **הגנת SSRF:** נתיב `/cdn/` חוסם כתובות פנימיות (loopback / RFC1918 / link-local / |
| 169.254.169.254). ה-relay חוסם גם הוא כתובות-IP פנימיות בנוסף ל-allowlist של Google. |
|
|
| ## למה `/ytp` ולא YouTube עצמו |
|
|
| נבדק אמפירית (2026-07-26): |
|
|
| | מאיפה | `youtube.com/watch` | תוצאה | |
| |-------|---------------------|-------| |
| | Cloudflare (הוורקר) | דף `/sorry/` — CAPTCHA | הוורקר נופל ל-`makeSorryResponse` → `/ytp` | |
| | IP ביתי (relay) | 938KB, `playabilityStatus: OK`, כתובות `url=` גלויות | תקין לחלוטין | |
| | InnerTube API מ-Cloudflare | `ANDROID+IOS`, 12 פורמטים | **עובד** — וזה מה ש-`/ytp` משתמש בו | |
|
|
| כלומר: **דף ה-HTML** של YouTube חסום ל-IP של דאטה-סנטר, אבל **ה-API** לא. `/ytp` מנצל |
| בדיוק את הפער הזה, ולכן המדיה זורמת דרך Cloudflare (מהיר) ולא דרך הבית. |
|
|
| להצגה ביוטיוב עצמו צריך: להביא את ה-HTML דרך ה-relay (≈1MB לכל טעינת דף על החיבור |
| הביתי), ואז **להחליף** את `streamingData` בתשובת `/youtubei/v1/player` בכתובות שהוורקר |
| פתר בעצמו — אחרת כתובות googlevideo יהיו חתומות ל-IP הביתי בעוד הבייטים נמשכים |
| מ-Cloudflare, ויחזור 403. התשתית לכך קיימת חלקית (`rewritePlayerApiJson`). |
| `?yt_ui=1` הוא פתח המילוט הקיים לניסיון. |
|
|
| ## ניגון: למה 502 על `/x/s/…bin` |
|
|
| כתובות googlevideo **חתומות ל-IP שפתר אותן**. פורמט שנפתר בוורקר חתום ל-Cloudflare וחייב |
| להישלף מ-Cloudflare; פורמט שנפתר דרך ה-relay חתום ל-IP הביתי וחייב לחזור דרכו. |
|
|
| הבאג: `tryFetchMedia` לקח את ה-relay **בלעדית** בכל פעם שהוא מוגדר, והחזיר `null` ברגע |
| שהוא נכשל — בלי לנסות אף פעם את הנתיב הישיר. כשהמנהרה נופלת, הניגון מת לגמרי, למרות |
| שהכתובות חתומות ל-Cloudflare וניתנות לשליפה ישירה (רואים את זה ב-`ip=172.70.x` שבתוך |
| כתובת ה-videoplayback). התוצאה: "שגיאה בניגון" + מאות 502. |
|
|
| עכשיו **שני** הנתיבים נוסים, לפי הסדר שממנו הכתובות באמת הגיעו (`pack.via`). |
|
|
| בנוסף, לולאת הפורמטים בלעה חריגות (`catch { /* next */ }`), כך ש-502 היה עיוור לחלוטין. |
| גוף השגיאה כולל עכשיו `dbg[]` עם ניסיון-אחר-ניסיון (סטטוס, content-type, שגיאה) — |
| אם ניגון נכשל שוב, זה מה שצריך להעתיק. |
|
|
| ## פתרון בעיות YouTube |
|
|
| 1. פתחו `/ytp` (לא את ממשק YouTube המלא — לא יציב דרך CF). |
| 2. אם יש 502 / no format: `/import-cookies` עם עוגיות מחשבון מחובר (כולל `SAPISID`). |
| 3. כתובות googlevideo חתומות ל-IP של ה-Worker — אל תעבירו `X-Forwarded-For`. |
|
|