44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
/** Use an explicit external origin, rather than trusting proxy-supplied schemes. */
|
|
export function studioRequest(
|
|
request: Request,
|
|
publicOrigin = process.env.STUDIO_PUBLIC_ORIGIN ??
|
|
"https://component.wrnexusjs.dev",
|
|
): Request | Response {
|
|
const incoming = new URL(request.url);
|
|
const configured = new URL(publicOrigin);
|
|
if (
|
|
configured.protocol !== "https:" ||
|
|
configured.username ||
|
|
configured.password ||
|
|
configured.pathname !== "/" ||
|
|
configured.search ||
|
|
configured.hash
|
|
)
|
|
throw Error(
|
|
"STUDIO_PUBLIC_ORIGIN must be an HTTPS origin without a path or credentials.",
|
|
);
|
|
const origin = request.headers.get("origin");
|
|
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(
|
|
incoming.hostname,
|
|
);
|
|
const expected =
|
|
loopback && (!origin || origin === incoming.origin)
|
|
? incoming.origin
|
|
: configured.origin;
|
|
if (origin && origin !== expected)
|
|
return Response.json(
|
|
{ error: "Same-origin requests only." },
|
|
{ status: 403, headers: { "cache-control": "no-store" } },
|
|
);
|
|
const normalized = new Request(
|
|
new URL(incoming.pathname + incoming.search, expected),
|
|
request,
|
|
);
|
|
normalized.headers.set(
|
|
"x-forwarded-proto",
|
|
new URL(expected).protocol.slice(0, -1),
|
|
);
|
|
normalized.headers.set("host", new URL(expected).host);
|
|
return normalized;
|
|
}
|