somratpro commited on
Commit
d80a47a
·
1 Parent(s): be3c836

feat: add undici library patching support and improve URL parsing robustness in cloudflare proxy

Browse files
Files changed (2) hide show
  1. cloudflare-proxy-setup.py +9 -10
  2. cloudflare-proxy.js +114 -14
cloudflare-proxy-setup.py CHANGED
@@ -87,17 +87,16 @@ function isAllowedHost(hostname) {{
87
  async function handleRequest(request) {{
88
  const url = new URL(request.url);
89
  const targetHost = request.headers.get("x-target-host");
90
- if (PROXY_SHARED_SECRET) {
91
- const providedSecret = request.headers.get("x-proxy-key") || "";
92
- if (providedSecret !== PROXY_SHARED_SECRET) {
93
- if (url.pathname.startsWith("/bot") && !targetHost) {
94
- // Allowed fallback
95
- } else {
96
- return new Response("Unauthorized", { status: 401 });
97
- }
98
- }
99
- }
100
 
 
 
 
 
 
 
 
 
 
101
  }}
102
 
103
  let targetBase = "";
 
87
  async function handleRequest(request) {{
88
  const url = new URL(request.url);
89
  const targetHost = request.headers.get("x-target-host");
 
 
 
 
 
 
 
 
 
 
90
 
91
+ if (PROXY_SHARED_SECRET) {{
92
+ const providedSecret = request.headers.get("x-proxy-key") || "";
93
+ if (providedSecret !== PROXY_SHARED_SECRET) {{
94
+ if (url.pathname.startsWith("/bot") && !targetHost) {{
95
+ // Allowed fallback
96
+ }} else {{
97
+ return new Response("Unauthorized", {{ status: 401 }});
98
+ }}
99
+ }}
100
  }}
101
 
102
  let targetBase = "";
cloudflare-proxy.js CHANGED
@@ -1,8 +1,8 @@
1
  /**
2
  * Cloudflare Proxy: Transparent Fix for Blocked Domains
3
  *
4
- * Patches https.request/http.request/fetch to redirect traffic for blocked
5
- * hosts through a Cloudflare Worker proxy.
6
  */
7
  "use strict";
8
 
@@ -70,9 +70,14 @@ if (PROXY_URL) {
70
  let headers = {};
71
 
72
  if (typeof options === "string") {
73
- const parsed = new URL(options);
74
- hostname = parsed.hostname;
75
- path = parsed.pathname + parsed.search;
 
 
 
 
 
76
  } else if (options instanceof URL) {
77
  hostname = options.hostname;
78
  path = options.pathname + options.search;
@@ -175,15 +180,14 @@ if (PROXY_URL) {
175
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
176
 
177
  if (request) {
178
- return originalFetch(
179
- new Request(proxiedUrl, {
180
- method: request.method,
181
- headers,
182
- body: request.body,
183
- redirect: request.redirect,
184
- duplex: "half",
185
- }),
186
- );
187
  }
188
 
189
  return originalFetch(proxiedUrl, {
@@ -193,6 +197,102 @@ if (PROXY_URL) {
193
  };
194
  }
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  if (DEBUG) {
197
  log(`[cloudflare-proxy] Transparent proxy active in ${PROXY_ALL ? "wildcard" : "list"} mode`);
198
  log(`[cloudflare-proxy] Target proxy: ${proxy.hostname}`);
 
1
  /**
2
  * Cloudflare Proxy: Transparent Fix for Blocked Domains
3
  *
4
+ * Patches https.request/http.request/fetch and undici to redirect traffic
5
+ * for blocked hosts through a Cloudflare Worker proxy.
6
  */
7
  "use strict";
8
 
 
70
  let headers = {};
71
 
72
  if (typeof options === "string") {
73
+ try {
74
+ const parsed = new URL(options);
75
+ hostname = parsed.hostname;
76
+ path = parsed.pathname + parsed.search;
77
+ } catch (e) {
78
+ hostname = options.split('/')[0];
79
+ path = '/' + options.split('/').slice(1).join('/');
80
+ }
81
  } else if (options instanceof URL) {
82
  hostname = options.hostname;
83
  path = options.pathname + options.search;
 
180
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
181
 
182
  if (request) {
183
+ const newInit = {
184
+ method: request.method,
185
+ headers,
186
+ body: request.body,
187
+ redirect: request.redirect,
188
+ duplex: "half",
189
+ };
190
+ return originalFetch(new Request(proxiedUrl, newInit));
 
191
  }
192
 
193
  return originalFetch(proxiedUrl, {
 
197
  };
198
  }
199
 
200
+ // undici patching
201
+ const patchUndiciInstance = (exports) => {
202
+ if (!exports) return;
203
+
204
+ const patchDispatch = (proto, name) => {
205
+ if (proto && proto.dispatch && !proto.dispatch._patched) {
206
+ const origDispatch = proto.dispatch;
207
+ proto.dispatch = function(options, handler) {
208
+ let origin = options.origin || this.origin;
209
+ if (origin && typeof origin !== 'string') {
210
+ try { origin = origin.origin || origin.toString(); } catch (e) { origin = ""; }
211
+ }
212
+
213
+ let hostname = "";
214
+ try {
215
+ hostname = new URL(String(origin)).hostname;
216
+ } catch(e) {
217
+ hostname = String(origin || "").split(':')[0];
218
+ }
219
+
220
+ if (hostname && shouldProxyHost(hostname)) {
221
+ if (DEBUG) log(`[cloudflare-proxy] Redirecting undici ${name}.dispatch: ${hostname}${options.path || ""} -> ${proxy.hostname}`);
222
+
223
+ let headers = options.headers;
224
+ const targetHeader = "x-target-host";
225
+ const secretHeader = "x-proxy-key";
226
+
227
+ if (Array.isArray(headers)) {
228
+ let foundTarget = false;
229
+ for (let i = 0; i < headers.length; i += 2) {
230
+ if (String(headers[i]).toLowerCase() === targetHeader) {
231
+ foundTarget = true;
232
+ break;
233
+ }
234
+ }
235
+ if (!foundTarget) {
236
+ headers.push(targetHeader, hostname);
237
+ if (PROXY_SHARED_SECRET) headers.push(secretHeader, PROXY_SHARED_SECRET);
238
+ }
239
+ } else {
240
+ options.headers = headers || {};
241
+ if (options.headers instanceof Map || (typeof options.headers.set === 'function')) {
242
+ options.headers.set(targetHeader, hostname);
243
+ if (PROXY_SHARED_SECRET) options.headers.set(secretHeader, PROXY_SHARED_SECRET);
244
+ } else {
245
+ options.headers[targetHeader] = hostname;
246
+ if (PROXY_SHARED_SECRET) options.headers[secretHeader] = PROXY_SHARED_SECRET;
247
+ }
248
+ }
249
+ options.origin = `https://${proxy.hostname}`;
250
+ }
251
+ return origDispatch.call(this, options, handler);
252
+ };
253
+ proto.dispatch._patched = true;
254
+ }
255
+ };
256
+
257
+ for (const key in exports) {
258
+ if (exports[key] && exports[key].prototype && typeof exports[key].prototype.dispatch === 'function') {
259
+ patchDispatch(exports[key].prototype, key);
260
+ }
261
+ }
262
+
263
+ if (exports.getGlobalDispatcher) {
264
+ try {
265
+ const globalDispatcher = exports.getGlobalDispatcher();
266
+ if (globalDispatcher && globalDispatcher.dispatch && !globalDispatcher.dispatch._patched) {
267
+ patchDispatch(globalDispatcher, "GlobalDispatcherInstance");
268
+ }
269
+ } catch (e) {}
270
+ }
271
+
272
+ if (exports.fetch && !exports.fetch._patched) {
273
+ exports.fetch = async function (input, init) {
274
+ return globalThis.fetch(input, init);
275
+ };
276
+ exports.fetch._patched = true;
277
+ }
278
+ };
279
+
280
+ // Try to require undici immediately
281
+ try {
282
+ const undici = require("undici");
283
+ patchUndiciInstance(undici);
284
+ } catch (e) {}
285
+
286
+ const Module = require("module");
287
+ const originalRequire = Module.prototype.require;
288
+ Module.prototype.require = function (id) {
289
+ const exports = originalRequire.apply(this, arguments);
290
+ if (id === "undici" || id.includes("/undici/")) {
291
+ try { patchUndiciInstance(exports); } catch (e) {}
292
+ }
293
+ return exports;
294
+ };
295
+
296
  if (DEBUG) {
297
  log(`[cloudflare-proxy] Transparent proxy active in ${PROXY_ALL ? "wildcard" : "list"} mode`);
298
  log(`[cloudflare-proxy] Target proxy: ${proxy.hostname}`);