feat(identity): F-005 register/login/logout with argon2 sessions and rate limiting
- Hexagonal identity module: domain ports, use cases, argon2id hasher, pg repos - Migration 002_identity: identity_users + identity_sessions (token hash only) - Opaque 512-bit session tokens; DB stores SHA-256 hash; 7-day TTL in SQL - Cookie HttpOnly + Secure (COOKIE_SECURE, default true) + SameSite=Lax - LoginRateLimiter: 10 failures -> 429 + Retry-After, 15-min cooldown - Anti-enumeration: identical generic 401 + dummy-hash timing equalization - buildApp gains optional pool/cookieSecure; foundation-only app preserved - 47 unit + 14 integration tests; live smoke covers all acceptance criteria
This commit is contained in:
@@ -7,7 +7,9 @@ import { performance } from 'node:perf_hooks';
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import type { FastifyError, FastifyReply, FastifyRequest } from 'fastify';
|
||||
import type { IncomingMessage } from 'node:http';
|
||||
import type pg from 'pg';
|
||||
import { registerHealthRoutes } from '../modules/health/index.js';
|
||||
import { registerIdentityRoutes } from '../modules/identity/index.js';
|
||||
import { createFlagStore, type FeatureFlagProvider } from '../modules/flags/index.js';
|
||||
import { AppError, errorEnvelope } from '../shared/errors.js';
|
||||
import { createLogger, type Logger } from '../infrastructure/logging/logger.js';
|
||||
@@ -26,6 +28,10 @@ export interface BuildAppDeps {
|
||||
logger?: Logger;
|
||||
/** Feature flags. Default: empty store, every flag OFF (fail-safe). */
|
||||
flags?: FeatureFlagProvider;
|
||||
/** Database pool. When present, DB-backed modules (identity) are wired. */
|
||||
pool?: pg.Pool;
|
||||
/** Secure cookie flag forwarded to identity routes. */
|
||||
cookieSecure?: boolean;
|
||||
}
|
||||
|
||||
function generateRequestId(raw: IncomingMessage): string {
|
||||
@@ -107,5 +113,14 @@ export async function buildApp(deps: BuildAppDeps = {}): Promise<FastifyInstance
|
||||
await registerHealthRoutes(instance);
|
||||
});
|
||||
|
||||
if (deps.pool) {
|
||||
await app.register(async (instance) => {
|
||||
await registerIdentityRoutes(instance, {
|
||||
pool: deps.pool as pg.Pool,
|
||||
cookieSecure: deps.cookieSecure,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user