/** * @module @arcis/node/middleware/protect * * Composite protection helpers (issue #52). Pre-configured middleware * stacks for the three endpoint shapes that show up in every app: * login, signup, generic API. Each helper composes EXISTING middleware * with sensible defaults; no new security logic lives here. * * Express supports passing an array of middleware to a route — the * elements get unrolled in declaration order — so each helper returns * a `RequestHandler[]` that drops directly into `app.post(...)`: * * ```ts * import { protectLogin, protectSignup, protectApi } from '@arcis/node'; * * app.post('/login', protectLogin(), loginHandler); * app.post('/signup', protectSignup(), signupHandler); * app.use ('/api', protectApi()); * ``` * * Defaults (issue #52 spec): * * | Helper | rate-limit | bot | csrf | cors | sanitize | email | * |---------------|------------|-----|------|------|----------|-------| * | protectLogin | 5/min | yes | yes | - | yes | - | * | protectSignup | 3/min | yes | - | - | yes | yes | * | protectApi | 100/min | - | - | yes | yes | - | * * Each option is overridable. Pass `{ rateLimit: false }` to disable a * specific layer; pass an options object to forward to the underlying * factory. */ import type { RequestHandler } from 'express'; import { type BotProtectionOptions } from './bot-detection'; import { type CsrfOptions } from './csrf'; import type { CorsOptions } from './cors'; import { type SignupProtectionOptions } from './signup-protection'; import { type BruteForceOptions } from './brute-force'; import type { RateLimitOptions, SanitizeOptions } from '../core/types'; import { CorrelationWindow } from './correlation'; /** * Per-protect-helper correlation-window wiring (improvements.md §1.4). * * Pass an instance of `CorrelationWindow` plus the vector tag this * route represents ("login" / "signup" / "api"). The middleware * records every request in the window and refuses the request when * the window flags the IP as a scanner / credential stuffer / race * probe. Detection-only otherwise. * * Pull-out fields: * - `usernameField`: body key whose value is the distinct-value * tracked for credential-stuffing detection. Defaults to * `'username'`. * - `route`: route label recorded in the window (so cross-route * aggregation is meaningful). Defaults to the request path. * - `statusCode` / `message`: response shape on a correlation block. */ export interface CorrelationOptions { window: CorrelationWindow; vector?: string; usernameField?: string; route?: string; statusCode?: number; message?: string; } /** * Per-layer override knob: pass `false` to disable, an options object * to merge into the layer's defaults, or omit to accept the helper's * baked-in default. */ type LayerOverride = false | T | undefined; export interface ProtectLoginOptions { rateLimit?: LayerOverride; bot?: LayerOverride; csrf?: LayerOverride; sanitize?: LayerOverride; /** Optional correlation-window wiring (improvements.md §1.4). */ correlation?: CorrelationOptions; /** * Optional brute-force layer. When enabled, layers a bursty limiter * on top of the fast rate-limit window: N attempts in `slowDuration` * seconds trips a `blockDuration`-second semi-permanent block. * Defaults to disabled (preserves existing behavior); pass `true` * for safe defaults or an options object to customize. */ bruteForce?: boolean | BruteForceOptions; } export interface ProtectSignupOptions { rateLimit?: LayerOverride; bot?: LayerOverride; sanitize?: LayerOverride; /** signupProtection options (email-style validation, disposable-mail block, etc.). */ signup?: LayerOverride; /** Optional correlation-window wiring (improvements.md §1.4). */ correlation?: CorrelationOptions; } export interface ProtectApiOptions { rateLimit?: LayerOverride; /** CORS is required to take an Origin/Methods config — no default origin. */ cors?: LayerOverride; sanitize?: LayerOverride; /** Optional correlation-window wiring (improvements.md §1.4). */ correlation?: CorrelationOptions; } /** * Login endpoints get the strictest defaults: 5 req/min/IP, deny * AUTOMATED bots, CSRF token check, and input sanitization. Designed * for `app.post('/login', protectLogin(), handler)`. */ export declare function protectLogin(options?: ProtectLoginOptions): RequestHandler[]; /** * Signup endpoints: 3 req/min/IP, deny AUTOMATED bots, sanitize input, * and run signup-specific validation (email shape + disposable-domain * check via `signupProtection`). No CSRF here because most signup * forms are first-touch, no prior session to anchor a token to. */ export declare function protectSignup(options?: ProtectSignupOptions): RequestHandler[]; /** * Generic API endpoints: 100 req/min/IP, CORS, input sanitization. No * bot detection by default because legitimate API consumers (curl, * fetch, server-to-server) are often classified AUTOMATED — opt-in * by passing a `bot` override... wait, protectApi doesn't expose bot. * That's deliberate per the issue spec table. Users who want bot * detection on API endpoints compose `botProtection()` directly. * * CORS is the one layer with no usable default — every app's allow * list is different. Pass `cors: { origin: '...' }` or `cors: false` * to skip it explicitly. */ export declare function protectApi(options?: ProtectApiOptions): RequestHandler[]; export {}; //# sourceMappingURL=protect.d.ts.map