import { expect, test } from "bun:test"; import { studioRequest } from "../app/lib/studio-origin.ts"; import { createContext } from "@wrnexus/core"; import designStudio from "../app/middleware/design-studio.ts"; const origin = "https://component.wrnexusjs.dev"; test("HTTPS browser module requests work behind an HTTP proxy without forwarded headers", async () => { const req = new Request( "http://component.wrnexusjs.dev/design-studio/studio.js", { headers: { origin } }, ); const normalized = studioRequest(req); expect(normalized).toBeInstanceOf(Request); expect((normalized as Request).url).toBe(origin + "/design-studio/studio.js"); const response = await designStudio( createContext(req, new URL(req.url)), () => new Response("wrong route", { status: 404 }), ); expect(response.status).toBe(200); expect(response.headers.get("content-type")).toContain("javascript"); }); test("proxy chains and internal Host values cannot break the canonical origin", () => { for (const proto of ["http", "https,http", "https, http", ""]) { const normalized = studioRequest( new Request("http://127.0.0.1:3000/design-studio/api/preview?page=1", { headers: { origin, "x-forwarded-proto": proto, "x-forwarded-host": "attacker.example", }, }), ) as Request; expect(normalized.url).toBe(origin + "/design-studio/api/preview?page=1"); expect(normalized.headers.get("x-forwarded-proto")).toBe("https"); } }); test("foreign and opaque origins remain rejected and local development keeps working", () => { for (const from of [ "https://attacker.example", "null", "http://component.wrnexusjs.dev", ]) { const response = studioRequest( new Request("http://component.wrnexusjs.dev/design-studio/api/generate", { headers: { origin: from }, }), ); expect((response as Response).status).toBe(403); } const local = "http://127.0.0.1:4320/design-studio/"; expect( ( studioRequest( new Request(local, { headers: { origin: "http://127.0.0.1:4320" } }), ) as Request ).url, ).toBe(local); expect(() => studioRequest(new Request(local), "https://example.org/path"), ).toThrow("HTTPS origin"); }); test("origin normalization preserves request bodies and configured custom domains", async () => { const req = new Request("http://internal:3000/design-studio/api/generate", { method: "POST", headers: { origin: "https://studio.example.org", "content-type": "application/json", }, body: '{"draft":"preserved"}', }); const normalized = studioRequest( req, "https://studio.example.org", ) as Request; expect(normalized.method).toBe("POST"); expect(await normalized.json()).toEqual({ draft: "preserved" }); });