From 994909e9b1e3c4e41e8cf65bbf12747b56c2ab37 Mon Sep 17 00:00:00 2001 From: anthroposcene Date: Mon, 27 Apr 2026 16:32:13 -0700 Subject: [PATCH] add script/worker.js --- script/worker.js | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 script/worker.js diff --git a/script/worker.js b/script/worker.js new file mode 100644 index 0000000..fd92c99 --- /dev/null +++ b/script/worker.js @@ -0,0 +1,88 @@ +const WORKER_URL = "myworker.workers.dev"; + +export default { + async fetch(request) { + try { + if (request.headers.get("x-relay-hop") === "1") { + return json({ e: "loop detected" }, 508); + } + + const req = await request.json(); + + if (!req.u) { + return json({ e: "missing url" }, 400); + } + + const targetUrl = new URL(req.u); + + const BLOCKED_HOSTS = [ + WORKER_URL, + ]; + + if (BLOCKED_HOSTS.some(h => targetUrl.hostname.endsWith(h))) { + return json({ e: "self-fetch blocked" }, 400); + } + + const headers = new Headers(); + if (req.h && typeof req.h === "object") { + for (const [k, v] of Object.entries(req.h)) { + headers.set(k, v); + } + } + + headers.set("x-relay-hop", "1"); + + const fetchOptions = { + method: (req.m || "GET").toUpperCase(), + headers, + redirect: req.r === false ? "manual" : "follow" + }; + + if (req.b) { + const binary = Uint8Array.from(atob(req.b), c => c.charCodeAt(0)); + fetchOptions.body = binary; + } + + const resp = await fetch(targetUrl.toString(), fetchOptions); + + // Read response safely (no stack overflow) + const buffer = await resp.arrayBuffer(); + const uint8 = new Uint8Array(buffer); + + let binary = ""; + const chunkSize = 0x8000; // prevent call stack overflow + + for (let i = 0; i < uint8.length; i += chunkSize) { + binary += String.fromCharCode.apply( + null, + uint8.subarray(i, i + chunkSize) + ); + } + + const base64 = btoa(binary); + + const responseHeaders = {}; + resp.headers.forEach((v, k) => { + responseHeaders[k] = v; + }); + + return json({ + s: resp.status, + h: responseHeaders, + b: base64 + }); + + } catch (err) { + return json({ e: String(err) }, 500); + } + } +}; + +function json(obj, status = 200) { + return new Response(JSON.stringify(obj), { + status, + headers: { + "content-type": "application/json" + } + }); +}