somratpro commited on
Commit
0afb9bd
·
1 Parent(s): ca16c55

feat: enable global wildcard proxying and enhance cloudflare-proxy with undici and fetch support

Browse files
Files changed (2) hide show
  1. cloudflare-proxy.js +115 -35
  2. start.sh +5 -3
cloudflare-proxy.js CHANGED
@@ -1,11 +1,14 @@
1
  /**
2
  * Cloudflare Proxy: Transparent Fix for Blocked Domains
3
  *
4
- * Patches https.request/http.request to redirect traffic for blocked hosts
5
- * through a Cloudflare Worker proxy.
6
  */
7
  "use strict";
8
 
 
 
 
9
  const https = require("https");
10
  const http = require("http");
11
 
@@ -18,10 +21,9 @@ if (
18
  PROXY_URL = `https://${PROXY_URL}`;
19
  }
20
 
21
- const DEBUG = process.env.CLOUDFLARE_PROXY_DEBUG === "true";
22
  const PROXY_SHARED_SECRET = (process.env.CLOUDFLARE_PROXY_SECRET || "").trim();
23
- // Default to wildcard mode so Google, WhatsApp, Telegram, Discord, and other
24
- // outbound integrations all work unless they are HF-internal hosts.
25
  const PROXY_DOMAINS = process.env.CLOUDFLARE_PROXY_DOMAINS || "*";
26
  const BLOCKED_DOMAINS = PROXY_DOMAINS.split(",")
27
  .map((domain) => domain.trim())
