Files
livedash-node/middleware/csrfProtection.ts
Kaj Kowalski 1eea2cc3e4 refactor: fix biome linting issues and update project documentation
- Fix 36+ biome linting issues reducing errors/warnings from 227 to 191
- Replace explicit 'any' types with proper TypeScript interfaces
- Fix React hooks dependencies and useCallback patterns
- Resolve unused variables and parameter assignment issues
- Improve accessibility with proper label associations
- Add comprehensive API documentation for admin and security features
- Update README.md with accurate PostgreSQL setup and current tech stack
- Create complete documentation for audit logging, CSP monitoring, and batch processing
- Fix outdated project information and missing developer workflows
2025-07-12 00:28:09 +02:00

124 lines
2.9 KiB
TypeScript

/**
* CSRF Protection Middleware
*
* This middleware protects against Cross-Site Request Forgery attacks by:
* 1. Validating CSRF tokens on state-changing operations
* 2. Generating new tokens for safe requests
* 3. Blocking unauthorized requests
*/
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { CSRFProtection, CSRF_CONFIG } from "../lib/csrf";
/**
* Routes that require CSRF protection
*/
const PROTECTED_PATHS = [
// Authentication endpoints
"/api/auth/signin",
"/api/auth/signout",
"/api/register",
"/api/forgot-password",
"/api/reset-password",
// Dashboard API endpoints
"/api/dashboard",
// Platform admin endpoints
"/api/platform",
// tRPC endpoints (all state-changing operations)
"/api/trpc",
] as const;
/**
* HTTP methods that require CSRF protection
*/
const PROTECTED_METHODS = ["POST", "PUT", "DELETE", "PATCH"] as const;
/**
* Check if path requires CSRF protection
*/
function requiresCSRFProtection(pathname: string, method: string): boolean {
// Only protect state-changing methods
if (!PROTECTED_METHODS.includes(method as any)) {
return false;
}
// Check if path starts with any protected path
return PROTECTED_PATHS.some((path) => pathname.startsWith(path));
}
/**
* CSRF protection middleware
*/
export async function csrfProtectionMiddleware(
request: NextRequest
): Promise<NextResponse> {
const { pathname } = request.nextUrl;
const method = request.method;
// Skip CSRF protection for safe methods and unprotected paths
if (!requiresCSRFProtection(pathname, method)) {
return NextResponse.next();
}
// Validate CSRF token for protected requests
const validation = await CSRFProtection.validateRequest(request);
if (!validation.valid) {
console.warn(
`CSRF validation failed for ${method} ${pathname}:`,
validation.error
);
return NextResponse.json(
{
success: false,
error: "Invalid or missing CSRF token",
code: "CSRF_TOKEN_INVALID",
},
{
status: 403,
headers: {
"Content-Type": "application/json",
},
}
);
}
return NextResponse.next();
}
/**
* Generate CSRF token endpoint response
*/
export function generateCSRFTokenResponse(): NextResponse {
const { token, cookie } = CSRFProtection.generateTokenResponse();
const response = NextResponse.json({
success: true,
token,
});
// Set the CSRF token cookie
response.cookies.set(cookie.name, cookie.value, cookie.options);
return response;
}
/**
* Middleware for serving CSRF tokens to clients
*/
export function csrfTokenMiddleware(request: NextRequest): NextResponse | null {
const { pathname } = request.nextUrl;
// Handle CSRF token endpoint
if (pathname === "/api/csrf-token" && request.method === "GET") {
return generateCSRFTokenResponse();
}
return null;
}