Files
WorkRoot-WRNexusJSComponent/test/studio-origin.test.ts
T

81 lines
2.8 KiB
TypeScript

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" });
});