Files
Jyotisha/frontend/tests/admin-http-origin.test.ts
Jesse_Chen 99e2abe9bc
Staging Backend Quality Gate / validate (push) Successful in 19m41s
Staging Backend Quality Gate / publish (push) Successful in 28m13s
fix(admin): secure proxied model mutations
2026-08-08 01:38:50 +08:00

124 lines
3.8 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { isTrustedAdminMutationRequest } from "../src/lib/admin/auth-policy.ts";
const adminOrigin = "https://admin.staging.jyotisha.chat";
const userOrigin = "https://staging.jyotisha.chat";
function request(
url: string,
headers: HeadersInit,
): Request {
return new Request(url, { method: "POST", headers });
}
test("trusted proxy admin origin accepts the configured host and protocol", () => {
const proxied = request("http://admin.staging.jyotisha.chat/api/admin/models", {
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
"x-forwarded-proto": "https",
});
assert.equal(isTrustedAdminMutationRequest(proxied, adminOrigin), true);
});
test("configured admin origin rejects wrong browser origins", () => {
const proxied = request("http://admin.staging.jyotisha.chat/api/admin/models", {
origin: "https://evil.example",
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
"x-forwarded-proto": "https",
});
assert.equal(isTrustedAdminMutationRequest(proxied, adminOrigin), false);
});
test("ordinary staging host cannot call admin mutations", () => {
const userHost = request(`${userOrigin}/api/admin/models`, {
origin: userOrigin,
host: "staging.jyotisha.chat",
"x-forwarded-host": "staging.jyotisha.chat",
"x-forwarded-proto": "https",
});
const forgedForwardedHost = request(`${userOrigin}/api/admin/models`, {
origin: adminOrigin,
host: "staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
"x-forwarded-proto": "https",
});
assert.equal(isTrustedAdminMutationRequest(userHost, adminOrigin), false);
assert.equal(isTrustedAdminMutationRequest(forgedForwardedHost, adminOrigin), false);
});
test("malformed or ambiguous forwarded origins fail closed", () => {
const cases: HeadersInit[] = [
{
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat, evil.example",
"x-forwarded-proto": "https",
},
{
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
"x-forwarded-proto": "https, http",
},
{
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat/path",
"x-forwarded-proto": "https",
},
{
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "",
"x-forwarded-proto": "https",
},
{
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
},
];
for (const headers of cases) {
assert.equal(
isTrustedAdminMutationRequest(
request("http://admin.staging.jyotisha.chat/api/admin/models", headers),
adminOrigin,
),
false,
);
}
});
test("direct same-origin requests retain the legacy fallback when no admin origin is configured", () => {
const direct = request("https://admin.example/api/admin/models", {
origin: "https://admin.example",
});
assert.equal(isTrustedAdminMutationRequest(direct), true);
});
test("invalid configured admin origins fail closed", () => {
const proxied = request("http://admin.staging.jyotisha.chat/api/admin/models", {
origin: adminOrigin,
host: "admin.staging.jyotisha.chat",
"x-forwarded-host": "admin.staging.jyotisha.chat",
"x-forwarded-proto": "https",
});
for (const configured of [
"not-an-origin",
`${adminOrigin}/path`,
"ftp://admin.staging.jyotisha.chat",
"http://admin.staging.jyotisha.chat",
]) {
assert.equal(isTrustedAdminMutationRequest(proxied, configured), false);
}
});