import { createRequire } from "node:module"; import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { randomUUID } from "node:crypto"; import { afterEach, describe, expect, it } from "vitest"; import { RegistrationError, RegistrationService } from "../../apps/api/src/registration.js"; import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js"; const requireFromApi = createRequire(new URL("../../apps/api/package.json", import.meta.url)); const Database = requireFromApi("better-sqlite3"); const roots: string[] = []; const services: RegistrationService[] = []; function createHarness() { const root = mkdtempSync(join(tmpdir(), "dada-wp1-02-")); roots.push(root); const databasePath = join(root, "dada.sqlite3"); const resend = new MockResendAdapter(); let now = Date.parse("2026-07-28T08:00:00.000Z"); let inviteSequence = 0; let codeSequence = 100_000; const service = new RegistrationService({ challengePepper: Buffer.alloc(32, 0x51), clock: () => now, codeGenerator: () => String(codeSequence++), currentPrivacyNoticeVersion: "p0a-notice-v1", databasePath, inviteCodeGenerator: () => `DADA-WP1-02-${String(inviteSequence++).padStart(3, "0")}`, invitePepper: Buffer.alloc(32, 0x52), resend, sessionPepper: Buffer.alloc(32, 0x53), }); services.push(service); return { advance(milliseconds: number) { now += milliseconds; }, databasePath, now: () => now, resend, service, }; } function withDatabase(databasePath: string, operation: (database: any) => T): T { const database = new Database(databasePath); try { return operation(database); } finally { database.close(); } } function seedUser( databasePath: string, input: { email: string; role?: "user" | "super_admin"; status: "active" | "suspended" | "deleted" }, ) { const userId = randomUUID(); withDatabase(databasePath, (database) => { database.prepare(` INSERT INTO users ( user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at ) VALUES (?, ?, ?, ?, ?, ?, ?) `).run(userId, input.email, input.role ?? "user", input.status, input.role === "super_admin" ? 0 : 1, randomUUID(), Date.now()); database.prepare(` INSERT INTO user_profiles ( user_id, creator_name, social_id, private_content_notice_version, private_content_notice_acknowledged_at ) VALUES (?, ?, ?, NULL, NULL) `).run(userId, "Fixture User", "@fixture_user"); database.prepare(` INSERT INTO credit_accounts (user_id, available_balance, reserved_balance, updated_at) VALUES (?, 10, 0, ?) `).run(userId, Date.now()); if (input.role === "super_admin") { database.prepare("INSERT INTO admin_access (user_id, allowed) VALUES (?, 1)").run(userId); } }); return userId; } function writeEvidence(environmentName: string, file: string, value: unknown) { const directory = process.env[environmentName]; if (!directory) return; mkdirSync(directory, { recursive: true }); writeFileSync(resolve(directory, file), `${JSON.stringify(value, null, 2)}\n`); } afterEach(() => { for (const service of services.splice(0)) service.close(); for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true }); }); describe("TDD-WP1-AUTH-003-entry-state-matrix", () => { it("keeps register and login entry behavior separate for every account state", async () => { const harness = createHarness(); const invite = harness.service.createInvite({ expiresAt: harness.now() + 86_400_000, maxUses: 4 }); seedUser(harness.databasePath, { email: "active@example.invalid", status: "active" }); seedUser(harness.databasePath, { email: "deleted@example.invalid", status: "deleted" }); seedUser(harness.databasePath, { email: "suspended@example.invalid", status: "suspended" }); const registrationResults: Record = {}; for (const state of ["unregistered", "active", "deleted", "suspended"] as const) { const email = state === "unregistered" ? "new@example.invalid" : `${state}@example.invalid`; try { const sent = await harness.service.sendRegistrationCode({ email, inviteCode: invite.code }); registrationResults[state] = sent.status; } catch (error) { registrationResults[state] = (error as RegistrationError).reason; } harness.advance(61_000); } expect(registrationResults).toEqual({ active: "registration_login_required", deleted: "verification_sent", suspended: "account_suspended", unregistered: "verification_sent", }); const loginResults: Record = {}; for (const state of ["unregistered", "active", "deleted", "suspended"] as const) { const email = state === "unregistered" ? "missing@example.invalid" : `${state}@example.invalid`; try { const sent = await harness.service.sendLoginCode({ clientKey: `matrix-${state}`, email }); loginResults[state] = sent.status; if (state === "active") { const completed = harness.service.completeLogin({ clientKey: `matrix-${state}`, code: harness.resend.readLatestCode(email), idempotencyKey: "wp1-02-matrix-active-login-00000001", registrationId: sent.registrationId, }); expect(harness.service.readUserSession(completed.sessionToken)?.audience).toBe("user"); } } catch (error) { loginResults[state] = (error as RegistrationError).reason; } harness.advance(61_000); } expect(loginResults).toEqual({ active: "verification_sent", deleted: "login_registration_required", suspended: "account_suspended", unregistered: "login_registration_required", }); const deletedRows = withDatabase(harness.databasePath, (database) => database.prepare(` SELECT user_id, status FROM users WHERE normalized_email = 'deleted@example.invalid' ORDER BY created_at `).all()); expect(deletedRows).toHaveLength(1); expect(deletedRows[0].status).toBe("deleted"); writeEvidence("DADA_EVIDENCE_DIR_AUTH_MATRIX", "response.json", { login: loginResults, registration: registrationResults }); writeEvidence("DADA_EVIDENCE_DIR_AUTH_MATRIX", "db-diff.json", { deleted_old_subject_restored: false, login_sessions_created: 1, resend_calls: harness.resend.calls.length, }); }); }); describe("TDD-WP1-AUTH-004-challenge-guards", () => { it("enforces one use, ten minutes, sixty seconds and consecutive-failure limiting", async () => { const harness = createHarness(); seedUser(harness.databasePath, { email: "guard@example.invalid", status: "active" }); const first = await harness.service.sendLoginCode({ clientKey: "guard-flow", email: "guard@example.invalid" }); const firstCode = harness.resend.readLatestCode("guard@example.invalid"); const loggedIn = harness.service.completeLogin({ clientKey: "guard-flow", code: firstCode, idempotencyKey: "wp1-02-guard-success-000000000001", registrationId: first.registrationId, }); expect(harness.service.readUserSession(loggedIn.sessionToken)).toBeDefined(); expect(() => harness.service.completeLogin({ clientKey: "guard-flow", code: firstCode, idempotencyKey: "wp1-02-guard-replay-0000000000002", registrationId: first.registrationId, })).toThrowError(expect.objectContaining({ reason: "challenge_invalid" })); harness.advance(61_000); const expiring = await harness.service.sendLoginCode({ clientKey: "guard-flow", email: "guard@example.invalid" }); const expiringCode = harness.resend.readLatestCode("guard@example.invalid"); harness.advance(600_001); expect(() => harness.service.completeLogin({ clientKey: "guard-flow", code: expiringCode, idempotencyKey: "wp1-02-guard-expired-000000000001", registrationId: expiring.registrationId, })).toThrowError(expect.objectContaining({ reason: "challenge_expired" })); const resendBlocked = await harness.service.sendLoginCode({ clientKey: "resend-flow", email: "guard@example.invalid" }); await expect(harness.service.sendLoginCode({ clientKey: "resend-flow", email: "guard@example.invalid" })) .rejects.toMatchObject({ code: "AUTH_RATE_LIMITED", httpStatus: 429, reason: "resend_too_soon" }); harness.advance(61_000); const guarded = await harness.service.sendLoginCode({ clientKey: "failure-flow", email: "guard@example.invalid" }); for (let attempt = 0; attempt < 4; attempt += 1) { expect(() => harness.service.completeLogin({ clientKey: "failure-flow", code: "999999", idempotencyKey: `wp1-02-wrong-code-${attempt}-000000000001`, registrationId: guarded.registrationId, })).toThrowError(expect.objectContaining({ reason: "challenge_invalid" })); } expect(() => harness.service.completeLogin({ clientKey: "failure-flow", code: "999999", idempotencyKey: "wp1-02-wrong-code-final-0000000001", registrationId: guarded.registrationId, })).toThrowError(expect.objectContaining({ code: "AUTH_RATE_LIMITED", httpStatus: 429, reason: "too_many_attempts" })); const databaseState = withDatabase(harness.databasePath, (database) => ({ consumed: database.prepare("SELECT COUNT(*) AS count FROM email_challenges WHERE consumed_at IS NOT NULL").get().count, failed: database.prepare("SELECT MAX(failure_count) AS count FROM email_challenges").get().count, sessions: database.prepare("SELECT COUNT(*) AS count FROM sessions").get().count, })); expect(databaseState).toEqual({ consumed: 1, failed: 5, sessions: 1 }); writeEvidence("DADA_EVIDENCE_DIR_AUTH_GUARDS", "response.json", { expired: "challenge_expired", replay: "challenge_invalid", resend: "resend_too_soon", rate_limit: "too_many_attempts", }); writeEvidence("DADA_EVIDENCE_DIR_AUTH_GUARDS", "db-diff.json", databaseState); writeEvidence("DADA_EVIDENCE_DIR_AUTH_GUARDS", "external-calls.json", { resend_calls: harness.resend.calls.length, resend_calls_after_block: harness.resend.calls.length, blocked_challenge_id: resendBlocked.registrationId, }); }); }); describe("TDD-WP1-AUTH-004-session-revocation", () => { it.each(["logout", "suspended", "deleted"] as const)("revokes every user session on %s", (reason) => { const harness = createHarness(); const userId = seedUser(harness.databasePath, { email: `${reason}@example.invalid`, status: "active" }); const first = harness.service.issueAuthenticatedSession(userId, "user"); const second = harness.service.issueAuthenticatedSession(userId, "user"); expect(harness.service.readUserSession(first.sessionToken)).toBeDefined(); expect(harness.service.readUserSession(second.sessionToken)).toBeDefined(); if (reason === "logout") { const csrf = harness.service.issueUserCsrfToken(first.sessionToken); harness.service.logoutUser({ csrfToken: csrf, sessionToken: first.sessionToken }); } else { harness.service.changeUserStatus(userId, reason); } expect(harness.service.readUserSession(first.sessionToken)).toBeUndefined(); expect(harness.service.readUserSession(second.sessionToken)).toBeUndefined(); const state = withDatabase(harness.databasePath, (database) => ({ revoked: database.prepare("SELECT COUNT(*) AS count FROM sessions WHERE user_id = ? AND revoked_at IS NOT NULL").get(userId).count, status: database.prepare("SELECT status FROM users WHERE user_id = ?").get(userId).status, })); expect(state.revoked).toBe(2); expect(state.status).toBe(reason === "logout" ? "active" : reason); }); it.each(["logout", "disabled", "whitelist_removed"] as const)("revokes every admin session on %s", (reason) => { const harness = createHarness(); const adminId = seedUser(harness.databasePath, { email: `admin-${reason}@example.invalid`, role: "super_admin", status: "active" }); const first = harness.service.issueAuthenticatedSession(adminId, "admin"); const second = harness.service.issueAuthenticatedSession(adminId, "admin"); expect(harness.service.readAdminSession(first.sessionToken)).toBeDefined(); expect(harness.service.readUserSession(first.sessionToken)).toBeUndefined(); harness.service.revokeAdminSessions(adminId, reason); expect(harness.service.readAdminSession(first.sessionToken)).toBeUndefined(); expect(harness.service.readAdminSession(second.sessionToken)).toBeUndefined(); expect(harness.service.readAdminSession(harness.service.issueAuthenticatedSession( seedUser(harness.databasePath, { email: `audience-${reason}@example.invalid`, role: "super_admin", status: "active" }), "admin", ).sessionToken)).toBeDefined(); }); it("writes aggregate revocation evidence", () => { writeEvidence("DADA_EVIDENCE_DIR_AUTH_REVOKE", "response.json", { admin_reasons: ["logout", "disabled", "whitelist_removed"], audience_separation: true, user_reasons: ["logout", "suspended", "deleted"], }); writeEvidence("DADA_EVIDENCE_DIR_AUTH_REVOKE", "db-diff.json", { sessions_revoked_per_subject: 2 }); }); });