Skip to main content
Glama
sanitization.ts6.12 kB
import { Request, Response, NextFunction } from 'express'; import { sanitizeObject, sanitizeString, SanitizationPresets, SanitizationOptions } from '../utils/input-sanitizer'; /** * Middleware configuration for request sanitization */ export interface SanitizationMiddlewareOptions { /** Sanitization options for request body */ bodyOptions?: SanitizationOptions; /** Sanitization options for query parameters */ queryOptions?: SanitizationOptions; /** Sanitization options for URL parameters */ paramsOptions?: SanitizationOptions; /** Skip sanitization for specific routes (regex patterns) */ skipRoutes?: RegExp[]; /** Custom sanitization logic for specific fields */ customSanitizers?: Record<string, (value: any) => any>; } /** * Default configuration for API sanitization */ const DEFAULT_OPTIONS: Required<SanitizationMiddlewareOptions> = { bodyOptions: SanitizationPresets.FORM_INPUT, queryOptions: SanitizationPresets.API_PARAM, paramsOptions: SanitizationPresets.API_PARAM, skipRoutes: [], customSanitizers: {}, }; /** * Creates a sanitization middleware with the specified options * * @param options - Configuration options for sanitization * @returns Express middleware function */ export function createSanitizationMiddleware( options: SanitizationMiddlewareOptions = {} ): (req: Request, res: Response, next: NextFunction) => void { const config = { ...DEFAULT_OPTIONS, ...options }; return (req: Request, res: Response, next: NextFunction) => { try { // Check if route should be skipped const shouldSkip = config.skipRoutes.some(pattern => pattern.test(req.path)); if (shouldSkip) { return next(); } // Sanitize request body if (req.body && typeof req.body === 'object') { req.body = sanitizeRequestObject(req.body, config.bodyOptions, config.customSanitizers); } // Sanitize query parameters if (req.query && typeof req.query === 'object') { req.query = sanitizeRequestObject(req.query, config.queryOptions, config.customSanitizers); } // Sanitize URL parameters if (req.params && typeof req.params === 'object') { req.params = sanitizeRequestObject(req.params, config.paramsOptions, config.customSanitizers); } next(); } catch (error) { // If sanitization fails, it's likely a security issue - reject the request res.status(400).json({ error: 'Invalid request data', message: 'Request contains invalid or potentially malicious content', }); } }; } /** * Sanitizes a request object with custom sanitizers */ function sanitizeRequestObject( obj: Record<string, any>, options: SanitizationOptions, customSanitizers: Record<string, (value: any) => any> ): Record<string, any> { // First apply standard sanitization const sanitized = sanitizeObject(obj, options); // Then apply custom sanitizers for specific fields for (const [fieldName, sanitizer] of Object.entries(customSanitizers)) { if (sanitized[fieldName] !== undefined) { sanitized[fieldName] = sanitizer(sanitized[fieldName]); } } return sanitized; } /** * Specific sanitization middleware for different types of content */ export const SanitizationMiddleware = { /** * Strict sanitization for API endpoints that handle IDs and parameters */ apiParams: createSanitizationMiddleware({ bodyOptions: SanitizationPresets.API_PARAM, queryOptions: SanitizationPresets.API_PARAM, paramsOptions: SanitizationPresets.API_PARAM, }), /** * Form input sanitization for endpoints that handle user-generated content */ formInput: createSanitizationMiddleware({ bodyOptions: SanitizationPresets.FORM_INPUT, queryOptions: SanitizationPresets.API_PARAM, paramsOptions: SanitizationPresets.API_PARAM, }), /** * Rich text sanitization for endpoints that handle formatted content */ richText: createSanitizationMiddleware({ bodyOptions: SanitizationPresets.RICH_TEXT, queryOptions: SanitizationPresets.API_PARAM, paramsOptions: SanitizationPresets.API_PARAM, }), /** * Custom sanitization for MCP tool requests */ mcpTools: createSanitizationMiddleware({ bodyOptions: SanitizationPresets.FORM_INPUT, queryOptions: SanitizationPresets.API_PARAM, paramsOptions: SanitizationPresets.API_PARAM, customSanitizers: { // Sanitize form IDs to ensure they're safe formId: (value: any) => { if (typeof value === 'string') { return sanitizeString(value, SanitizationPresets.API_PARAM); } return value; }, // Sanitize workspace IDs workspaceId: (value: any) => { if (typeof value === 'string') { return sanitizeString(value, SanitizationPresets.API_PARAM); } return value; }, // Sanitize user IDs userId: (value: any) => { if (typeof value === 'string') { return sanitizeString(value, SanitizationPresets.API_PARAM); } return value; }, }, }), }; /** * Manual sanitization functions for specific use cases */ export const ManualSanitization = { /** * Sanitizes form data before sending to Tally API */ formData: (data: Record<string, any>) => { return sanitizeObject(data, SanitizationPresets.FORM_INPUT); }, /** * Sanitizes API response data from external sources */ apiResponse: (data: Record<string, any>) => { return sanitizeObject(data, SanitizationPresets.STRICT); }, /** * Sanitizes user profile data */ userProfile: (data: Record<string, any>) => { return sanitizeObject(data, { allowBasicFormatting: false, allowLinks: false, stripAllHtml: true, }); }, /** * Sanitizes log messages to prevent log injection */ logMessage: (message: string) => { return sanitizeString(message, { stripAllHtml: true, allowBasicFormatting: false, allowLinks: false, }).replace(/[\r\n\t]/g, ' '); // Remove line breaks that could break log format }, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/learnwithcc/tally-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server