├── LICENSE ├── README.md └── Script ├── Clansty ├── README.md └── proxy.js ├── KusakabeSi ├── README.md ├── reverse_demo.js └── worker.js ├── Mikotwa ├── README.md └── index.js ├── viperadnan ├── README.md └── booster.js ├── xiaoyang-sde ├── Examples │ ├── GitHub.com │ ├── google.com │ ├── nytimes.com │ └── pornhub.com ├── README.md └── index.js └── ymyuuu ├── README.md └── worker.js /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### INTRO 2 | 3 | Workers-Proxy is a lightweight Javascript Reverse Proxy based on Cloudflare Workers. 4 | 5 | Users could deploy the reverse proxy on Cloudflare's global network without setting up virtual private servers and configuring Nginx or Apache. 6 | 7 | ## ✨ Unique Features 8 | 9 | - 🔎 Bypass Country Blockade 10 | - 🔐 Block specific areas or IP 11 | - 🚀 Some Important Features 12 | - 📥 Speed 13 | - 📥 Optimization 14 | - 📥 Firewall 15 | - 📥 Serverless 16 | - 📥 Increase security 17 | - 🛠️ String replacement 18 | - 🧬 Custom resource replacment 19 | - 🪅 Removing Ads Possible 20 | 21 | ## 🤝 Special Thanks & Credits 22 | 23 | ### Source: 24 | - **[xiaoyang-sde](https://github.com/xiaoyang-sde)** : for writing such a great script 25 | - **[viperadnan-git](https://github.com/viperadnan-git) & all initial contributors** : for contributing to the project 26 | - **[KusakabeSi](https://github.com/5MayRain)** : for implementing string replacement & custom resources 27 | - **[Mikotwa](https://github.com/Mikotwa)** : for implementing HTMLRewriter 28 | 29 | ## 🚸 Warnings : 30 | 31 | - This is Just For Educational Purpose 32 | - DO NOT Sell this Script, This is 💯% Free 33 | 34 | ## 🤗 Meet Me : 35 | 36 | 37 | • 😪 check you did all things perfectly before contacting [ Warning ]
38 | • For any Support About Script contact [@OshekherO](https://t.me/OshekherO) at Telegram
39 | 40 | --- 41 |

© 2022 ツ ѕнєкнєя

42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Script/Clansty/README.md: -------------------------------------------------------------------------------- 1 | ### Cloudflare-Telegram-Channel-Proxy 2 | 3 | Reverse proxy Telegram Channel's preview page for embedding in other web pages 4 | 5 | ## Cause 6 | 7 | When you want to embed your TG channel preview into your website, you should find that the parameter in the response header of the channel preview page tells the browser not to load it. So we need to reverse proxy the preview page and remove the header that prevents loading. 8 | 9 | ## What does this program do 10 | 11 | This is a [Cloudflare Worker](https://workers.dev) program, which can reverse proxy your TG channel preview page, and proxy images, CSS, JS and other resources together. Then you can easily embed the proxied web page into your own website. 12 | 13 | At the same time, you can also modify the CSS of the page and make some other customizations. 14 | 15 | ## how to use 16 | 17 | 1. Go to the [Cloudflare Dashboard](https://dash.cloudflare.com/sign-up/workers) to create a worker 18 | 19 | 2. Edit the Worker code online, copy and paste all the content of [program](./proxy.js) into the edit box (replace the original content) 20 | 21 | 3. Replace some constants at the beginning of the script with the values ​​you want, then save and deploy 22 | 23 | 4. Visit the domain name of .workers.dev, if there is no problem, you can embed this webpage into the webpage you want 24 | 25 | ## hint 26 | 27 | If you want to get a better display effect, the width of the embedded web page should not exceed 720px. 28 | -------------------------------------------------------------------------------- /Script/Clansty/proxy.js: -------------------------------------------------------------------------------- 1 | const USERNAME = 'thewantedcracker'; // Telegram username 2 | const BASE_URL = 'https://proxy.oshekher.workers.dev'; // Ensure the base URL is properly formatted 3 | const ICON = '' + 4 | '' + 5 | ``; 16 | const CHANNEL_URL = `https://t.me/s/${USERNAME}`; 17 | 18 | addEventListener('fetch', event => { 19 | event.respondWith(handleRequest(event.request).catch(error => { 20 | console.error('Error in handleRequest:', error); 21 | return new Response('Internal Server Error', { status: 500 }); 22 | })); 23 | }); 24 | 25 | async function replaceText(resp) { 26 | let ct = resp.headers.get('content-type'); 27 | if (!ct) return resp; 28 | ct = ct.toLowerCase(); 29 | if (!(ct.includes('text/html') || ct.includes('application/json'))) return resp; 30 | 31 | let text = await resp.text(); 32 | text = text.replace(//g, 33 | ``) 34 | .replace(//g, 35 | ``) 36 | .replace(//g, ICON) 37 | .replace(/https?:\/\/telegram\.org\//g, `${BASE_URL}/tgorg/`) 38 | .replace(/https?:\/\/cdn(\d)\.telesco\.pe\//g, `${BASE_URL}/ts/$1/`) 39 | .replace(/https?:\/\/t\.me\/[A-z0-9\_]{5,}\//g, `${BASE_URL}/`) 40 | .replace(/
to view and join the conversation<\/div>/g, "") 41 | .replace(/Download Telegram/g, "Join Channel"); 42 | 43 | return new Response(text, { 44 | headers: { "content-type": ct } 45 | }); 46 | } 47 | 48 | async function replaceTextForTgOrg(resp) { 49 | let ct = resp.headers.get('content-type'); 50 | if (!ct) return resp; 51 | ct = ct.toLowerCase(); 52 | if (!ct.includes('text/css')) return resp; 53 | 54 | let text = await resp.text(); 55 | text = text.replace(/url\(\//g, `url(${BASE_URL}/tgorg/`) 56 | .replace(/url\('\//g, `url('${BASE_URL}/tgorg/`); 57 | 58 | return new Response(text, { 59 | headers: { "content-type": ct } 60 | }); 61 | } 62 | 63 | async function handleRequest(request) { 64 | const u = new URL(request.url); 65 | const reg = /\/[0-9]*$/; 66 | 67 | // Statistics node 68 | if (u.pathname === '/v/') { 69 | return new Response('true', { 70 | headers: { "content-type": "application/json" } 71 | }); 72 | } 73 | 74 | // Home 75 | if (u.pathname === '/') { 76 | const req = new Request(CHANNEL_URL, { 77 | method: 'GET', 78 | }); 79 | const result = await fetch(req).catch(error => { 80 | console.error('Error fetching home page:', error); 81 | return new Response('Internal Server Error', { status: 500 }); 82 | }); 83 | return replaceText(result); 84 | } 85 | 86 | // Message location 87 | if (reg.test(u.pathname)) { 88 | const req = new Request(CHANNEL_URL + u.pathname, { 89 | method: 'GET', 90 | }); 91 | const result = await fetch(req).catch(error => { 92 | console.error('Error fetching message:', error); 93 | return new Response('Internal Server Error', { status: 500 }); 94 | }); 95 | return replaceText(result); 96 | } 97 | 98 | const pathParts = u.pathname.split('/').slice(1); 99 | const host = pathParts[0] || ''; 100 | const hostParam = pathParts[1] || ''; 101 | 102 | // Node of telegram.org 103 | if (host === 'tgorg') { 104 | const req = new Request(`https://telegram.org/${pathParts.slice(1).join('/')}`, { 105 | method: 'GET', 106 | }); 107 | const result = await fetch(req).catch(error => { 108 | console.error('Error fetching telegram.org:', error); 109 | return new Response('Internal Server Error', { status: 500 }); 110 | }); 111 | return replaceTextForTgOrg(result); 112 | } 113 | 114 | // Telescope node 115 | if (host === 'ts') { 116 | const req = new Request(`https://cdn${hostParam}.telesco.pe/${pathParts.slice(2).join('/')}`, { 117 | method: 'GET', 118 | }); 119 | const result = await fetch(req).catch(error => { 120 | console.error('Error fetching telescope:', error); 121 | return new Response('Internal Server Error', { status: 500 }); 122 | }); 123 | return result; 124 | } 125 | 126 | // Load more 127 | if (host === 's' && hostParam === USERNAME) { 128 | u.host = 't.me'; 129 | const req = new Request(u, { 130 | method: 'POST', 131 | headers: { 'X-Requested-With': 'XMLHttpRequest' } 132 | }); 133 | const result = await fetch(req).catch(error => { 134 | console.error('Error fetching load more:', error); 135 | return new Response('Internal Server Error', { status: 500 }); 136 | }); 137 | return replaceText(result); 138 | } 139 | 140 | return await fetch(new Request('https://proxy.oshekher.workers.dev', { 141 | method: request.method, 142 | headers: request.headers, 143 | body: request.body 144 | })).catch(error => { 145 | console.error('Error fetching default:', error); 146 | return new Response('Internal Server Error', { status: 500 }); 147 | }); 148 | } 149 | -------------------------------------------------------------------------------- /Script/KusakabeSi/README.md: -------------------------------------------------------------------------------- 1 | # Reverse Proxy for Cloudflare Worker 2 | A reverse proxy for Cloudflare Worker with some additional features: 3 | 1. Miltiple site in one worker 4 | 2. String replacement 5 | 3. Custom resource replacment 6 | 3. [cloudflare email-protection](https://support.cloudflare.com/hc/en-us/articles/200170016-What-is-Email-Address-Obfuscation-) bypass. 7 | 8 | ## Demo 9 | 1. https://wix.kskb.eu.org 10 | 1. https://proxy.oshekher.workers.dev 11 | 1. https://uwiki.kskb.eu.org 12 | 1. https://revdemo.kskb.eu.org 13 | 1. https://blog.kskb.eu.org 14 | 1. https://blog.wget.date 15 | 16 | 17 | ## How to use: 18 | 19 | Create a cloudflare worker 20 | Checkout my [worker.js](https://github.com/OshekharO/CF-REVERSE-PROXY/blob/main/Script/KusakabeSi/worker.js), copy and paste to your cloudflare worker. 21 | Then modify the `reverse ` section, fill the infomatoin based on my [reverse_demo.js](https://github.com/OshekharO/CF-REVERSE-PROXY/blob/main/Script/KusakabeSi/reverse_demo.js). 22 | 23 | ## code 24 | 25 | // Remove ads from scripts 26 | const scriptPattern = /)<[^<]*)*<\/script>/gi; 27 | html = html.replace(scriptPattern, (match, p1) => { 28 | if (match.includes("ads")) { 29 | return ""; 30 | } else { 31 | return match; 32 | } 33 | }); 34 | 35 | // Remove ads from iframes 36 | const iframePattern = /)<[^<]*)*<\/iframe>/gi; 37 | html = html.replace(iframePattern, (match, p1) => { 38 | if (match.includes("ads")) { 39 | return ""; 40 | } else { 41 | return match; 42 | } 43 | }); 44 | 45 | Need to be placed in response(req) 46 | -------------------------------------------------------------------------------- /Script/KusakabeSi/reverse_demo.js: -------------------------------------------------------------------------------- 1 | reverse = { 2 | "uwiki.kskb.eu.org": { // Domain of the cf worker 3 | "protocol": "https", // HTTP or HTTPS, protocol of the original site 4 | "host": "en.wikipedia.org", // Target domain 5 | "replace": { //Replace string for all json/html/text/javascript through this proxy 6 | "Wiki": "Uncyclo", 7 | }, 8 | "reverse": { // Additional reverse proxy for for custom resource, such as picture 9 | "/static/images/project-logos/enwiki.png": "https://images.uncyclomedia.co/uncyclopedia/en/b/bc/Wiki.png" 10 | }, 11 | "redirect": {} // 302 resirection 12 | }, 13 | "revdemo.kskb.eu.org": { 14 | "protocol": "https", 15 | "host": "www.example.com", 16 | "replace": { 17 | "Example": "Demo", 18 | "Domain": "Site", 19 | "domain": "site", 20 | "More": "Less", 21 | "https://www.iana.org/sites/example": "https://github.com/KusakabeSi/cf-revpxy" 22 | }, 23 | "reverse": {}, 24 | "redirect": {} 25 | }, 26 | "blog.kskb.eu.org": { 27 | "protocol": "https", 28 | "host": "www.kskb.eu.org", 29 | "replace": {}, 30 | "reverse": {}, 31 | "redirect": {} 32 | }, 33 | "blog.wget.date": { 34 | "protocol": "https", 35 | "host": "www.kskb.eu.org", 36 | "replace": {}, 37 | "reverse": {}, 38 | "redirect": {} 39 | }, 40 | "42status.kskb.eu.org": { 41 | "protocol": "https", 42 | "host": "stats.uptimerobot.com", 43 | "replace": { 44 | 'pageUrl=': 'pageUrl="https://42status.kskb.eu.org/jB082hYYXv";', 45 | }, 46 | "reverse": { 47 | "/": "/jB082hYYXv", 48 | }, 49 | "redirect": { 50 | "/assets/sounds/notification.mp3": "https://stats.uptimerobot.com/assets/sounds/notification.mp3", 51 | "/jB082hYYXv": "/" 52 | } 53 | }, 54 | "wix.kskb.eu.org": { 55 | "protocol": "https", 56 | "host": "kskbsi.wixsite.com", 57 | "replace": { 58 | 'id="WIX_ADS"': 'id="WIX_ADS" style="display:none"', 59 | }, 60 | "reverse": { 61 | "/": "/blog" 62 | }, 63 | "redirect": { 64 | 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Script/KusakabeSi/worker.js: -------------------------------------------------------------------------------- 1 | /* 2 | _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ 3 | ( ____ \( ____ \ ( ____ )( ____ \|\ /|( ____ \( ____ )( ____ \( ____ \ ( ____ )( ____ )( ___ )|\ /||\ /| 4 | | ( \/| ( \/ | ( )|| ( \/| ) ( || ( \/| ( )|| ( \/| ( \/ | ( )|| ( )|| ( ) |( \ / )( \ / ) 5 | | | | (__ | (____)|| (__ | | | || (__ | (____)|| (_____ | (__ | (____)|| (____)|| | | | \ (_) / \ (_) / 6 | | | | __) | __)| __) ( ( ) )| __) | __)(_____ )| __) | _____)| __)| | | | ) _ ( \ / 7 | | | | ( | (\ ( | ( \ \_/ / | ( | (\ ( ) || ( | ( | (\ ( | | | | / ( ) \ ) ( 8 | | (____/\| ) | ) \ \__| (____/\ \ / | (____/\| ) \ \__/\____) || (____/\ | ) | ) \ \__| (___) |( / \ ) | | 9 | (_______/|/ |/ \__/(_______/ \_/ (_______/|/ \__/\_______)(_______/ |/ |/ \__/(_______)|/ \| \_/ 10 | 11 | 12 | A CF-REVERSE-PROXY Script For Cloudflare Workers at https://github.com/OshekharO/CF-REVERSE-PROXY */ 13 | 14 | reverse = {} 15 | 16 | target = {} // Temporary variable, do not edit 17 | 18 | addEventListener("fetch", event => { 19 | var request = event.request 20 | var url = new URL(event.request.url); 21 | for (const [s_domain, s_target] of Object.entries(reverse)) { 22 | if (url.host.endsWith(s_domain)) { 23 | target = reverse[s_domain]; 24 | target.f_host = s_domain; 25 | break; 26 | } 27 | } 28 | 29 | if (target.f_host == undefined) { 30 | return event.respondWith(new Response("Not found", { 31 | status: 404, 32 | })); 33 | } 34 | 35 | url.protocol = target.protocol; 36 | url.host = target.host; 37 | 38 | if (url.pathname in target.redirect) { 39 | return event.respondWith(new Response("", { 40 | status: 302, 41 | headers: { 42 | "Location": target.redirect[url.pathname], 43 | } 44 | })); 45 | } 46 | 47 | if (url.pathname in target.reverse) { 48 | const reverse_target = target.reverse[url.pathname]; 49 | if (reverse_target.startsWith("http")) { 50 | url = new URL(reverse_target); 51 | } else { 52 | url.pathname = reverse_target; 53 | } 54 | } 55 | 56 | if (target.path_prefix) { 57 | url.pathname = target.path_prefix + url.pathname; 58 | } 59 | 60 | const modifiedRequest = new Request(url, { 61 | body: request.body, 62 | headers: request.headers, 63 | method: request.method 64 | }); 65 | event.passThroughOnException(); 66 | return event.respondWith(handleRequest(modifiedRequest)); 67 | }); 68 | 69 | function cfDecodeEmail(encodedString) { 70 | var email = "", 71 | r = parseInt(encodedString.substr(0, 2), 16), 72 | n, i; 73 | for (n = 2; encodedString.length - n; n += 2) { 74 | i = parseInt(encodedString.substr(n, 2), 16) ^ r; 75 | email += String.fromCharCode(i); 76 | } 77 | return email; 78 | } 79 | 80 | function cfEncodeEmail(email, key = 0) { 81 | var randomnumber = Math.floor(Math.random() * (99 - 11 + 1)) + 11; 82 | if (key == 0) { 83 | key = randomnumber; 84 | } 85 | let out = key.toString(16).padStart(2, "0"); 86 | for (const c of email) { 87 | out += (c.charCodeAt(0) ^ key).toString(16).padStart(2, "0"); 88 | } 89 | return out; 90 | } 91 | 92 | async function handleRequest(req) { 93 | try { 94 | var response = await fetch(req); 95 | 96 | let contype = response.headers.get("Content-Type"); 97 | if (contype != null && (contype.includes("json") || contype.includes("html") || contype.includes("text") || contype.includes("javascript"))) { 98 | var html = await response.text(); 99 | html = html.replace(/<\s*div\s+class\s*=\s*["']?\s*ads?\s*["']?\s*>.*?<\s*\/\s*div\s*>/ig, ""); 100 | let allemail = [...html.matchAll(new RegExp("data-cfemail=\"([a-z0-9]+)\"", "g"))].concat([...html.matchAll(new RegExp("email-protection#([a-z0-9]+)\"", "g"))]); 101 | let replace_add = {}; 102 | for (const [_, org_cf_email] of allemail) { 103 | let org_cf_email_decode = cfDecodeEmail(org_cf_email); 104 | for (const [rs, rd] of Object.entries(target.replace)) { 105 | org_cf_email_decode = org_cf_email_decode.replaceAll(rs, rd); 106 | } 107 | org_cf_email_decode = org_cf_email_decode.replaceAll(target.host, target.f_host); 108 | replace_add[org_cf_email] = cfEncodeEmail(org_cf_email_decode); 109 | } 110 | target.replace = { 111 | ...target.replace, 112 | ...replace_add 113 | }; 114 | target.html = html; 115 | 116 | // Single pass replacement 117 | const replaceRegex = new RegExp(Object.keys(target.replace).join('|'), 'g'); 118 | html = html.replace(replaceRegex, match => target.replace[match]); 119 | html = html.replaceAll(target.host, target.f_host); 120 | 121 | return new Response(html, { 122 | headers: new Headers(response.headers) 123 | }); 124 | } else { 125 | return response; 126 | } 127 | } catch (error) { 128 | console.error("Error handling request:", error); 129 | return new Response("Internal Server Error", { 130 | status: 500 131 | }); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Script/Mikotwa/README.md: -------------------------------------------------------------------------------- 1 | # Reverse-proxy-cf 2 | 3 | Turn your Cloudflare Worker into an HTTP online web proxy/mirror. 4 | 5 | > Warning! Use of this item is restricted by the laws and regulations of your location. It is your responsibility to ensure the compliant use of this program. This item is provided "as is" without any express or implied. The author is not responsible for any damages caused by the use of this project. 6 | 7 | ## What are the advantages 8 | - Flexible handling of resource/JS loading in web pages without missing content. 9 | - Multisite support. One node, many worlds. 10 | - Lightweight and easy to build. All you need is a free Cloudflare account. 11 | 12 | ## test example 13 | > The test instance is limited to only allow access to the following two domain names. You can build it yourself, and there is no limit to the instance you can build. 14 | 1. Reverse MDN: https://reverse-proxy-cf-mdn.lacknown.workers.dev/developer.mozilla.org 15 | 2. Reverse example.com: https://reverse-proxy-cf-mdn.lacknown.workers.dev/example.com 16 | 17 | ## how to use? 18 | Open index.js and modify the following: 19 | - ```WORKER_HOSTNAME```: your Worker domain name 20 | 21 | Then, paste the modified content onto the newly created Cloudflare Worker. Try it out and see the effect. 22 | 23 | ## Known limitations / to be improved 24 | - Some sites (such as Bing, Mediawiki, etc.) have abnormal reverse results. 25 | - Referer inversion is broken... 26 | - ~~Only one site can be reversed. ~~ Multisite is already supported. 27 | - ~~Web pages that depend on other CDN JS loading may be missing content (the relevant code is not perfect)~~ Partially fixed. 28 | - ... 29 | -------------------------------------------------------------------------------- /Script/Mikotwa/index.js: -------------------------------------------------------------------------------- 1 | /* A CF-REVERSE-PROXY Script For Cloudflare Workers at https://github.com/OshekharO/CF-REVERSE-PROXY */ 2 | 3 | const WORKER_HOSTNAME = "proxy.oshekher.workers.dev"; 4 | 5 | let real_hostname = null; 6 | let real_path = null; 7 | 8 | async function handleRequest(req) { 9 | let parsedUrl = new URL(req.url); 10 | let referer = req.headers.get("Referer"); 11 | 12 | // If there is a Referer from the node, modify to forward 13 | if (referer) { 14 | parsedUrl = new URL(referer); 15 | } 16 | 17 | // Intercept the real domain name and path 18 | let first_char_index = parsedUrl.href.indexOf(WORKER_HOSTNAME) + WORKER_HOSTNAME.length + 1; 19 | let second_char_index = parsedUrl.href.indexOf('/', first_char_index + 1); 20 | 21 | if (second_char_index === -1) { 22 | let attribute_index = parsedUrl.href.indexOf('?', first_char_index); 23 | if (attribute_index === -1) { // URL does not end with /, and no query string starting with ? 24 | real_hostname = parsedUrl.href.substring(first_char_index); 25 | real_path = ''; 26 | } else { // Contains ? query string 27 | real_hostname = parsedUrl.href.substring(first_char_index, attribute_index); 28 | real_path = parsedUrl.href.substring(attribute_index); 29 | } 30 | } else { // URL ends with ? / 31 | real_hostname = parsedUrl.href.substring(first_char_index, second_char_index); 32 | real_path = parsedUrl.href.substring(second_char_index); 33 | } 34 | 35 | console.log(real_hostname); 36 | console.log(real_path); 37 | 38 | const res = await fetch('https://' + real_hostname + real_path, { 39 | headers: { 40 | 'Referer': parsedUrl.origin + parsedUrl.pathname 41 | } 42 | }); 43 | 44 | // remove nosniff 45 | let clean_res = new Response(res.body, res); 46 | clean_res.headers.delete("x-content-type-options"); 47 | 48 | const Accept = req.headers.get("Accept") || ""; 49 | 50 | // If request header Accept contains text/css, do not pass to HTMLRewriter 51 | if (Accept.includes("text/css")) { 52 | const contentType = clean_res.headers.get("content-type") || ""; 53 | if (contentType.includes("text/javascript")) { 54 | let css_res = new Response(clean_res.body, clean_res); 55 | css_res.headers.set("content-type", contentType.replace("text/javascript", "text/css")); 56 | return css_res; 57 | } 58 | 59 | clean_res.headers.set("content-type", "text/css; charset=utf-8"); 60 | return clean_res; 61 | } 62 | 63 | return rewriter.transform(clean_res); 64 | } 65 | 66 | class AttributeRewriter { 67 | constructor(attributeName) { 68 | this.attributeName = attributeName; 69 | } 70 | 71 | element(element) { 72 | const attribute = element.getAttribute(this.attributeName); 73 | if (attribute) { 74 | console.log(`Rewriting ${this.attributeName} from ${attribute}`); 75 | if (attribute.startsWith('https://')) { 76 | element.setAttribute(this.attributeName, 'https://' + WORKER_HOSTNAME + '/' + real_hostname + attribute.substring(8)); 77 | } else if (attribute.startsWith('//')) { 78 | element.setAttribute(this.attributeName, '//' + WORKER_HOSTNAME + '/' + real_hostname + attribute.substring(2)); 79 | } else if (attribute.startsWith('/')) { 80 | element.setAttribute(this.attributeName, 'https://' + WORKER_HOSTNAME + '/' + real_hostname + attribute); 81 | } else if (!attribute.startsWith('http')) { 82 | element.setAttribute(this.attributeName, 'https://' + WORKER_HOSTNAME + '/' + real_hostname + '/' + attribute); 83 | } 84 | console.log(`Rewritten ${this.attributeName} to ${element.getAttribute(this.attributeName)}`); 85 | } 86 | } 87 | } 88 | 89 | const rewriter = new HTMLRewriter() 90 | .on("a", new AttributeRewriter("href")) 91 | .on("img", new AttributeRewriter("src")) 92 | .on("img", new AttributeRewriter("data-src")) 93 | .on("iframe", new AttributeRewriter("src")) 94 | .on("link", new AttributeRewriter("href")) 95 | .on("script", new AttributeRewriter("src")); 96 | 97 | addEventListener("fetch", event => { 98 | event.respondWith(handleRequest(event.request)); 99 | }); 100 | -------------------------------------------------------------------------------- /Script/viperadnan/README.md: -------------------------------------------------------------------------------- 1 | **Booster.js** is a speed and performance optimizier for your website, delivering fast web experiences to users. Built with Cloudflare Workers, it caches static assets on the high performance global network, applies optimizations to web pages, and guards your website from scrapers or malicious attacks. 2 | 3 | - Speed: Deliver your website with Cloudflare’s global network, which is milliseconds away from virtually every Internet user. 4 | - Network: Set up HTTP/2, TLS 1.3, HTTPS (Free SSL Certificate), and IPv6 for your website. 5 | - Optimization: Minify JavaScript codes, compress images, cache static assets. 6 | - Firewall: Block traffics from specific IP addresses, regions, or known scrapers. 7 | - Routes: Serve different webpages to visitors based on their region or devices. 8 | - Serverless: No virtual machines, no servers, and no containers to maintain. 9 | - Todo: Load balancer, HTMLRewriter, and advanced routing rules. 10 | 11 | ## Deploy manually 12 | 13 | 1. Navigate to [Cloudflare Workers](https://workers.cloudflare.com), register or sign in your Cloudflare account, and set custom subdomain for workers, and create a new Worker. 14 | 15 | 2. Customize [booster.js](https://github.com/OshekharO/CF-REVERSE-PROXY/blob/main/Script/viperadnan/booster.js), paste the code into Cloudflare online editor to replace the default one. 16 | 17 | 3. Change the name of your Worker, save and deploy the code. 18 | 19 | ### Bind to Custom Domain 20 | 21 | 1. Add your domain to Cloudflare. 22 | 23 | 2. Navigate to the dashboard, select 'Workers' page, and click on 'Add Route'. 24 | 25 | 3. Type `https:///*` in `Route` and select the Worker you've created. 26 | 27 | 4. Add a CNAME DNS record for your custom domain. Input the subdomain (Example: `@` or `www`) in the 'Name' field, input the **second level domain** of your workers (Example: `readme.workers.dev`) in the 'Target' field, and then set 'Proxy status' to 'Proxied'. 28 | 29 | ## Config 30 | 31 | [![Config](https://raw.githubusercontent.com/viperadnan-git/website-booster/master/.github/img/config.png)](https://github.com/discordiy/CF-REVERSE-PROXY) 32 | 33 | `basic` 34 | - `upstream`: Protocol, Domain, Port (Optional), Path (Optional). Example: `https://www.math.ucla.edu/~tao/` 35 | - `mobileRedirect`: Automatically redirect mobile device visitors to a mobile-optimized website. 36 | 37 | `firewall` 38 | - `blockedRegion`: Block visitors from specific regions. Full list of codes: [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) 39 | - `blockedIPAddress`: Block visitors from specific IP Address. 40 | - `scrapeShield`: Discover, detect, and deter content scraping. Reference: [Introducing ScrapeShield](https://blog.cloudflare.com/introducing-scrapeshield-discover-defend-dete/) 41 | 42 | `routes`: Map country/region codes to specific upstream. Full list of codes: [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) Example: 43 | 44 | ```js 45 | routes: { 46 | FR: 'https://www.google.fr/', 47 | CA: 'https://www.google.ca/' 48 | } 49 | ``` 50 | 51 | `optimization` 52 | - `cacheEverything`: Forces Cloudflare to cache the response for this request, regardless of the response headers. 53 | - `cacheTtl`: Forces Cloudflare to cache the response for this request with specific TTL, regardless of the response headers. 54 | - `mirage`: Detects screen size and connection speed to optimally deliver images for the current browser window. 55 | - `polish`: Automatically optimizes the images on your site. The possible values are `lossy`, `lossless` or `off`. Reference: [Introducing Polish](https://blog.cloudflare.com/introducing-polish-automatic-image-optimizati/) 56 | - `minify`: Removes unnecessary characters from JavaScript, CSS, and HTML files. 57 | -------------------------------------------------------------------------------- /Script/viperadnan/booster.js: -------------------------------------------------------------------------------- 1 | /* 2 | _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ 3 | ( ____ \( ____ \ ( ____ )( ____ \|\ /|( ____ \( ____ )( ____ \( ____ \ ( ____ )( ____ )( ___ )|\ /||\ /| 4 | | ( \/| ( \/ | ( )|| ( \/| ) ( || ( \/| ( )|| ( \/| ( \/ | ( )|| ( )|| ( ) |( \ / )( \ / ) 5 | | | | (__ | (____)|| (__ | | | || (__ | (____)|| (_____ | (__ | (____)|| (____)|| | | | \ (_) / \ (_) / 6 | | | | __) | __)| __) ( ( ) )| __) | __)(_____ )| __) | _____)| __)| | | | ) _ ( \ / 7 | | | | ( | (\ ( | ( \ \_/ / | ( | (\ ( ) || ( | ( | (\ ( | | | | / ( ) \ ) ( 8 | | (____/\| ) | ) \ \__| (____/\ \ / | (____/\| ) \ \__/\____) || (____/\ | ) | ) \ \__| (___) |( / \ ) | | 9 | (_______/|/ |/ \__/(_______/ \_/ (_______/|/ \__/\_______)(_______/ |/ |/ \__/(_______)|/ \| \_/ 10 | 11 | A CF-REVERSE-PROXY Script For Cloudflare Workers at https://github.com/OshekharO/CF-REVERSE-PROXY */ 12 | 13 | const config = { 14 | basic: { 15 | upstream: 'https://www.google.com/', 16 | mobileRedirect: 'https://www.google.com/' 17 | }, 18 | firewall: { 19 | blockedRegion: ['CN', 'KP', 'SY', 'PK', 'CU'], 20 | blockedIPAddress: [], 21 | scrapeShield: true 22 | }, 23 | routes: { 24 | CA: 'https://www.google.ca/', 25 | FR: 'https://www.google.fr/' 26 | }, 27 | optimization: { 28 | cacheEverything: false, 29 | cacheTtl: 5, 30 | mirage: true, 31 | polish: 'off', 32 | minify: { 33 | javascript: true, 34 | css: true, 35 | html: true 36 | } 37 | } 38 | }; 39 | 40 | function isMobile(userAgent) { 41 | const agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']; 42 | return agents.some(agent => userAgent.includes(agent)); 43 | } 44 | 45 | async function fetchAndApply(request) { 46 | const region = request.headers.get('cf-ipcountry') || ''; 47 | const ipAddress = request.headers.get('cf-connecting-ip') || ''; 48 | const userAgent = request.headers.get('user-agent') || ''; 49 | 50 | // Firewall checks 51 | if (config.firewall.blockedRegion.includes(region.toUpperCase())) { 52 | return new Response('Access denied: booster.js is not available in your region.', { status: 403 }); 53 | } 54 | 55 | if (config.firewall.blockedIPAddress.includes(ipAddress)) { 56 | return new Response('Access denied: Your IP address is blocked by booster.js.', { status: 403 }); 57 | } 58 | 59 | // Determine upstream URL 60 | let upstreamURL = new URL(config.basic.upstream); 61 | 62 | if (isMobile(userAgent)) { 63 | upstreamURL = new URL(config.basic.mobileRedirect); 64 | } else if (region.toUpperCase() in config.routes) { 65 | upstreamURL = new URL(config.routes[region.toUpperCase()]); 66 | } 67 | 68 | const requestURL = new URL(request.url); 69 | requestURL.protocol = upstreamURL.protocol; 70 | requestURL.host = upstreamURL.host; 71 | requestURL.pathname = upstreamURL.pathname + requestURL.pathname; 72 | 73 | // Create new request 74 | let newRequest; 75 | if (request.method === 'GET' || request.method === 'HEAD') { 76 | newRequest = new Request(requestURL, { 77 | cf: { 78 | cacheEverything: config.optimization.cacheEverything, 79 | cacheTtl: config.optimization.cacheTtl, 80 | mirage: config.optimization.mirage, 81 | polish: config.optimization.polish, 82 | minify: config.optimization.minify, 83 | scrapeShield: config.firewall.scrapeShield 84 | }, 85 | method: request.method, 86 | headers: request.headers 87 | }); 88 | } else { 89 | const requestBody = await request.text(); 90 | newRequest = new Request(requestURL, { 91 | cf: { 92 | cacheEverything: config.optimization.cacheEverything, 93 | cacheTtl: config.optimization.cacheTtl, 94 | mirage: config.optimization.mirage, 95 | polish: config.optimization.polish, 96 | minify: config.optimization.minify, 97 | scrapeShield: config.firewall.scrapeShield 98 | }, 99 | method: request.method, 100 | headers: request.headers, 101 | body: requestBody 102 | }); 103 | } 104 | 105 | try { 106 | const fetchedResponse = await fetch(newRequest); 107 | const modifiedResponseHeaders = new Headers(fetchedResponse.headers); 108 | 109 | if (modifiedResponseHeaders.has('x-pjax-url')) { 110 | const pjaxURL = new URL(modifiedResponseHeaders.get('x-pjax-url')); 111 | pjaxURL.protocol = requestURL.protocol; 112 | pjaxURL.host = requestURL.host; 113 | pjaxURL.pathname = pjaxURL.pathname.replace(requestURL.pathname, '/'); 114 | modifiedResponseHeaders.set('x-pjax-url', pjaxURL.href); 115 | } 116 | 117 | return new Response(fetchedResponse.body, { 118 | headers: modifiedResponseHeaders, 119 | status: fetchedResponse.status, 120 | statusText: fetchedResponse.statusText 121 | }); 122 | } catch (error) { 123 | return new Response('An error occurred while processing your request.', { status: 500 }); 124 | } 125 | } 126 | 127 | addEventListener('fetch', event => { 128 | event.respondWith(fetchAndApply(event.request)); 129 | }); 130 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/Examples/GitHub.com: -------------------------------------------------------------------------------- 1 | // Website you intended to retrieve for users. 2 | const upstream = 'github.com' 3 | 4 | // Custom pathname for the upstream website. 5 | const upstream_path = '/' 6 | 7 | // Website you intended to retrieve for users using mobile devices. 8 | const upstream_mobile = 'github.com' 9 | 10 | // Countries and regions where you wish to suspend your service. 11 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] 12 | 13 | // IP addresses which you wish to block from using your service. 14 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] 15 | 16 | // Whether to use HTTPS protocol for upstream address. 17 | const https = true 18 | 19 | // Whether to disable cache. 20 | const disable_cache = true 21 | 22 | // Replace texts. 23 | const replace_dict = { 24 | '$upstream': '$custom_domain' 25 | } 26 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/Examples/google.com: -------------------------------------------------------------------------------- 1 | // Website you intended to retrieve for users. 2 | const upstream = 'www.google.com' 3 | 4 | // Custom pathname for the upstream website. 5 | const upstream_path = '/' 6 | 7 | // Website you intended to retrieve for users using mobile devices. 8 | const upstream_mobile = 'www.google.com' 9 | 10 | // Countries and regions where you wish to suspend your service. 11 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] 12 | 13 | // IP addresses which you wish to block from using your service. 14 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] 15 | 16 | // Whether to use HTTPS protocol for upstream address. 17 | const https = true 18 | 19 | // Whether to disable cache. 20 | const disable_cache = false 21 | 22 | // Replace texts. 23 | const replace_dict = { 24 | '$upstream': '$custom_domain', 25 | '//google.com': '' 26 | } 27 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/Examples/nytimes.com: -------------------------------------------------------------------------------- 1 | // Website you intended to retrieve for users. 2 | const upstream = 'www.nytimes.com' 3 | 4 | // Custom pathname for the upstream website. 5 | const upstream_path = '/' 6 | 7 | // Website you intended to retrieve for users using mobile devices. 8 | const upstream_mobile = 'www.nytimes.com' 9 | 10 | // Countries and regions where you wish to suspend your service. 11 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] 12 | 13 | // IP addresses which you wish to block from using your service. 14 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] 15 | 16 | // Whether to use HTTPS protocol for upstream address. 17 | const https = true 18 | 19 | // Whether to disable cache. 20 | const disable_cache = false 21 | 22 | // Replace texts. 23 | const replace_dict = { 24 | '$upstream': '$custom_domain', 25 | "static01.nyt.com": "$custom_domain" 26 | } 27 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/Examples/pornhub.com: -------------------------------------------------------------------------------- 1 | // Website you intended to retrieve for users. 2 | const upstream = 'www.pornhub.com' 3 | 4 | // Custom pathname for the upstream website. 5 | const upstream_path = '/' 6 | 7 | // Website you intended to retrieve for users using mobile devices. 8 | const upstream_mobile = 'www.pornhub.com' 9 | 10 | // Countries and regions where you wish to suspend your service. 11 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] 12 | 13 | // IP addresses which you wish to block from using your service. 14 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] 15 | 16 | // Whether to use HTTPS protocol for upstream address. 17 | const https = true 18 | 19 | // Whether to disable cache. 20 | const disable_cache = false 21 | 22 | // Replace texts. 23 | const replace_dict = { 24 | '$upstream': '$custom_domain', 25 | '//ci.phncdn.com': '//ciphncdncom.pornproxy.workers.dev', // replace this with your other deployment. 26 | 'trafficjunky.com': '', 27 | 'trafficjunky.net': '', 28 | 'contentabc.com': '', 29 | 'Ads By Traffic Junky': '', 30 | 'cdn1d-static-shared.phncdn.com/iframe-1.1.5.html': '', 31 | '/ads/iframe-mobile-3.0.0.html': '', 32 | '': '-->', 34 | 'Remove Ads': '' 35 | } 36 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Workers-Proxy is a lightweight Javascript [Reverse Proxy](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/) based on [Cloudflare Workers](https://workers.cloudflare.com/). 4 | 5 | Users could deploy the reverse proxy on Cloudflare's global network without setting up virtual private servers and configuring Nginx or Apache. 6 | 7 | ### Features 8 | 9 | * Build mirror websites 10 | * Improve loading speed with Cloudflare's global network 11 | * Increase security (Hide IP addresses of websites) 12 | * Block specific areas or IP addresses 13 | * Redirect mobile users to different web pages 14 | 15 | ## Getting Started 16 | 17 | ### Build and Deploy 18 | 19 | #### Deploy manually 20 | 21 | 1. Navigate to [Cloudflare Workers](https://workers.cloudflare.com), register or sign in your Cloudflare account, and set custom subdomain for workers, and create a new Worker. 22 | 23 | 2. Customize '[src/index.js](https://github.com/OshekharO/CF-REVERSE-PROXY/blob/main/Script/xiaoyang-sde/index.js)', paste the code into Cloudflare online editor to replace the default one. 24 | 25 | 3. Change name of your Worker, save and deploy it, and check whether its performance fulfills your demand. 26 | 27 | ### Bind to Custom Domain 28 | 29 | 1. Check whether your domain is currently under Cloudflare's protection. 30 | 31 | 2. Navigate to the dashboard of your domain, select 'Workers' page, and click on 'Add Route'. 32 | 33 | 3. Type `https:///*` in `Route` and select the Worker you created previously. 34 | 35 | 4. Add a CNAME DNS record for your custom domain. Concretely, enter the subdomain (or '@' for root) in the 'Name' field, enter the **second level domain** of your workers in the 'Target' field, and set 'Proxy status' to 'Proxied'. 36 | 37 | ### Customize index.js 38 | 39 | Basically, there are a few constants on the top of the 'index.js' file. 40 | 41 | To customize your own Workers-Proxy Service, you should edit these constants according to your demands. 42 | 43 | ``` 44 | // Website you intended to retrieve for users. 45 | const upstream = 'www.google.com' 46 | 47 | // Custom pathname for the upstream website. 48 | const upstream_path = '/' 49 | 50 | // Website you intended to retrieve for users using mobile devices. 51 | const upstream_mobile = 'www.google.com' 52 | 53 | // Countries and regions where you wish to suspend your service. 54 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU'] 55 | 56 | // IP addresses which you wish to block from using your service. 57 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] 58 | 59 | // Whether to use HTTPS protocol for upstream address. 60 | const https = true 61 | 62 | // Whether to disable cache. 63 | const disable_cache = false 64 | 65 | // Replace texts. 66 | const replace_dict = { 67 | '$upstream': '$custom_domain', 68 | '//google.com': '' 69 | } 70 | ``` 71 | 72 | ### Websites with Multiple Domains 73 | 74 | If the website uses another domain name to serve static resources, users could deploy multiple Workers-Proxy and configure text replacement. 75 | 76 | 1. **www.google.com** serve static resources on **www.gstatic.com** 77 | 2. Deploy **Workers-Proxy A** to proxy **www.gstatic.com** 78 | 3. Deploy **Workers-Proxy B** to proxy **www.google.com** 79 | 4. Configure text replacement for **Workers-Proxy B**: 80 | ``` 81 | const replace_dict = { 82 | '$upstream': '$custom_domain', 83 | 'www.gstatic.com': '' 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /Script/xiaoyang-sde/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ 3 | ( ____ \( ____ \ ( ____ )( ____ \|\ /|( ____ \( ____ )( ____ \( ____ \ ( ____ )( ____ )( ___ )|\ /||\ /| 4 | | ( \/| ( \/ | ( )|| ( \/| ) ( || ( \/| ( )|| ( \/| ( \/ | ( )|| ( )|| ( ) |( \ / )( \ / ) 5 | | | | (__ | (____)|| (__ | | | || (__ | (____)|| (_____ | (__ | (____)|| (____)|| | | | \ (_) / \ (_) / 6 | | | | __) | __)| __) ( ( ) )| __) | __)(_____ )| __) | _____)| __)| | | | ) _ ( \ / 7 | | | | ( | (\ ( | ( \ \_/ / | ( | (\ ( ) || ( | ( | (\ ( | | | | / ( ) \ ) ( 8 | | (____/\| ) | ) \ \__| (____/\ \ / | (____/\| ) \ \__/\____) || (____/\ | ) | ) \ \__| (___) |( / \ ) | | 9 | (_______/|/ |/ \__/(_______/ \_/ (_______/|/ \__/\_______)(_______/ |/ |/ \__/(_______)|/ \| \_/ 10 | 11 | A CF-REVERSE-PROXY Script For Cloudflare Workers at https://github.com/OshekharO/CF-REVERSE-PROXY */ 12 | 13 | // Website you intended to retrieve for users. 14 | const upstream = 'uncoder.eu.org'; 15 | 16 | // Custom pathname for the upstream website. 17 | const upstream_path = '/'; 18 | 19 | // Website you intended to retrieve for users using mobile devices. 20 | const upstream_mobile = 'uncoder.eu.org'; 21 | 22 | // Countries and regions where you wish to suspend your service. 23 | const blocked_region = ['CN', 'KP', 'SY', 'PK', 'CU']; 24 | 25 | // IP addresses which you wish to block from using your service. 26 | const blocked_ip_address = ['0.0.0.0', '127.0.0.1']; 27 | 28 | // Whether to use HTTPS protocol for upstream address. 29 | const https = true; 30 | 31 | // Whether to disable cache. 32 | const disable_cache = true; 33 | 34 | // Replace texts. 35 | const replace_dict = { 36 | '$upstream': '$custom_domain', 37 | 'Premium': '' 38 | }; 39 | 40 | addEventListener('fetch', event => { 41 | event.respondWith(fetchAndApply(event.request)); 42 | }); 43 | 44 | async function fetchAndApply(request) { 45 | const region = request.headers.get('cf-ipcountry')?.toUpperCase(); 46 | const ip_address = request.headers.get('cf-connecting-ip'); 47 | const user_agent = request.headers.get('user-agent'); 48 | 49 | if (!region || !ip_address || !user_agent) { 50 | console.error('Missing required headers:', region, ip_address, user_agent); 51 | return new Response('Access denied: Missing required headers.', { status: 403 }); 52 | } 53 | 54 | let response = null; 55 | let url = new URL(request.url); 56 | let url_hostname = url.hostname; 57 | 58 | if (https) { 59 | url.protocol = 'https:'; 60 | } else { 61 | url.protocol = 'http:'; 62 | } 63 | 64 | const isDesktop = await device_status(user_agent); 65 | const upstream_domain = isDesktop ? upstream : upstream_mobile; 66 | 67 | url.host = upstream_domain; 68 | if (url.pathname === '/') { 69 | url.pathname = upstream_path; 70 | } else { 71 | url.pathname = upstream_path + url.pathname; 72 | } 73 | 74 | if (blocked_region.includes(region)) { 75 | console.error('Access denied for region:', region); 76 | response = new Response('Access denied: WorkersProxy is not available in your region yet.', { 77 | status: 403 78 | }); 79 | } else if (blocked_ip_address.includes(ip_address)) { 80 | console.error('Access denied for IP:', ip_address); 81 | response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', { 82 | status: 403 83 | }); 84 | } else { 85 | const method = request.method; 86 | const request_headers = request.headers; 87 | const new_request_headers = new Headers(request_headers); 88 | 89 | new_request_headers.set('Host', upstream_domain); 90 | new_request_headers.set('Referer', url.protocol + '//' + url_hostname); 91 | 92 | try { 93 | const original_response = await fetch(url.href, { 94 | method, 95 | headers: new_request_headers 96 | }); 97 | 98 | const response_headers = original_response.headers; 99 | const new_response_headers = new Headers(response_headers); 100 | const status = original_response.status; 101 | 102 | if (disable_cache) { 103 | new_response_headers.set('Cache-Control', 'no-store'); 104 | } 105 | 106 | new_response_headers.set('Access-Control-Allow-Origin', '*'); 107 | new_response_headers.set('Access-Control-Allow-Credentials', 'true'); 108 | new_response_headers.delete('Content-Security-Policy'); 109 | new_response_headers.delete('Content-Security-Policy-Report-Only'); 110 | new_response_headers.delete('Clear-Site-Data'); 111 | 112 | if (new_response_headers.get('X-Pjax-Url')) { 113 | new_response_headers.set('X-Pjax-Url', response_headers.get('X-Pjax-Url').replace('//' + upstream_domain, '//' + url_hostname)); 114 | } 115 | 116 | const content_type = new_response_headers.get('Content-Type'); 117 | let original_text = null; 118 | 119 | if (content_type && content_type.includes('text/html') && content_type.includes('UTF-8')) { 120 | console.log('Content type is text/html and UTF-8, applying text replacement.'); 121 | original_text = await replace_response_text(original_response, upstream_domain, url_hostname); 122 | console.log('Text after replacement:', original_text); 123 | } else { 124 | console.log('Content type is not text/html and UTF-8, not applying text replacement.'); 125 | original_text = await original_response.blob(); 126 | } 127 | 128 | response = new Response(original_text, { 129 | status, 130 | headers: new_response_headers 131 | }); 132 | } catch (error) { 133 | console.error('Error fetching upstream:', error); 134 | response = new Response('Internal server error', { status: 500 }); 135 | } 136 | } 137 | return response; 138 | } 139 | 140 | async function replace_response_text(response, upstream_domain, host_name) { 141 | const text = await response.text(); 142 | console.log('Original text:', text); 143 | 144 | let replaced_text = text; 145 | 146 | for (const [i, j] of Object.entries(replace_dict)) { 147 | let key = i; 148 | let value = j; 149 | 150 | if (key === '$upstream') { 151 | key = upstream_domain; 152 | } else if (key === '$custom_domain') { 153 | key = host_name; 154 | } 155 | 156 | if (value === '$upstream') { 157 | value = upstream_domain; 158 | } else if (value === '$custom_domain') { 159 | value = host_name; 160 | } 161 | 162 | const re = new RegExp(key, 'gi'); // Use 'gi' for case-insensitive and global replacement 163 | replaced_text = replaced_text.replace(re, value); 164 | } 165 | 166 | console.log('Replaced text:', replaced_text); 167 | return replaced_text; 168 | } 169 | 170 | async function device_status(user_agent_info) { 171 | const agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; 172 | return !agents.some(agent => user_agent_info.includes(agent)); 173 | } 174 | -------------------------------------------------------------------------------- /Script/ymyuuu/README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Workers Proxy 2 | 3 | 这是一个基于 Cloudflare Workers 的简单反向代理脚本,用于将客户端的请求转发到目标地址,并将目标地址的响应返回给客户端。在使用本脚本之前,请务必详细阅读以下安全注意事项和免责声明,以确保使用脚本时的安全和法律合规性。 4 | 5 | - 群聊: [HeroCore](https://t.me/HeroCore) 6 | - 频道: [HeroMsg](https://t.me/HeroMsg) 7 | 8 | ![image](https://github.com/user-attachments/assets/72b35862-16cc-4224-89e1-ad0419a7ac4e) 9 | 10 | 11 | ## 简介 12 | 13 | 这个 Cloudflare Workers 脚本充当了一个反向代理,它的主要功能是接收客户端的请求,并将请求代理到目标地址,然后将目标地址的响应返回给客户端。具体功能包括: 14 | 15 | - 代理客户端请求到目标地址。 16 | - 修改响应中的相对路径为绝对路径,以确保资源的正确加载。 17 | - 处理重定向并进行适当的修改,以保持资源路径的正确性。 18 | - 添加 CORS 头部,以允许跨域访问。 19 | 20 | ## 如何部署 21 | 22 | 以下是部署 Cloudflare Workers 反向代理脚本的详细步骤: 23 | 24 | 1. 注册 Cloudflare 账户:如果您尚未拥有 Cloudflare 账户,请在 [Cloudflare 官方网站](https://www.cloudflare.com/) 上注册一个账户。 25 | 26 | 2. 创建 Workers 脚本:登录到 Cloudflare 账户后,进入 "Workers" 部分,创建一个新的 Workers 脚本。 27 | 28 | 3. 复制[worker.js](worker.js):将提供的反向代理脚本粘贴到 Workers 编辑器中。 29 | 30 | 4. 保存并部署:保存脚本后,点击 "Deploy" 按钮,以部署您的 Workers 脚本。 31 | 32 | 5. 配置域名:在 Cloudflare 中,将您的域名与部署的 Workers 脚本关联。确保将流量路由到您的 Workers 脚本。 33 | 34 | 6. 测试:访问您的域名或者 Cloudflare Workers URL 会看到一个输入框,您可以在其中输入要代理的目标网站的 URL,然后点击 "进入代理" 按钮进行访问。 35 | 36 | ## 使用方法 37 | 38 | 要使用此反向代理访问其他网站,请按照以下步骤操作: 39 | 40 | 1. 发出请求:只需向您的 Cloudflare Workers URL 发出请求,将请求发送到目标网站。 41 | 42 | 示例请求:`https://your-worker-url.com/https://example.com/` 43 | 44 | 将 `your-worker-url.com` 替换为您的 Cloudflare Workers URL,`example.com` 替换为您要代理的目标网站的地址。 45 | 46 | 2. 处理重定向 47 | 48 | 反向代理脚本能够处理重定向并适当修改资源路径,以确保正确性。 49 | 50 | 3. 允许跨域请求 51 | 52 | 反向代理添加了 CORS(跨源资源共享)头部,以允许跨域请求。这意味着您可以在前端 JavaScript 代码中从不同域(不同域名)发起请求,而不会受到浏览器的跨域安全限制。 53 | 54 | 4. 用户友好界面 55 | 56 | 如果您未提供目标网站的 URL,此反向代理还提供了一个用户友好的界面。用户可以在此界面中输入目标网站的 URL,然后点击 "进入代理" 按钮,以便快速代理访问目标网站。 57 | 58 | ## 注意事项 59 | 60 | - 请确保部署的 Workers 脚本在部署时是有效的,并且有足够的资源来处理请求。 61 | 62 | - 请注意不要滥用该服务,确保只将它用于合法和合适的用途。 63 | 64 | ## 免责声明 65 | 66 | - **责任限制**:作者不对脚本可能导致的任何安全问题、数据损失、服务中断、法律纠纷或其他损害负责。使用此脚本需自行承担风险。 67 | 68 | - **不当使用**:使用者需了解,本脚本可能被用于非法活动或未经授权的访问。作者强烈反对和谴责任何不当使用脚本的行为,并鼓励合法合规的使用。 69 | 70 | - **合法性**:请确保遵守所有适用的法律、法规和政策,包括但不限于互联网使用政策、隐私法规和知识产权法。确保您拥有对目标地址的合法权限。 71 | 72 | - **自担风险**:使用此脚本需自行承担风险。作者和 Cloudflare 不对脚本的滥用、不当使用或导致的任何损害承担责任。 73 | 74 | **此免责声明针对非中国大陆地区用户,如在中国大陆地区使用,需遵守相关地区法律法规,且由使用者自行承担相应风险与责任。** 75 | 76 | 77 | ## 资源 78 | 79 | - [Cloudflare Workers 文档](https://developers.cloudflare.com/workers) 80 | - [Cloudflare Workers 设置](https://developers.cloudflare.com/workers/platform/settings) 81 | 82 | ## 许可证 83 | 84 | 本项目采用 MIT 许可证。详细信息请参阅 [LICENSE](LICENSE) 文件。 85 | 86 | 感谢您的使用!如果您对这个项目有任何改进或建议,也欢迎贡献代码或提出问题。 87 | -------------------------------------------------------------------------------- /Script/ymyuuu/worker.js: -------------------------------------------------------------------------------- 1 | addEventListener('fetch', event => { 2 | event.respondWith(handleRequest(event.request)); 3 | }); 4 | 5 | const ALLOWED_PROTOCOLS = ['http:', 'https:']; 6 | const BLACKLISTED_DOMAINS = ['example.com', 'another-blocked-site.com']; 7 | 8 | function isAllowedUrl(url) { 9 | try { 10 | const parsedUrl = new URL(url); 11 | 12 | if (!ALLOWED_PROTOCOLS.includes(parsedUrl.protocol)) { 13 | return { valid: false, error: 'Invalid protocol' }; 14 | } 15 | if (BLACKLISTED_DOMAINS.some(domain => 16 | parsedUrl.hostname.includes(domain))) { 17 | return { valid: false, error: 'Blacklisted domain' }; 18 | } 19 | return { valid: true, error: null }; 20 | } catch { 21 | return { valid: false, error: 'Invalid URL' }; 22 | } 23 | } 24 | 25 | async function handleRequest(request) { 26 | try { 27 | const url = new URL(request.url); 28 | if (url.pathname === "/") { 29 | return new Response(getRootHtml(), { 30 | headers: { 31 | 'Content-Type': 'text/html; charset=utf-8' 32 | } 33 | }); 34 | } 35 | 36 | let actualUrlStr = decodeURIComponent(url.pathname.replace("/", "")); 37 | 38 | actualUrlStr = ensureProtocol(actualUrlStr, url.protocol); 39 | 40 | actualUrlStr += url.search; 41 | 42 | const validation = isAllowedUrl(actualUrlStr); 43 | if (!validation.valid) { 44 | console.log(`Blocked request to ${actualUrlStr} due to ${validation.error}`); 45 | return jsonResponse({ 46 | error: `URL validation failed: ${validation.error}` 47 | }, 400); 48 | } 49 | 50 | const newHeaders = filterHeaders(request.headers, name => !name.startsWith('cf-')); 51 | 52 | const modifiedRequest = new Request(actualUrlStr, { 53 | headers: newHeaders, 54 | method: request.method, 55 | body: request.body, 56 | redirect: 'manual' 57 | }); 58 | 59 | const response = await fetch(modifiedRequest); 60 | let body = response.body; 61 | if ([301, 302, 303, 307, 308].includes(response.status)) { 62 | return handleRedirect(response); 63 | } else if (response.headers.get("Content-Type")?.includes("text/html")) { 64 | const clonedResponse = response.clone(); 65 | body = await handleHtmlContent(clonedResponse, url.protocol, url.host, actualUrlStr); 66 | } 67 | const modifiedResponse = new Response(body, { 68 | status: response.status, 69 | statusText: response.statusText, 70 | headers: response.headers 71 | }); 72 | setNoCacheHeaders(modifiedResponse.headers); 73 | setCorsHeaders(modifiedResponse.headers, request.headers.get('Origin')); 74 | return modifiedResponse; 75 | } catch (error) { 76 | console.error(`Error handling request to ${request.url}:`, error); 77 | return jsonResponse({ 78 | error: error.message 79 | }, 500); 80 | } 81 | } 82 | 83 | function ensureProtocol(url, defaultProtocol) { 84 | return url.startsWith("http://") || url.startsWith("https://") ? url : defaultProtocol + "//" + url; 85 | } 86 | 87 | function handleRedirect(response) { 88 | const location = new URL(response.headers.get('location')); 89 | const modifiedLocation = `/${encodeURIComponent(location.toString())}`; 90 | return new Response(response.body, { 91 | status: response.status, 92 | statusText: response.statusText, 93 | headers: { 94 | ...response.headers, 95 | 'Location': modifiedLocation 96 | } 97 | }); 98 | } 99 | 100 | async function handleHtmlContent(response, protocol, host, actualUrlStr) { 101 | const originalText = await response.text(); 102 | const regex = new RegExp('((href|src|action)=["\'])/(?!/)', 'g'); 103 | let modifiedText = replaceRelativePaths(originalText, protocol, host, new URL(actualUrlStr).origin); 104 | return modifiedText; 105 | } 106 | 107 | function replaceRelativePaths(text, protocol, host, origin) { 108 | const regex = new RegExp('((href|src|action)=["\'])/(?!/)', 'g'); 109 | return text.replace(regex, `$1${protocol}//${host}/${origin}/`); 110 | } 111 | 112 | function jsonResponse(data, status) { 113 | return new Response(JSON.stringify(data), { 114 | status: status, 115 | headers: { 116 | 'Content-Type': 'application/json; charset=utf-8' 117 | } 118 | }); 119 | } 120 | 121 | function filterHeaders(headers, filterFunc) { 122 | return new Headers([...headers].filter(([name]) => filterFunc(name))); 123 | } 124 | 125 | function setNoCacheHeaders(headers) { 126 | headers.set('Cache-Control', 'no-store'); 127 | } 128 | 129 | function setCorsHeaders(headers, origin) { 130 | if (origin) { 131 | headers.set('Access-Control-Allow-Origin', origin); 132 | } 133 | headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 134 | headers.set('Access-Control-Allow-Headers', '*'); 135 | } 136 | 137 | function handleCorsPreflight(request) { 138 | const headers = new Headers(); 139 | setCorsHeaders(headers, request.headers.get('Origin')); 140 | return new Response(null, { 141 | status: 204, 142 | headers: headers 143 | }); 144 | } 145 | 146 | function getRootHtml() { 147 | return ` 148 | 149 | 150 | 151 | 152 | Proxy Everything 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 198 | 199 | 200 |
201 |
202 |
203 |
204 |
205 |
206 | linkProxy Everything 207 |
208 |
209 | 210 | 211 |
212 | 213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 | 221 | 229 | 230 | `; 231 | } 232 | --------------------------------------------------------------------------------