fix: initialize hosted Studio behind HTTPS reverse proxies
This commit is contained in:
1 parent
60467a4c05
commit
953e928b05
9 files changed
+186
-4
No files matched your search
@@ -0,0 +1,80 @@
|
||||
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" });
|
||||
});
|
||||
Reference in new issue
Block a user