import { describe, it, before, after } from "node:test"; import assert from "node:assert/strict"; import type { BackendDbInterface } from "../../src/db/types/DbInterface.js"; import { NotFoundAbodeError, NotAuthorizedAbodeError, ConflictAbodeError, } from "../../src/db/types/errors.js"; import { hashPassword } from "../../src/util/hash.js"; export function runAuthTests( name: string, getDb: () => Promise<{ db: BackendDbInterface; close(): void }>, createExpiredApikey?: (db: BackendDbInterface, uid: string) => Promise<`at_${string}`> ): void { describe(`${name}: auth`, async () => { let db: BackendDbInterface; let close: () => void; let email: string; const password = "auth-test-password"; before(async () => { ({ db, close } = await getDb()); email = `auth-user-${Date.now()}@test.example`; const pw = await hashPassword(password); await db.createUser({ email, name: "Auth User", password: pw, flags: {} }); }); after(() => close()); it("getUserByLogin returns user on correct credentials", async () => { const user = await db.getUserByLogin({ email, password }); assert.equal(user.email, email); assert.ok(!("password" in user)); }); it("getUserByLogin throws NotAuthorizedAbodeError for wrong password", async () => { await assert.rejects( () => db.getUserByLogin({ email, password: "wrong-password" }), (err) => { assert.ok(err instanceof NotAuthorizedAbodeError); return true; } ); }); it("getUserByLogin throws NotFoundAbodeError for unknown email", async () => { await assert.rejects( () => db.getUserByLogin({ email: "nobody@nowhere.example", password: "any", }), (err) => { assert.ok(err instanceof NotFoundAbodeError); return true; } ); }); it("getUserByLogin throws ConflictAbodeError for #unset password", async () => { const unsetEmail = `unset-${Date.now()}@test.example`; await db.createUser({ email: unsetEmail, name: "Unset User", password: "#unset", flags: {}, }); await assert.rejects( () => db.getUserByLogin({ email: unsetEmail, password: "any" }), (err) => { assert.ok(err instanceof ConflictAbodeError); return true; } ); }); }); describe(`${name}: auth apikey`, async () => { let db: BackendDbInterface; let close: () => void; let uid: string; before(async () => { ({ db, close } = await getDb()); const pw = await hashPassword("apikey-auth-password"); const user = await db.createUser({ email: `apikey-auth-${Date.now()}@test.example`, name: "Apikey Auth User", password: pw, flags: {}, }); uid = user.uid; }); after(() => close()); it("getUserByApikey returns [user, apikey] for valid token", async () => { const [, token] = await db.createApikey({ uid, name: "Auth Key", permissions: {}, }); const [user, apikey] = await db.getUserByApikey(token); assert.equal(user.uid, uid); assert.ok(apikey.kid); assert.equal(apikey.uid, uid); }); it("getUserByApikey throws NotAuthorizedAbodeError for expired key", async (t) => { if (!createExpiredApikey) { t.skip("createExpiredApikey helper not provided for this backend"); return; } const token = await createExpiredApikey(db, uid); await assert.rejects( () => db.getUserByApikey(token), (err) => { assert.ok(err instanceof NotAuthorizedAbodeError); return true; } ); }); it("getUserByApikey throws NotFoundAbodeError for unknown token", async () => { const fakeToken = `at_${"0".repeat(32)}` as `at_${string}`; await assert.rejects( () => db.getUserByApikey(fakeToken), (err) => { assert.ok(err instanceof NotFoundAbodeError); return true; } ); }); }); }