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>
18 lines
765 B
TypeScript
18 lines
765 B
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { validatePasswordStrength } from '@/modules/identity/auth/mapper/password-policy';
|
|
import { authConfig } from '@/config';
|
|
|
|
describe('validatePasswordStrength', () => {
|
|
it('rejects a password shorter than the configured minimum, naming the actual requirement', () => {
|
|
const tooShort = 'a'.repeat(authConfig.passwordMinLength - 1);
|
|
expect(() => validatePasswordStrength(tooShort)).toThrowError(
|
|
`Password must be at least ${authConfig.passwordMinLength} characters.`,
|
|
);
|
|
});
|
|
|
|
it('accepts a password meeting the configured minimum', () => {
|
|
const meetsPolicy = 'a'.repeat(authConfig.passwordMinLength);
|
|
expect(() => validatePasswordStrength(meetsPolicy)).not.toThrow();
|
|
});
|
|
});
|