admin-auth.test.js
3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Integration test for the minimal admin auth gate on /api/admin/*
// (dev-plan.md T6). Spawns server.js on a throwaway port, same isolation
// approach as uploads-route.test.js.
const test = require("node:test");
const assert = require("node:assert/strict");
const { spawn } = require("node:child_process");
const PORT = 19934 + Math.floor(Math.random() * 1000);
const BASE = `http://localhost:${PORT}`;
const ADMIN_PASSWORD = "test-password-only-for-this-run";
function waitForServer(url, timeoutMs = 10000) {
const deadline = Date.now() + timeoutMs;
return (async function poll() {
while (Date.now() < deadline) {
try {
await fetch(url);
return;
} catch {
await new Promise((r) => setTimeout(r, 100));
}
}
throw new Error("server did not come up in time");
})();
}
function sessionCookie(loginRes) {
const setCookie = loginRes.headers.get("set-cookie") || "";
return setCookie.split(";")[0];
}
let child;
test.before(async () => {
child = spawn(process.execPath, ["server.js"], {
cwd: __dirname,
env: { ...process.env, PORT: String(PORT), H3_CONSOLE_BASE: "", H3_CONSOLE_TOKEN: "", ADMIN_PASSWORD },
stdio: "pipe",
});
await waitForServer(BASE);
});
test.after(() => child.kill());
test("any /api/admin/* route returns 401 without a session cookie", async () => {
const res = await fetch(`${BASE}/api/admin/library`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: "x", videoUrl: "http://example.com/x.mp4" }),
});
assert.equal(res.status, 401);
});
test("logging in with the wrong password is rejected and sets no cookie", async () => {
const res = await fetch(`${BASE}/api/admin/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ password: "definitely-wrong" }),
});
assert.equal(res.status, 401);
assert.equal(res.headers.get("set-cookie"), null);
});
test("logging in with the right password grants a session that unlocks /api/admin/*, and logout revokes it", async () => {
const loginRes = await fetch(`${BASE}/api/admin/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ password: ADMIN_PASSWORD }),
});
assert.equal(loginRes.status, 200);
const cookie = sessionCookie(loginRes);
assert.match(cookie, /^admin_session=.+/);
const authedRes = await fetch(`${BASE}/api/admin/library`, {
method: "POST",
headers: { "Content-Type": "application/json", Cookie: cookie },
body: JSON.stringify({ prompt: "authed test entry", videoUrl: "http://example.com/x.mp4" }),
});
assert.equal(authedRes.status, 200);
const created = await authedRes.json();
// clean up the entry this test created in the real library.json
await fetch(`${BASE}/api/admin/library/${created.id}`, { method: "DELETE", headers: { Cookie: cookie } });
const logoutRes = await fetch(`${BASE}/api/admin/logout`, { method: "POST", headers: { Cookie: cookie } });
assert.equal(logoutRes.status, 200);
const afterLogout = await fetch(`${BASE}/api/admin/library`, {
method: "POST",
headers: { "Content-Type": "application/json", Cookie: cookie },
body: JSON.stringify({ prompt: "should be rejected", videoUrl: "http://example.com/x.mp4" }),
});
assert.equal(afterLogout.status, 401);
});