81 lines
2.8 KiB
TypeScript
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" });
|
|
});
|