"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationMiddleware = void 0; const ErrorResponseService_1 = require("./ErrorResponseService"); const Logger_1 = require("./Logger"); /** * Common validation middleware functions for request validation */ class ValidationMiddleware { /** * Validates required fields in request body * @param requiredFields Array of required field names */ static validateRequiredFields(requiredFields) { return (req, res, next) => { const missingFields = []; for (const field of requiredFields) { if (!req.body || req.body[field] === undefined || req.body[field] === null || req.body[field] === '') { missingFields.push(field); } } if (missingFields.length > 0) { (0, Logger_1.logWarning)('Validation failed - missing required fields', { missingFields, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Missing required fields', { missingFields }); } next(); }; } /** * Validates field types in request body * @param fieldTypes Object mapping field names to expected types */ static validateFieldTypes(fieldTypes) { return (req, res, next) => { const typeErrors = []; for (const [field, expectedType] of Object.entries(fieldTypes)) { if (req.body && req.body[field] !== undefined) { const actualType = Array.isArray(req.body[field]) ? 'array' : typeof req.body[field]; if (actualType !== expectedType) { typeErrors.push(`Field '${field}' should be ${expectedType}, got ${actualType}`); } } } if (typeErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - invalid field types', { typeErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Invalid field types', { errors: typeErrors }); } next(); }; } /** * Validates string field length constraints * @param constraints Object mapping field names to min/max length */ static validateStringLength(constraints) { return (req, res, next) => { const lengthErrors = []; for (const [field, constraint] of Object.entries(constraints)) { if (req.body && typeof req.body[field] === 'string') { const value = req.body[field]; if (constraint.min !== undefined && value.length < constraint.min) { lengthErrors.push(`Field '${field}' must be at least ${constraint.min} characters`); } if (constraint.max !== undefined && value.length > constraint.max) { lengthErrors.push(`Field '${field}' must not exceed ${constraint.max} characters`); } } } if (lengthErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - string length constraints', { lengthErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'String length validation failed', { errors: lengthErrors }); } next(); }; } /** * Validates email format * @param emailFields Array of field names that should contain valid emails */ static validateEmailFormat(emailFields) { return (req, res, next) => { const emailErrors = []; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; for (const field of emailFields) { if (req.body && req.body[field] && typeof req.body[field] === 'string') { if (!emailRegex.test(req.body[field])) { emailErrors.push(`Field '${field}' must contain a valid email address`); } } } if (emailErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - invalid email format', { emailErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Email format validation failed', { errors: emailErrors }); } next(); }; } /** * Validates UUIDs format * @param uuidFields Array of field names that should contain valid UUIDs */ static validateUUIDFormat(uuidFields) { return (req, res, next) => { const uuidErrors = []; const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; for (const field of uuidFields) { const value = field.includes('.') ? this.getNestedValue(req, field) : req.body?.[field] || req.params?.[field] || req.query?.[field]; if (value && typeof value === 'string') { if (!uuidRegex.test(value)) { uuidErrors.push(`Field '${field}' must contain a valid UUID`); } } } if (uuidErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - invalid UUID format', { uuidErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'UUID format validation failed', { errors: uuidErrors }); } next(); }; } /** * Validates numeric constraints * @param constraints Object mapping field names to min/max values */ static validateNumericConstraints(constraints) { return (req, res, next) => { const numericErrors = []; for (const [field, constraint] of Object.entries(constraints)) { if (req.body && typeof req.body[field] === 'number') { const value = req.body[field]; if (constraint.min !== undefined && value < constraint.min) { numericErrors.push(`Field '${field}' must be at least ${constraint.min}`); } if (constraint.max !== undefined && value > constraint.max) { numericErrors.push(`Field '${field}' must not exceed ${constraint.max}`); } } } if (numericErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - numeric constraints', { numericErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Numeric validation failed', { errors: numericErrors }); } next(); }; } /** * Validates that arrays are not empty * @param arrayFields Array of field names that should contain non-empty arrays */ static validateNonEmptyArrays(arrayFields) { return (req, res, next) => { const arrayErrors = []; for (const field of arrayFields) { if (req.body && Array.isArray(req.body[field])) { if (req.body[field].length === 0) { arrayErrors.push(`Field '${field}' must not be empty`); } } else if (req.body && req.body[field] !== undefined) { arrayErrors.push(`Field '${field}' must be an array`); } } if (arrayErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - empty arrays', { arrayErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Array validation failed', { errors: arrayErrors }); } next(); }; } /** * Validates allowed values for enum-like fields * @param allowedValues Object mapping field names to arrays of allowed values */ static validateAllowedValues(allowedValues) { return (req, res, next) => { const valueErrors = []; for (const [field, allowed] of Object.entries(allowedValues)) { if (req.body && req.body[field] !== undefined) { if (!allowed.includes(req.body[field])) { valueErrors.push(`Field '${field}' must be one of: ${allowed.join(', ')}`); } } } if (valueErrors.length > 0) { (0, Logger_1.logWarning)('Validation failed - disallowed values', { valueErrors, endpoint: req.path }, req, res); return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Value validation failed', { errors: valueErrors }); } next(); }; } /** * Combines multiple validation middlewares * @param validations Array of validation middleware functions */ static combine(validations) { return async (req, res, next) => { let currentIndex = 0; const runNext = (error) => { if (error) { return next(error); } if (currentIndex >= validations.length) { return next(); } const currentValidation = validations[currentIndex++]; try { currentValidation(req, res, (err) => { if (res.headersSent) { return; // Response already sent, don't continue } runNext(err); }); } catch (error) { (0, Logger_1.logError)('Validation middleware error', error, req, res); ErrorResponseService_1.ErrorResponseService.sendInternalServerError(res); } }; runNext(); }; } /** * Helper method to get nested values from request * @param req Request object * @param path Dot-notation path like 'body.user.id' */ static getNestedValue(req, path) { const parts = path.split('.'); let current = req; for (const part of parts) { if (current && typeof current === 'object') { current = current[part]; } else { return undefined; } } return current; } } exports.ValidationMiddleware = ValidationMiddleware; //# sourceMappingURL=ValidationMiddleware.js.map