mcp-sanitizer
Version:
Comprehensive security sanitization library for Model Context Protocol (MCP) servers with trusted security libraries
411 lines (360 loc) • 11 kB
JavaScript
/**
* MCP Sanitizer Validators Module
*
* This module exports all validator classes and utility functions for easy importing.
* Each validator provides comprehensive validation and sanitization for specific
* input types, with consistent APIs and return formats.
*
* All validators implement the following interface:
* - validate(input, options): Promise<ValidationResult>
* - sanitize(input, options): Promise<SanitizationResult>
* - updateConfig(newConfig): void
* - getConfig(): Object
*
* ValidationResult format:
* {
* isValid: boolean,
* sanitized: string|null,
* warnings: string[],
* severity: 'low'|'medium'|'high'|'critical'|null,
* metadata: Object
* }
*
* @example
* // Import specific validators
* const { FilePathValidator, URLValidator } = require('./validators');
*
* // Import factory functions
* const { createFilePathValidator, validateURL } = require('./validators');
*
* // Import all validators
* const validators = require('./validators');
* const fileValidator = new validators.FilePathValidator();
*/
// Import individual validator modules
const filePathValidator = require('./file-path')
const urlValidator = require('./url')
const commandValidator = require('./command')
const sqlValidator = require('./sql')
/**
* Export all validator classes
*/
const FilePathValidator = filePathValidator.FilePathValidator
const URLValidator = urlValidator.URLValidator
const CommandValidator = commandValidator.CommandValidator
const SQLValidator = sqlValidator.SQLValidator
/**
* Export all factory functions
*/
const createFilePathValidator = filePathValidator.createFilePathValidator
const createURLValidator = urlValidator.createURLValidator
const createCommandValidator = commandValidator.createCommandValidator
const createSQLValidator = sqlValidator.createSQLValidator
/**
* Export all convenience functions
*/
const validateFilePath = filePathValidator.validateFilePath
const sanitizeFilePath = filePathValidator.sanitizeFilePath
const validateURL = urlValidator.validateURL
const sanitizeURL = urlValidator.sanitizeURL
const validateCommand = commandValidator.validateCommand
const sanitizeCommand = commandValidator.sanitizeCommand
const validateSQL = sqlValidator.validateSQL
const sanitizeSQL = sqlValidator.sanitizeSQL
/**
* Export all constants
*/
const SEVERITY_LEVELS = {
LOW: 'low',
MEDIUM: 'medium',
HIGH: 'high',
CRITICAL: 'critical'
}
/**
* Validator type constants for easier identification
*/
const VALIDATOR_TYPES = {
FILE_PATH: 'file_path',
URL: 'url',
COMMAND: 'command',
SQL: 'sql'
}
/**
* Default configurations for all validators
*/
const DEFAULT_CONFIGS = {
filePath: filePathValidator.DEFAULT_CONFIG,
url: urlValidator.DEFAULT_CONFIG,
command: commandValidator.DEFAULT_CONFIG,
sql: sqlValidator.DEFAULT_CONFIG
}
/**
* Create a validator instance based on type
* @param {string} type - Validator type (file_path, url, command, sql)
* @param {Object} config - Optional configuration
* @returns {Object} Validator instance
*/
function createValidator (type, config = {}) {
switch (type.toLowerCase()) {
case VALIDATOR_TYPES.FILE_PATH:
case 'filepath':
case 'path':
return new FilePathValidator(config)
case VALIDATOR_TYPES.URL:
case 'uri':
return new URLValidator(config)
case VALIDATOR_TYPES.COMMAND:
case 'cmd':
return new CommandValidator(config)
case VALIDATOR_TYPES.SQL:
case 'query':
return new SQLValidator(config)
default:
throw new Error(`Unknown validator type: ${type}. Supported types: ${Object.values(VALIDATOR_TYPES).join(', ')}`)
}
}
/**
* Validate input using appropriate validator based on type
* @param {string} input - Input to validate
* @param {string} type - Validator type
* @param {Object} config - Optional configuration
* @returns {Promise<Object>} Validation result
*/
async function validate (input, type, config = {}) {
const validator = createValidator(type, config)
return await validator.validate(input)
}
/**
* Sanitize input using appropriate validator based on type
* @param {string} input - Input to sanitize
* @param {string} type - Validator type
* @param {Object} config - Optional configuration
* @returns {Promise<Object>} Sanitization result
*/
async function sanitize (input, type, config = {}) {
const validator = createValidator(type, config)
return await validator.sanitize(input)
}
/**
* Batch validate multiple inputs of different types
* @param {Array} inputs - Array of {input, type, config} objects
* @returns {Promise<Array>} Array of validation results
*/
async function validateBatch (inputs) {
const results = []
for (const { input, type, config = {} } of inputs) {
try {
const result = await validate(input, type, config)
results.push({
input,
type,
...result
})
} catch (error) {
results.push({
input,
type,
isValid: false,
sanitized: null,
warnings: [`Validation error: ${error.message}`],
severity: SEVERITY_LEVELS.HIGH,
metadata: { error: error.message }
})
}
}
return results
}
/**
* Batch sanitize multiple inputs of different types
* @param {Array} inputs - Array of {input, type, config} objects
* @returns {Promise<Array>} Array of sanitization results
*/
async function sanitizeBatch (inputs) {
const results = []
for (const { input, type, config = {} } of inputs) {
try {
const result = await sanitize(input, type, config)
results.push({
input,
type,
...result
})
} catch (error) {
results.push({
input,
type,
isValid: false,
sanitized: null,
warnings: [`Sanitization error: ${error.message}`],
severity: SEVERITY_LEVELS.HIGH,
metadata: { error: error.message }
})
}
}
return results
}
/**
* Get validator configuration by type
* @param {string} type - Validator type
* @returns {Object} Default configuration for the validator
*/
function getValidatorConfig (type) {
switch (type.toLowerCase()) {
case VALIDATOR_TYPES.FILE_PATH:
case 'filepath':
case 'path':
return { ...DEFAULT_CONFIGS.filePath }
case VALIDATOR_TYPES.URL:
case 'uri':
return { ...DEFAULT_CONFIGS.url }
case VALIDATOR_TYPES.COMMAND:
case 'cmd':
return { ...DEFAULT_CONFIGS.command }
case VALIDATOR_TYPES.SQL:
case 'query':
return { ...DEFAULT_CONFIGS.sql }
default:
throw new Error(`Unknown validator type: ${type}`)
}
}
/**
* Create a configured validator manager for consistent validation across an application
* @param {Object} globalConfig - Global configuration to apply to all validators
* @returns {Object} Validator manager with pre-configured validators
*/
function createValidatorManager (globalConfig = {}) {
const configs = {
filePath: { ...DEFAULT_CONFIGS.filePath, ...globalConfig.filePath },
url: { ...DEFAULT_CONFIGS.url, ...globalConfig.url },
command: { ...DEFAULT_CONFIGS.command, ...globalConfig.command },
sql: { ...DEFAULT_CONFIGS.sql, ...globalConfig.sql }
}
const validators = {
filePath: new FilePathValidator(configs.filePath),
url: new URLValidator(configs.url),
command: new CommandValidator(configs.command),
sql: new SQLValidator(configs.sql)
}
return {
// Direct validator access
validators,
// Convenience methods
async validateFilePath (input, options = {}) {
return await validators.filePath.validate(input, options)
},
async sanitizeFilePath (input, options = {}) {
return await validators.filePath.sanitize(input, options)
},
async validateURL (input, options = {}) {
return await validators.url.validate(input, options)
},
async sanitizeURL (input, options = {}) {
return await validators.url.sanitize(input, options)
},
async validateCommand (input, options = {}) {
return await validators.command.validate(input, options)
},
async sanitizeCommand (input, options = {}) {
return await validators.command.sanitize(input, options)
},
async validateSQL (input, options = {}) {
return await validators.sql.validate(input, options)
},
async sanitizeSQL (input, options = {}) {
return await validators.sql.sanitize(input, options)
},
// Generic methods
async validate (input, type, options = {}) {
const validator = validators[type] || this._getValidatorByType(type)
return await validator.validate(input, options)
},
async sanitize (input, type, options = {}) {
const validator = validators[type] || this._getValidatorByType(type)
return await validator.sanitize(input, options)
},
// Update configurations
updateConfig (type, newConfig) {
if (validators[type]) {
validators[type].updateConfig(newConfig)
}
},
updateAllConfigs (newGlobalConfig) {
Object.keys(validators).forEach(type => {
if (newGlobalConfig[type]) {
validators[type].updateConfig(newGlobalConfig[type])
}
})
},
// Get configurations
getConfig (type) {
return validators[type] ? validators[type].getConfig() : null
},
getAllConfigs () {
const configs = {}
Object.keys(validators).forEach(type => {
configs[type] = validators[type].getConfig()
})
return configs
},
// Helper method to get validator by type string
_getValidatorByType (type) {
switch (type.toLowerCase()) {
case VALIDATOR_TYPES.FILE_PATH:
case 'filepath':
case 'path':
return validators.filePath
case VALIDATOR_TYPES.URL:
case 'uri':
return validators.url
case VALIDATOR_TYPES.COMMAND:
case 'cmd':
return validators.command
case VALIDATOR_TYPES.SQL:
case 'query':
return validators.sql
default:
throw new Error(`Unknown validator type: ${type}`)
}
}
}
}
// Export everything
module.exports = {
// Validator classes
FilePathValidator,
URLValidator,
CommandValidator,
SQLValidator,
// Factory functions
createFilePathValidator,
createURLValidator,
createCommandValidator,
createSQLValidator,
createValidator,
createValidatorManager,
// Convenience functions
validateFilePath,
sanitizeFilePath,
validateURL,
sanitizeURL,
validateCommand,
sanitizeCommand,
validateSQL,
sanitizeSQL,
// Generic functions
validate,
sanitize,
validateBatch,
sanitizeBatch,
// Configuration utilities
getValidatorConfig,
// Constants
SEVERITY_LEVELS,
VALIDATOR_TYPES,
DEFAULT_CONFIGS,
// Individual module exports for direct access
filePathValidator,
urlValidator,
commandValidator,
sqlValidator
}