import { describe, expect, test } from "bun:test"; import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { createApp } from "../src/app"; import { openDb } from "../src/db"; import { loadOrCreateKey } from "../src/lib/crypto"; function makeApp() { const dir = mkdtempSync(join(tmpdir(), "helios-")); return createApp({ db: openDb(dir), key: loadOrCreateKey(dir) }); } const json = (body: unknown) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), }); describe("auth", () => { test("fresh instance needs setup; setup then login yields a session", async () => { const app = makeApp(); let me = await (await app.request("/api/me")).json(); expect(me).toEqual({ needsSetup: true, authenticated: false }); expect((await app.request("/api/setup", json({ password: "hunter2hunter2" }))).status).toBe(204); expect((await app.request("/api/setup", json({ password: "again-not-allowed" }))).status).toBe(400); const login = await app.request("/api/login", json({ password: "hunter2hunter2" })); expect(login.status).toBe(204); const cookie = login.headers.get("set-cookie")!; expect(cookie).toContain("helios_session="); expect(cookie).toContain("HttpOnly"); me = await (await app.request("/api/me", { headers: { cookie } })).json(); expect(me.authenticated).toBe(true); }); test("wrong password 401; protected route 401 without cookie", async () => { const app = makeApp(); await app.request("/api/setup", json({ password: "hunter2hunter2" })); expect((await app.request("/api/login", json({ password: "wrong-wrong-1" }))).status).toBe(401); expect((await app.request("/api/settings")).status).toBe(401); }); test("11th failed login from one IP is rate-limited", async () => { const app = makeApp(); await app.request("/api/setup", json({ password: "hunter2hunter2" })); const hdrs = { "content-type": "application/json", "x-forwarded-for": "10.9.8.7" }; let last = 0; for (let i = 0; i < 11; i++) { last = (await app.request("/api/login", { method: "POST", headers: hdrs, body: JSON.stringify({ password: "wrong-wrong-1" }) })).status; } expect(last).toBe(429); }); test("unknown /api/* returns 404 when authed, 401 when unauthed", async () => { const app = makeApp(); await app.request("/api/setup", json({ password: "hunter2hunter2" })); // Unauthed request to unknown endpoint returns 401 expect((await app.request("/api/nope")).status).toBe(401); // Authed request to unknown endpoint returns 404 const login = await app.request("/api/login", json({ password: "hunter2hunter2" })); const cookie = login.headers.get("set-cookie")!; const res = await app.request("/api/nope", { headers: { cookie } }); expect(res.status).toBe(404); expect(await res.json()).toEqual({ error: "not found" }); }); });