@@ -127,19 +129,29 @@ if (PROXY_URL) {
127
  https.request = patch(originalHttpsRequest, "https");
128
  http.request = patch(originalHttpRequest, "http");
129
 
 
130
  if (originalFetch) {
131
  globalThis.fetch = async function patchedFetch(input, init) {
132
  const request = input instanceof Request ? input : null;
133
- const url =
134
- request
135
- ? new URL(request.url)
136
- : input instanceof URL
137
- ? input
138
- : new URL(String(input));
 
 
139
 
140
  const hostname = url.hostname;
141
  const shouldProxy = shouldProxyHost(hostname);
142
- const headers = new Headers(request ? request.headers : init?.headers || {});
 
 
 
 
 
 
 
143
  const alreadyProxied =
144
  headers.has("x-target-host") || headers.has("X-Target-Host");
145
 
@@ -161,15 +173,14 @@ if (PROXY_URL) {
161
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
162
 
163
  if (request) {
164
- return originalFetch(
165
- new Request(proxiedUrl, {
166
- method: request.method,
167
- headers,
168
- body: request.body,
169
- redirect: request.redirect,
170
- duplex: "half",
171
- }),
172
- );
173
  }
174
 
175
  return originalFetch(proxiedUrl, {
@@ -179,23 +190,92 @@ if (PROXY_URL) {
179
  };
180
  }
181
 
182
- if (DEBUG) {
183
- if (PROXY_ALL) {
184
- console.log(
185
- "[cloudflare-proxy] Transparent proxy active in wildcard mode",
186
- );
187
- } else {
188
- console.log(
189
- `[cloudflare-proxy] Transparent proxy active for: ${BLOCKED_DOMAINS.join(", ")}`,
190
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
 
 
 
 
192
  console.log(`[cloudflare-proxy] Target proxy: ${proxy.hostname}`);
 
193
  }
194
  } catch (error) {
195
- if (DEBUG) {
196
- console.error(
197
- `[cloudflare-proxy] Failed to initialize: ${error.message}`,
198
- );
199
- }
200
  }
201
  }
 
 
1
  /**
2
  * Cloudflare Proxy: Transparent Fix for Blocked Domains
3
  *
4
+ * Patches https.request/http.request and undici/fetch to redirect traffic
5
+ * for blocked hosts through a Cloudflare Worker proxy.
6
  */
7
  "use strict";
8
 
9
+ // Always log that we are loaded
10
+ console.log("🦞 Cloudflare Proxy: Transparent redirector active");
11
+
12
  const https = require("https");
13
  const http = require("http");
14
 
 
21
  PROXY_URL = `https://${PROXY_URL}`;
22
  }
23
 
24
+ const DEBUG = process.env.CLOUDFLARE_PROXY_DEBUG === "true" || true;
25
  const PROXY_SHARED_SECRET = (process.env.CLOUDFLARE_PROXY_SECRET || "").trim();
26
+ // Default to wildcard mode to ensure all blocked external traffic is caught
 
27
  const PROXY_DOMAINS = process.env.CLOUDFLARE_PROXY_DOMAINS || "*";
28
  const BLOCKED_DOMAINS = PROXY_DOMAINS.split(",")
29
  .map((domain) => domain.trim())
 
129
  https.request = patch(originalHttpsRequest, "https");
130
  http.request = patch(originalHttpRequest, "http");
131
 
132
+ // Patch global fetch
133
  if (originalFetch) {
134
  globalThis.fetch = async function patchedFetch(input, init) {
135
  const request = input instanceof Request ? input : null;
136
+ const urlStr = request ? request.url : String(input);
137
+
138
+ let url;
139
+ try {
140
+ url = new URL(urlStr);
141
+ } catch (e) {
142
+ return originalFetch(input, init);
143
+ }
144
 
145
  const hostname = url.hostname;
146
  const shouldProxy = shouldProxyHost(hostname);
147
+
148
+ let headers;
149
+ if (request) {
150
+ headers = new Headers(request.headers);
151
+ } else {
152
+ headers = new Headers(init?.headers || {});
153
+ }
154
+
155
  const alreadyProxied =
156
  headers.has("x-target-host") || headers.has("X-Target-Host");
157
 
 
173
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
174
 
175
  if (request) {
176
+ const newInit = {
177
+ method: request.method,
178
+ headers,
179
+ body: request.body,
180
+ redirect: request.redirect,
181
+ duplex: "half",
182
+ };
183
+ return originalFetch(new Request(proxiedUrl, newInit));
 
184
  }
185
 
186
  return originalFetch(proxiedUrl, {
 
190
  };
191
  }
192
 
193
+ // Comprehensive undici patching via require interception
194
+ const Module = require("module");
195
+ const originalRequire = Module.prototype.require;
196
+ Module.prototype.require = function (id) {
197
+ const exports = originalRequire.apply(this, arguments);
198
+ if (id === "undici" || id.endsWith("/undici/index.js") || id.endsWith("/undici/lib/index.js")) {
199
+ // Patch undici.fetch
200
+ if (exports.fetch && !exports.fetch._patched) {
201
+ const origUndiciFetch = exports.fetch;
202
+ exports.fetch = async function (input, init) {
203
+ return globalThis.fetch(input, init);
204
+ };
205
+ exports.fetch._patched = true;
206
+ if (DEBUG) console.log("[cloudflare-proxy] Patched undici.fetch");
207
+ }
208
+
209
+ // Patch undici.request
210
+ if (exports.request && !exports.request._patched) {
211
+ const origUndiciRequest = exports.request;
212
+ exports.request = async function(url, options) {
213
+ let parsedUrl;
214
+ try {
215
+ parsedUrl = new URL(url);
216
+ } catch(e) {
217
+ return origUndiciRequest.apply(this, arguments);
218
+ }
219
+
220
+ if (shouldProxyHost(parsedUrl.hostname)) {
221
+ if (DEBUG) console.log(`[cloudflare-proxy] Redirecting undici.request://${parsedUrl.hostname} -> ${proxy.hostname}`);
222
+ const headers = options?.headers || {};
223
+ headers["x-target-host"] = parsedUrl.hostname;
224
+ if (PROXY_SHARED_SECRET) headers["x-proxy-key"] = PROXY_SHARED_SECRET;
225
+
226
+ const proxiedUrl = new URL(parsedUrl.pathname + parsedUrl.search, proxy);
227
+ return origUndiciRequest.call(this, proxiedUrl, {
228
+ ...options,
229
+ headers
230
+ });
231
+ }
232
+ return origUndiciRequest.apply(this, arguments);
233
+ };
234
+ exports.request._patched = true;
235
+ if (DEBUG) console.log("[cloudflare-proxy] Patched undici.request");
236
+ }
237
+
238
+ // Patch undici.Dispatcher to catch low-level calls (Pool, Client, etc.)
239
+ if (exports.Dispatcher && exports.Dispatcher.prototype.dispatch && !exports.Dispatcher.prototype.dispatch._patched) {
240
+ const origDispatch = exports.Dispatcher.prototype.dispatch;
241
+ exports.Dispatcher.prototype.dispatch = function(options, handler) {
242
+ const origin = options.origin ? String(options.origin) : "";
243
+ let hostname = "";
244
+ try {
245
+ hostname = new URL(origin).hostname;
246
+ } catch(e) {
247
+ hostname = origin.split(':')[0];
248
+ }
249
+
250
+ if (shouldProxyHost(hostname)) {
251
+ if (DEBUG) console.log(`[cloudflare-proxy] Redirecting undici dispatch: ${hostname}${options.path} -> ${proxy.hostname}`);
252
+
253
+ if (Array.isArray(options.headers)) {
254
+ options.headers.push("x-target-host", hostname);
255
+ if (PROXY_SHARED_SECRET) options.headers.push("x-proxy-key", PROXY_SHARED_SECRET);
256
+ } else {
257
+ options.headers = options.headers || {};
258
+ options.headers["x-target-host"] = hostname;
259
+ if (PROXY_SHARED_SECRET) options.headers["x-proxy-key"] = PROXY_SHARED_SECRET;
260
+ }
261
+
262
+ options.origin = `https://${proxy.hostname}`;
263
+ }
264
+ return origDispatch.call(this, options, handler);
265
+ };
266
+ exports.Dispatcher.prototype.dispatch._patched = true;
267
+ if (DEBUG) console.log("[cloudflare-proxy] Patched undici.Dispatcher.prototype.dispatch");
268
+ }
269
  }
270
+ return exports;
271
+ };
272
+
273
+ if (DEBUG) {
274
  console.log(`[cloudflare-proxy] Target proxy: ${proxy.hostname}`);
275
+ console.log(`[cloudflare-proxy] Proxying: ${PROXY_ALL ? "ALL (except internal)" : BLOCKED_DOMAINS.join(", ")}`);
276
  }
277
  } catch (error) {
278
+ console.error(`[cloudflare-proxy] Failed to initialize: ${error.message}`);
 
 
 
 
279
  }
280
  }
281
+
start.sh CHANGED
@@ -157,11 +157,13 @@ CLOUDFLARE_WORKERS_TOKEN="${CLOUDFLARE_WORKERS_TOKEN:-${CLOUDFLARE_API_TOKEN:-}}
157
  export CLOUDFLARE_WORKERS_TOKEN
158
  CF_PROXY_ENV_FILE="/tmp/huggingclaw-cloudflare-proxy.env"
159
  if [ -n "${CLOUDFLARE_WORKERS_TOKEN:-}" ] || [ -n "${CLOUDFLARE_PROXY_URL:-}" ]; then
160
- export CLOUDFLARE_PROXY_DOMAINS="${CLOUDFLARE_PROXY_DOMAINS:-api.telegram.org,web.whatsapp.com}"
 
161
  echo "☁️ Preparing Cloudflare outbound proxy..."
162
  python3 /home/node/app/cloudflare-proxy-setup.py || true
163
  if [ -f "$CF_PROXY_ENV_FILE" ]; then
164
  . "$CF_PROXY_ENV_FILE"
 
165
  fi
166
  fi
167
 
@@ -360,8 +362,8 @@ if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
360
  | .channels.telegram.botToken = $token
361
  | .channels.telegram.commands.native = false
362
  | .channels.telegram.timeoutSeconds = 60
363
- | .channels.telegram.network.autoSelectFamily = false
364
- | .channels.telegram.network.dnsResultOrder = "ipv4first"
365
  | .channels.telegram.retry = {
366
  "attempts": 5,
367
  "minDelayMs": 800,
 
157
  export CLOUDFLARE_WORKERS_TOKEN
158
  CF_PROXY_ENV_FILE="/tmp/huggingclaw-cloudflare-proxy.env"
159
  if [ -n "${CLOUDFLARE_WORKERS_TOKEN:-}" ] || [ -n "${CLOUDFLARE_PROXY_URL:-}" ]; then
160
+ export CLOUDFLARE_PROXY_DOMAINS="${CLOUDFLARE_PROXY_DOMAINS:-*}"
161
+ export CLOUDFLARE_PROXY_DEBUG="${CLOUDFLARE_PROXY_DEBUG:-true}"
162
  echo "☁️ Preparing Cloudflare outbound proxy..."
163
  python3 /home/node/app/cloudflare-proxy-setup.py || true
164
  if [ -f "$CF_PROXY_ENV_FILE" ]; then
165
  . "$CF_PROXY_ENV_FILE"
166
+ echo " ✅ Proxy environment loaded: ${CLOUDFLARE_PROXY_URL:-none}"
167
  fi
168
  fi
169
 
 
362
  | .channels.telegram.botToken = $token
363
  | .channels.telegram.commands.native = false
364
  | .channels.telegram.timeoutSeconds = 60
365
+ # | .channels.telegram.network.autoSelectFamily = false
366
+ # | .channels.telegram.network.dnsResultOrder = "ipv4first"
367
  | .channels.telegram.retry = {
368
  "attempts": 5,
369
  "minDelayMs": 800,