underrate's picture
Initial commit
d53e5b4 verified
Raw
History Blame Contribute Delete
1.83 kB
import { Request, Response, NextFunction } from 'express';
import { AnyZodObject, ZodError } from 'zod';
import xss from 'xss';
/**
* Validates request body, query, or params against a Zod schema.
* Automatically sanitizes strings in `req.body` using the `xss` library before validation.
*/
export const validateRequest = (schema: AnyZodObject) => {
return async (req: Request, res: Response, next: NextFunction) => {
try {
// Traverse and sanitize string fields in req.body
if (req.body && typeof req.body === 'object') {
for (const key of Object.keys(req.body)) {
if (typeof req.body[key] === 'string') {
req.body[key] = xss(req.body[key], {
whiteList: {}, // completely strip all HTML tags
stripIgnoreTag: true,
stripIgnoreTagBody: ['script'] // ensures inner content of <script> is ripped out
});
}
}
}
// Validate against Zod Schema
await schema.parseAsync({
body: req.body,
query: req.query,
params: req.params,
});
return next();
} catch (error) {
if (error instanceof ZodError) {
return res.status(400).json({
error: 'Validation failed',
details: error.errors.map(err => ({
path: err.path.join('.'),
message: err.message
}))
});
}
return res.status(500).json({ error: 'Internal server error during validation' });
}
};
};