Files
Checkmate/server/src/api/middleware/sanitization.ts
T

63 lines
1.9 KiB
TypeScript

import type { Request, Response, NextFunction } from "express";
import DOMPurify from "isomorphic-dompurify";
export function sanitizeInput(input: string, options?: object): string;
export function sanitizeInput(input: unknown, options?: object): unknown;
export function sanitizeInput(input: unknown, options = {}): unknown {
if (typeof input !== "string") {
return input;
}
// Default configuration - remove all HTML tags and attributes
const defaultConfig = {
ALLOWED_TAGS: [] as string[],
ALLOWED_ATTR: [] as string[],
KEEP_CONTENT: true,
...options,
};
return DOMPurify.sanitize(input, defaultConfig);
}
export const sanitizeObject = (obj: unknown, options = {}): unknown => {
if (typeof obj !== "object" || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => sanitizeObject(item, options));
}
const sanitized: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "string") {
sanitized[key] = sanitizeInput(value, options);
} else if (typeof value === "object" && value !== null) {
sanitized[key] = sanitizeObject(value, options);
} else {
sanitized[key] = value;
}
}
return sanitized;
};
export const sanitizeBody = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req: Request, res: Response, next: NextFunction) => {
if (req.body && typeof req.body === "object") {
req.body = sanitizeObject(req.body, options);
}
next();
};
};
export const sanitizeQuery = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req: Request, res: Response, next: NextFunction) => {
const sanitized = Object.fromEntries(
Object.entries(req.query).map(([key, value]) => [key, typeof value === "string" ? sanitizeInput(value, options) : value])
);
Object.defineProperty(req, "query", { value: sanitized, writable: true, configurable: true, enumerable: true });
next();
};
};