Spaces:
Paused
Paused
| /** | |
| * Middleware for validating path parameters against ALLOWED_ROOT_DIRECTORY | |
| * Provides a clean, reusable way to validate paths without repeating the same | |
| * try-catch block in every route handler | |
| */ | |
| import type { Request, Response, NextFunction } from 'express'; | |
| import { validatePath, PathNotAllowedError } from '@automaker/platform'; | |
| /** | |
| * Helper to get parameter value from request (checks body first, then query) | |
| */ | |
| function getParamValue(req: Request, paramName: string): unknown { | |
| // Check body first (for POST/PUT/PATCH requests) | |
| if (req.body && req.body[paramName] !== undefined) { | |
| return req.body[paramName]; | |
| } | |
| // Fall back to query params (for GET requests) | |
| if (req.query && req.query[paramName] !== undefined) { | |
| return req.query[paramName]; | |
| } | |
| return undefined; | |
| } | |
| /** | |
| * Creates a middleware that validates specified path parameters in req.body or req.query | |
| * @param paramNames - Names of parameters to validate (e.g., 'projectPath', 'worktreePath') | |
| * @example | |
| * router.post('/create', validatePathParams('projectPath'), handler); | |
| * router.post('/delete', validatePathParams('projectPath', 'worktreePath'), handler); | |
| * router.post('/send', validatePathParams('workingDirectory?', 'imagePaths[]'), handler); | |
| * router.get('/logs', validatePathParams('worktreePath'), handler); // Works with query params too | |
| * | |
| * Special syntax: | |
| * - 'paramName?' - Optional parameter (only validated if present) | |
| * - 'paramName[]' - Array parameter (validates each element) | |
| */ | |
| export function validatePathParams(...paramNames: string[]) { | |
| return (req: Request, res: Response, next: NextFunction): void => { | |
| try { | |
| for (const paramName of paramNames) { | |
| // Handle optional parameters (paramName?) | |
| if (paramName.endsWith('?')) { | |
| const actualName = paramName.slice(0, -1); | |
| const value = getParamValue(req, actualName); | |
| if (value && typeof value === 'string') { | |
| validatePath(value); | |
| } | |
| continue; | |
| } | |
| // Handle array parameters (paramName[]) | |
| if (paramName.endsWith('[]')) { | |
| const actualName = paramName.slice(0, -2); | |
| const values = getParamValue(req, actualName); | |
| if (Array.isArray(values) && values.length > 0) { | |
| for (const value of values) { | |
| if (typeof value === 'string') { | |
| validatePath(value); | |
| } | |
| } | |
| } | |
| continue; | |
| } | |
| // Handle regular parameters | |
| const value = getParamValue(req, paramName); | |
| if (value && typeof value === 'string') { | |
| validatePath(value); | |
| } | |
| } | |
| next(); | |
| } catch (error) { | |
| if (error instanceof PathNotAllowedError) { | |
| res.status(403).json({ | |
| success: false, | |
| error: error.message, | |
| }); | |
| return; | |
| } | |
| // Re-throw unexpected errors | |
| throw error; | |
| } | |
| }; | |
| } | |