UNPKG

@csrf-armor/core

Version:

Framework-agnostic CSRF protection core functionality

169 lines (168 loc) 5.74 kB
import { CsrfAdapter, CsrfConfig } from "./types.mjs"; //#region src/csrf.d.ts declare class CsrfProtection<TRequest = unknown, TResponse = unknown> { private readonly config; private readonly adapter; /** * Creates a new CSRF protection instance. * * @param adapter - Framework-specific adapter for request/response handling * @param userConfig - Optional configuration overrides */ constructor(adapter: CsrfAdapter<TRequest, TResponse>, userConfig?: CsrfConfig); /** * Checks if a request should be excluded from CSRF protection. * * @param request - The CSRF request to check * @returns true if the request should be skipped * @internal */ private shouldSkipProtection; /** * Attempts to reuse existing CSRF tokens if they are still valid. * * @param request - The CSRF request containing potential existing tokens * @returns Token data if reuse is possible, null otherwise * @internal */ private attemptTokenReuse; /** * Builds the CSRF response with headers and cookies. * * @param tokenData - The token data to include in the response * @returns The CSRF response object * @internal */ private buildCsrfResponse; /** * Protects a request/response pair against CSRF attacks. * * This is the main method that applies CSRF protection to incoming requests. * It handles both token generation for safe methods (GET, HEAD, OPTIONS) and * token validation for state-changing methods (POST, PUT, DELETE, etc.). * * The method: * 1. Extracts request data using the framework adapter * 2. Checks if the request should be excluded or skipped * 3. For safe methods: generates and sets new CSRF tokens * 4. For unsafe methods: validates existing tokens using the configured strategy * 5. Applies response data (headers, cookies) using the adapter * * @param request - Framework-specific request object * @param response - Framework-specific response object * @returns Promise resolving to protection result with success status and modified response * * @example * ```typescript * // Basic usage in middleware * const result = await csrf.protect(req, res); * if (!result.success) { * return res.status(403).json({ * error: 'CSRF validation failed', * reason: result.reason * }); * } * * // Token is available for safe methods * if (result.token) { * console.log('Generated CSRF token:', result.token); * } * * // Continue with the modified response * return result.response; * ``` * * @example * ```typescript * // Error handling with specific reasons * const result = await csrf.protect(req, res); * if (!result.success) { * switch (result.reason) { * case 'Invalid token': * return res.status(403).json({ error: 'CSRF token is invalid' }); * case 'Token expired': * return res.status(403).json({ error: 'CSRF token has expired' }); * case 'Origin mismatch': * return res.status(403).json({ error: 'Request origin not allowed' }); * default: * return res.status(403).json({ error: 'CSRF validation failed' }); * } * } * ``` */ protect(request: TRequest, response: TResponse): Promise<{ success: boolean; response: TResponse; token?: string; reason?: string; }>; private generateTokensForStrategy; } /** * Factory function to create a CSRF protection instance. * * Convenient alternative to using the CsrfProtection constructor directly. * This function is the recommended way to create CSRF protection instances * as it provides better type inference and a cleaner API. * * @public * @template TRequest - Framework-specific request type * @template TResponse - Framework-specific response type * @param adapter - Framework adapter implementing CsrfAdapter interface * @param config - Optional CSRF configuration (uses secure defaults if not provided) * @returns Configured CSRF protection instance ready for use * * @example * ```typescript * import { createCsrfProtection } from '@csrf-armor/core'; * import { ExpressAdapter } from '@csrf-armor/express'; * * // Basic setup with defaults * const csrf = createCsrfProtection(new ExpressAdapter()); * * // Custom configuration * const csrf = createCsrfProtection(new ExpressAdapter(), { * strategy: 'signed-double-submit', * secret: process.env.CSRF_SECRET, * token: { * expiry: 7200, // 2 hours * fieldName: 'authenticity_token' * }, * excludePaths: ['/api/public'], * allowedOrigins: ['https://yourdomain.com'] * }); * * // Use in middleware * app.use(async (req, res, next) => { * const result = await csrf.protect(req, res); * if (result.success) { * next(); * } else { * res.status(403).json({ error: result.reason }); * } * }); * ``` * * @example * ```typescript * // Framework-specific usage * * // Express.js * import { ExpressAdapter } from '@csrf-armor/express'; * const expressCsrf = createCsrfProtection(new ExpressAdapter(), config); * * // Next.js * import { NextjsAdapter } from '@csrf-armor/nextjs'; * const nextCsrf = createCsrfProtection(new NextjsAdapter(), config); * * // Custom framework * class MyAdapter implements CsrfAdapter<MyRequest, MyResponse> { * // Implementation... * } * const customCsrf = createCsrfProtection(new MyAdapter(), config); * ``` */ declare function createCsrfProtection<TRequest = unknown, TResponse = unknown>(adapter: CsrfAdapter<TRequest, TResponse>, config?: CsrfConfig): CsrfProtection<TRequest, TResponse>; //#endregion export { CsrfProtection, createCsrfProtection }; //# sourceMappingURL=csrf.d.mts.map