/**
* UUID Validation Middleware
*
* Provides middleware functions to validate UUID parameters in Express routes.
* This prevents undefined parameter errors when invalid UUIDs are passed to UUID2hex().
*
* Usage:
* - Apply as route middleware: api.delete('/:UID', validateSingleUID, handler)
* - Apply as param middleware: api.param('UID', validateUUIDParam)
* - Validate multiple params: validateUUID(['UID', 'UIDparent', 'UIDperson'])
*/
import { isValidUID } from './UUIDs.js';
/**
* Validates UUID parameters in the request
* @param {string[]} paramNames - Array of parameter names to validate
* @returns {Function} Express middleware function
*
* @example
* // Validate single parameter
* api.delete('/:UID', validateUUID(['UID']), controller.delete);
*
* @example
* // Validate multiple parameters
* api.put('/:member/:group', validateUUID(['member', 'group']), controller.update);
*/
export const validateUUID = (paramNames = ['UID']) => {
return (req, res, next) => {
const invalidParams = [];
for (const paramName of paramNames) {
const uid = req.params[paramName];
// Only validate if parameter exists (some routes have optional params)
if (uid && !isValidUID(uid)) {
invalidParams.push(paramName);
}
}
if (invalidParams.length > 0) {
return res.status(400).json({
success: false,
message: `Invalid UUID format for parameter${invalidParams.length > 1 ? 's' : ''}: ${invalidParams.join(', ')}`,
error: 'INVALID_UUID',
params: invalidParams
});
}
next();
};
};
/**
* Convenience middleware for validating a single UID parameter
* Most common use case for DELETE, GET, POST endpoints
*
* @example
* api.delete('/:UID', validateSingleUID, controller.delete);
*/
export const validateSingleUID = validateUUID(['UID']);
/**
* Convenience middleware for validating multiple common UUID parameters
* Useful for endpoints that accept multiple UIDs
*
* @example
* api.put('/:member/:group/:function', validateMultipleUIDs, controller.create);
*/
export const validateMultipleUIDs = validateUUID([
'UID',
'UIDparent',
'UIDperson',
'UIDmember',
'UIDgroup',
'UIDfamily',
'UIDfunction',
'member',
'group',
'function',
'template'
]);
/**
* Express param middleware for automatic validation
* Apply this to automatically validate any route parameter
*
* @param {string} paramName - The parameter name to validate (e.g., 'UID')
* @returns {Function} Express param middleware function
*
* @example
* // Automatically validate all :UID parameters in this router
* api.param('UID', validateUUIDParam('UID'));
*
* // Now all routes with :UID are automatically protected
* api.delete('/:UID', controller.delete);
* api.get('/:UID', controller.get);
*/
export const validateUUIDParam = (paramName = 'UID') => {
return (req, res, next, value) => {
if (!isValidUID(value)) {
return res.status(400).json({
success: false,
message: `Invalid UUID format for parameter: ${paramName}`,
error: 'INVALID_UUID',
param: paramName,
value: value
});
}
next();
};
};
/**
* Validator for query parameters (not route params)
* Some endpoints receive UIDs in query strings
*
* @param {string[]} queryNames - Array of query parameter names to validate
* @returns {Function} Express middleware function
*
* @example
* api.get('/search', validateQueryUUID(['user', 'loginUser']), controller.search);
*/
export const validateQueryUUID = (queryNames = []) => {
return (req, res, next) => {
const invalidParams = [];
for (const queryName of queryNames) {
const uid = req.query[queryName];
// Only validate if query param exists
if (uid && !isValidUID(uid)) {
invalidParams.push(queryName);
}
}
if (invalidParams.length > 0) {
return res.status(400).json({
success: false,
message: `Invalid UUID format for query parameter${invalidParams.length > 1 ? 's' : ''}: ${invalidParams.join(', ')}`,
error: 'INVALID_UUID',
params: invalidParams
});
}
next();
};
};
/**
* Validator for request body UIDs
* Some endpoints receive UIDs in the request body
*
* @param {string[]} bodyFields - Array of body field names to validate
* @param {boolean} required - Whether the fields are required (default: false)
* @returns {Function} Express middleware function
*
* @example
* api.put('/', validateBodyUUID(['UID', 'UIDparent'], false), controller.create);
*/
export const validateBodyUUID = (bodyFields = [], required = false) => {
return (req, res, next) => {
const invalidFields = [];
const missingFields = [];
for (const fieldName of bodyFields) {
const uid = req.body[fieldName];
if (!uid) {
if (required) {
missingFields.push(fieldName);
}
continue;
}
if (!isValidUID(uid)) {
invalidFields.push(fieldName);
}
}
if (missingFields.length > 0) {
return res.status(400).json({
success: false,
message: `Missing required UUID field${missingFields.length > 1 ? 's' : ''}: ${missingFields.join(', ')}`,
error: 'MISSING_UUID',
fields: missingFields
});
}
if (invalidFields.length > 0) {
return res.status(400).json({
success: false,
message: `Invalid UUID format for field${invalidFields.length > 1 ? 's' : ''}: ${invalidFields.join(', ')}`,
error: 'INVALID_UUID',
fields: invalidFields
});
}
next();
};
};