2026-04-24 14:15:55 +00:00
|
|
|
// @vitest-environment node
|
|
|
|
|
|
|
|
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
|
import worker, {
|
|
|
|
|
ADMIN_APP_SESSION_COOKIE,
|
|
|
|
|
buildAccessDeniedHtml,
|
|
|
|
|
createSignedAdminAppSession,
|
|
|
|
|
} from "./index";
|
|
|
|
|
|
|
|
|
|
const env = {
|
|
|
|
|
ADMIN_APP_ACCESS_TOKEN: "super-secret-admin-app-token",
|
|
|
|
|
ADMIN_APP_SESSION_SECRET: "worker-session-secret",
|
|
|
|
|
ASSETS: {
|
|
|
|
|
fetch: vi.fn(async () => new Response("<html>app</html>", { status: 200 })),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
describe("admin worker firewall", () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.clearAllMocks();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("serves the admin access gate when no session cookie is present", async () => {
|
|
|
|
|
const response = await worker.fetch(
|
2026-04-24 14:22:51 +00:00
|
|
|
new Request("https://admin-panel.xtablo.com/", {
|
2026-04-24 14:15:55 +00:00
|
|
|
headers: {
|
|
|
|
|
accept: "text/html",
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
env
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(response.status).toBe(401);
|
|
|
|
|
await expect(response.text()).resolves.toContain("Internal Admin Access");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("creates a signed app session cookie from a valid access token", async () => {
|
2026-04-24 14:22:51 +00:00
|
|
|
const request = new Request("https://admin-panel.xtablo.com/__admin/access", {
|
2026-04-24 14:15:55 +00:00
|
|
|
body: new URLSearchParams({ accessToken: env.ADMIN_APP_ACCESS_TOKEN }),
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
|
|
|
},
|
|
|
|
|
method: "POST",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const response = await worker.fetch(request, env);
|
|
|
|
|
|
|
|
|
|
expect(response.status).toBe(302);
|
2026-04-24 14:22:51 +00:00
|
|
|
expect(response.headers.get("location")).toBe("https://admin-panel.xtablo.com/");
|
2026-04-24 14:15:55 +00:00
|
|
|
expect(response.headers.get("set-cookie")).toContain(`${ADMIN_APP_SESSION_COOKIE}=`);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("allows authenticated requests through to static assets", async () => {
|
|
|
|
|
const session = await createSignedAdminAppSession(env.ADMIN_APP_SESSION_SECRET);
|
2026-04-24 14:22:51 +00:00
|
|
|
const request = new Request("https://admin-panel.xtablo.com/", {
|
2026-04-24 14:15:55 +00:00
|
|
|
headers: {
|
|
|
|
|
cookie: `${ADMIN_APP_SESSION_COOKIE}=${session}`,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const response = await worker.fetch(request, env);
|
|
|
|
|
|
|
|
|
|
expect(response.status).toBe(200);
|
|
|
|
|
expect(env.ASSETS.fetch).toHaveBeenCalledOnce();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("rejects invalid access tokens", async () => {
|
2026-04-24 14:22:51 +00:00
|
|
|
const request = new Request("https://admin-panel.xtablo.com/__admin/access", {
|
2026-04-24 14:15:55 +00:00
|
|
|
body: new URLSearchParams({ accessToken: "wrong-token" }),
|
|
|
|
|
headers: {
|
|
|
|
|
accept: "text/html",
|
|
|
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
|
|
|
},
|
|
|
|
|
method: "POST",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const response = await worker.fetch(request, env);
|
|
|
|
|
|
|
|
|
|
expect(response.status).toBe(401);
|
|
|
|
|
await expect(response.text()).resolves.toContain("Invalid app access token");
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("buildAccessDeniedHtml", () => {
|
|
|
|
|
it("renders the access error when provided", () => {
|
|
|
|
|
expect(buildAccessDeniedHtml("Bad token")).toContain("Bad token");
|
|
|
|
|
});
|
|
|
|
|
});
|