diff --git a/packages/edge-preview-authenticated-proxy/src/index.ts b/packages/edge-preview-authenticated-proxy/src/index.ts index 828bb6d9a8b..99f2215ec5f 100644 --- a/packages/edge-preview-authenticated-proxy/src/index.ts +++ b/packages/edge-preview-authenticated-proxy/src/index.ts @@ -74,6 +74,19 @@ class PreviewRequestFailed extends HttpError { } } +class InvalidURL extends HttpError { + constructor(private readonly url: string) { + super("Invalid URL", 400, false); + } + get data() { + return { url: this.url }; + } +} + +function assertValidURL(maybeUrl: string) { + if (!URL.canParse(maybeUrl)) throw new InvalidURL(maybeUrl); +} + function switchRemote(url: URL, remote: string) { const workerUrl = new URL(url); const remoteUrl = new URL(remote); @@ -252,6 +265,9 @@ async function updatePreviewToken(url: URL, env: Env, ctx: ExecutionContext) { throw new TokenUpdateFailed(); } + assertValidURL(prewarmUrl); + assertValidURL(remote); + ctx.waitUntil( fetch(prewarmUrl, { method: "POST", @@ -296,6 +312,7 @@ async function handleTokenExchange(url: URL) { if (!exchangeUrl) { throw new NoExchangeUrl(); } + assertValidURL(exchangeUrl); const exchangeRes = await fetch(exchangeUrl); if (exchangeRes.status !== 200) { const exchange = new URL(exchangeUrl); diff --git a/packages/edge-preview-authenticated-proxy/tests/index.test.ts b/packages/edge-preview-authenticated-proxy/tests/index.test.ts index 2fe601286ce..615d68dc3d7 100644 --- a/packages/edge-preview-authenticated-proxy/tests/index.test.ts +++ b/packages/edge-preview-authenticated-proxy/tests/index.test.ts @@ -107,6 +107,16 @@ compatibility_date = "2023-01-01" ` ); }); + it("should reject invalid exchange_url", async () => { + const resp = await worker.fetch( + `https://preview.devprod.cloudflare.dev/exchange?exchange_url=not_an_exchange_url`, + { method: "POST" } + ); + expect(resp.status).toBe(400); + expect(await resp.text()).toMatchInlineSnapshot( + '"{\\"error\\":\\"Error\\",\\"message\\":\\"Invalid URL\\"}"' + ); + }); it("should allow tokens > 4096 bytes", async () => { // 4096 is the size limit for cookies const token = randomBytes(4096).toString("hex"); @@ -179,6 +189,28 @@ compatibility_date = "2023-01-01" .split(";")[0] .split("=")[1]; }); + it("should reject invalid prewarm url", async () => { + const resp = await worker.fetch( + `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=TEST_TOKEN&prewarm=not_a_prewarm_url&remote=${encodeURIComponent( + `http://127.0.0.1:${remote.port}` + )}&suffix=${encodeURIComponent("/hello?world")}` + ); + expect(resp.status).toBe(400); + expect(await resp.text()).toMatchInlineSnapshot( + '"{\\"error\\":\\"Error\\",\\"message\\":\\"Invalid URL\\"}"' + ); + }); + it("should reject invalid remote url", async () => { + const resp = await worker.fetch( + `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=TEST_TOKEN&prewarm=${encodeURIComponent( + `http://127.0.0.1:${remote.port}/prewarm` + )}&remote=not_a_remote_url&suffix=${encodeURIComponent("/hello?world")}` + ); + expect(resp.status).toBe(400); + expect(await resp.text()).toMatchInlineSnapshot( + '"{\\"error\\":\\"Error\\",\\"message\\":\\"Invalid URL\\"}"' + ); + }); it("should convert cookie to header", async () => { const resp = await worker.fetch(