import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { getGameDb } from '@/lib/db/client'; import { createSession } from '@/lib/auth'; import { GET } from './route'; // v0.71.0 — admin guard + table list tests: no/expired session → 401, non-admin → 403, // admin passes and sees every user table (sqlite_% excluded). let dir: string; beforeAll(async () => { dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-admin-tables-')); process.env.FLIGHT_DB_PATH = path.join(dir, 'tables.db'); }); afterAll(async () => { delete process.env.FLIGHT_DB_PATH; await fs.rm(dir, { recursive: true, force: true }); }); const get = (sessionId?: string) => GET( new Request('http://localhost/api/admin/tables', { headers: sessionId ? { 'X-Flight-Session': sessionId } : undefined, }), ); async function makeUser(username: string, admin: number): Promise { const inst = await getGameDb(); const id = `user-${username}`; inst.raw.run( `INSERT INTO users (id, username, password_hash, admin, created_at) SELECT ?, ?, 'aa$bb', ?, ? WHERE NOT EXISTS (SELECT 1 FROM users WHERE id = ?)`, [id, username, admin, Date.now(), id], ); return id; } describe('GET /api/admin/tables', () => { it('returns 401 without a session header', async () => { const res = await get(); expect(res.status).toBe(401); }); it('returns 401 for an expired session', async () => { const inst = await getGameDb(); inst.raw.run('INSERT INTO sessions (id, user_id, expires_at) VALUES (?, ?, ?)', [ 'expired-admin-session', 'admin-kamilkrzywda', Date.now() - 1000, ]); const res = await get('expired-admin-session'); expect(res.status).toBe(401); }); it('returns 403 for a valid non-admin session', async () => { const userId = await makeUser('tables-nonadmin', 0); const sessionId = await createSession(await getGameDb(), userId); const res = await get(sessionId); expect(res.status).toBe(403); expect(((await res.json()) as { error: string }).error).toMatch(/admin/i); }); it('lists every user table for an admin, excluding sqlite_% internals', async () => { const sessionId = await createSession(await getGameDb(), 'admin-kamilkrzywda'); const res = await get(sessionId); expect(res.status).toBe(200); const names = ((await res.json()) as Array<{ name: string }>).map((t) => t.name); for (const expected of ['packages', 'players', 'planes', 'sessions', 'sim_state', 'users']) { expect(names, `missing ${expected}`).toContain(expected); } expect(names.some((n) => n.startsWith('sqlite_'))).toBe(false); // Name-ordered. expect([...names].sort()).toEqual(names); }); });