Files
support_backend/tests/helpers/auth.ts
T
saqib mirandClaude Sonnet 5 79bc2ef25b feat(013-auth-hardening): password reset, password strength policy, login rate-limiting
Closes the two gaps 010-identity-auth explicitly deferred (password reset,
login rate-limiting), plus a shared password-strength validator both the
reset-consume endpoint and admin account creation now depend on.

- Password reset: single-use, paired-Redis-key tokens (never in Postgres),
  identical response regardless of account existence, stubbed delivery via
  a structured log line (no email infrastructure exists yet).
- Password strength: one validatePasswordStrength() call site, wired into
  both POST /admin/users and the reset-consume flow.
- Login rate-limiting: checkRateLimit keyed by submitted email, checked
  before any credential verification.

Also fixes tests/helpers/auth.ts's shared loginAs() helper, which reused
two fixed accounts across the whole integration suite via upsert — now
rate-limited per email, that collided across ~30 files sharing one budget.
Each call now gets a unique email; no call sites needed to change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 21:22:49 +05:30

45 lines
1.6 KiB
TypeScript

import { randomUUID } from 'crypto';
import { FastifyInstance } from 'fastify';
import bcrypt from 'bcryptjs';
import { prismaClient } from '@/infrastructure/database';
const TEST_PASSWORD = 'Test-Password-123!';
/**
* 010-identity-auth made fastify.authenticate real — every test file calling a route already
* gated by it (across 002-009's own suites) needs a real session now. This creates its own
* throwaway admin/agent account directly and logs in as it, so callers don't depend on
* prisma/seed/roles.seed.ts having already been run against whatever database the suite
* connects to.
*
* 013-auth-hardening: the email is unique per call (not a fixed `test-admin@...` shared across
* every integration test file) because login is now rate-limited per email — dozens of files
* each calling this once in their own beforeAll would otherwise share one rate-limit bucket and
* trip it well before any file's own tests get to run.
*/
export async function loginAs(
app: FastifyInstance,
role: 'ADMIN' | 'AGENT' = 'ADMIN',
): Promise<string> {
const email = `test-${role.toLowerCase()}-${randomUUID()}@supporthub.test`;
await prismaClient.user.create({
data: {
email,
name: `Test ${role}`,
role,
passwordHash: await bcrypt.hash(TEST_PASSWORD, 10),
},
});
const response = await app.inject({
method: 'POST',
url: '/auth/login',
payload: { email, password: TEST_PASSWORD },
});
return response.json().data.token as string;
}
export function authHeader(token: string): { authorization: string } {
return { authorization: `Bearer ${token}` };
}