UNPKG

@mickdarling/dollhousemcp

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

101 lines 13.5 kB
/** * Input validation and sanitization functions */ import { SECURITY_LIMITS, VALIDATION_PATTERNS } from './constants.js'; import { VALID_CATEGORIES } from '../config/constants.js'; /** * Validate and sanitize a filename */ export function validateFilename(filename) { if (!filename || typeof filename !== 'string') { throw new Error('Filename must be a non-empty string'); } if (filename.length > SECURITY_LIMITS.MAX_FILENAME_LENGTH) { throw new Error(`Filename too long (max ${SECURITY_LIMITS.MAX_FILENAME_LENGTH} characters)`); } // Remove any path separators and dangerous characters const sanitized = filename.replace(/[\/\\:*?"<>|]/g, '').replace(/^\.+/, ''); if (!VALIDATION_PATTERNS.SAFE_FILENAME.test(sanitized)) { throw new Error('Invalid filename format. Use alphanumeric characters, hyphens, underscores, and dots only.'); } return sanitized; } /** * Validate and sanitize a path */ export function validatePath(inputPath) { if (!inputPath || typeof inputPath !== 'string') { throw new Error('Path must be a non-empty string'); } // Remove leading/trailing slashes and normalize // Length limits added to prevent ReDoS attacks const normalized = inputPath.replace(/^\/{1,100}|\/{1,100}$/g, '').replace(/\/{1,100}/g, '/'); if (!VALIDATION_PATTERNS.SAFE_PATH.test(normalized)) { throw new Error('Invalid path format. Use alphanumeric characters, hyphens, underscores, dots, and forward slashes only.'); } // Check for path traversal attempts if (normalized.includes('..') || normalized.includes('./') || normalized.includes('/.')) { throw new Error('Path traversal not allowed'); } // Validate path depth const depth = normalized.split('/').length; if (depth > SECURITY_LIMITS.MAX_PATH_DEPTH) { throw new Error(`Path too deep (max ${SECURITY_LIMITS.MAX_PATH_DEPTH} levels)`); } return normalized; } /** * Validate and sanitize a username */ export function validateUsername(username) { if (!username || typeof username !== 'string') { throw new Error('Username must be a non-empty string'); } if (!VALIDATION_PATTERNS.SAFE_USERNAME.test(username)) { throw new Error('Invalid username format. Use alphanumeric characters, hyphens, underscores, and dots only.'); } return username.toLowerCase(); } /** * Validate a category */ export function validateCategory(category) { if (!category || typeof category !== 'string') { throw new Error('Category must be a non-empty string'); } if (!VALIDATION_PATTERNS.SAFE_CATEGORY.test(category)) { throw new Error('Invalid category format. Use alphabetic characters, hyphens, and underscores only.'); } const normalized = category.toLowerCase(); if (!VALID_CATEGORIES.includes(normalized)) { throw new Error(`Invalid category. Must be one of: ${VALID_CATEGORIES.join(', ')}`); } return normalized; } /** * Validate content size */ export function validateContentSize(content, maxSize = SECURITY_LIMITS.MAX_CONTENT_LENGTH) { if (!content || typeof content !== 'string') { throw new Error('Content must be a non-empty string'); } const sizeBytes = Buffer.byteLength(content, 'utf8'); if (sizeBytes > maxSize) { throw new Error(`Content too large (${sizeBytes} bytes, max ${maxSize} bytes)`); } } /** * General input sanitization */ export function sanitizeInput(input, maxLength = 1000) { if (!input || typeof input !== 'string') { return ''; } // Remove potentially dangerous characters and limit length return input .replace(/[\x00-\x1F\x7F]/g, '') // Remove control characters .replace(/[<>'"&]/g, '') // Remove HTML-dangerous characters .substring(0, maxLength) .trim(); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5wdXRWYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VjdXJpdHkvSW5wdXRWYWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxPQUFPLEVBQUUsZUFBZSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFMUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsUUFBZ0I7SUFDL0MsSUFBSSxDQUFDLFFBQVEsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QyxNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxlQUFlLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMxRCxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixlQUFlLENBQUMsbUJBQW1CLGNBQWMsQ0FBQyxDQUFDO0lBQy9GLENBQUM7SUFFRCxzREFBc0Q7SUFDdEQsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBRTdFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyw0RkFBNEYsQ0FBQyxDQUFDO0lBQ2hILENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUFDLFNBQWlCO0lBQzVDLElBQUksQ0FBQyxTQUFTLElBQUksT0FBTyxTQUFTLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDaEQs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RyxPQUFPLEVBQUUsQ0FBQztRQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLHNCQUFzQixTQUFTLGVBQWUsT0FBTyxTQUFTLENBQUMsQ0FBQztJQUNsRixDQUFDO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxLQUFhLEVBQUUsWUFBb0IsSUFBSTtJQUNuRSxJQUFJLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3hDLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxPQUFPLEtBQUs7U0FDVCxPQUFPLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxDQUFDLENBQUMsNEJBQTRCO1NBQzVELE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsbUNBQW1DO1NBQzNELFNBQVMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDO1NBQ3ZCLElBQUksRUFBRSxDQUFDO0FBQ1osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogSW5wdXQgdmFsaWRhdGlvbiBhbmQgc2FuaXRpemF0aW9uIGZ1bmN0aW9uc1xuICovXG5cbmltcG9ydCB7IFNFQ1VSSVRZX0xJTUlUUywgVkFMSURBVElPTl9QQVRURVJOUyB9IGZyb20gJy4vY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IFZBTElEX0NBVEVHT1JJRVMgfSBmcm9tICcuLi9jb25maWcvY29uc3RhbnRzLmpzJztcblxuLyoqXG4gKiBWYWxpZGF0ZSBhbmQgc2FuaXRpemUgYSBmaWxlbmFtZVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKCFmaWxlbmFtZSB8fCB0eXBlb2YgZmlsZW5hbWUgIT09ICdzdHJpbmcnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGaWxlbmFtZSBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZycpO1xuICB9XG4gIFxuICBpZiAoZmlsZW5hbWUubGVuZ3RoID4gU0VDVVJJVFlfTElNSVRTLk1BWF9GSUxFTkFNRV9MRU5HVEgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZpbGVuYW1lIHRvbyBsb25nIChtYXggJHtTRUNVUklUWV9MSU1JVFMuTUFYX0ZJTEVOQU1FX0xFTkdUSH0gY2hhcmFjdGVycylgKTtcbiAgfVxuICBcbiAgLy8gUmVtb3ZlIGFueSBwYXRoIHNlcGFyYXRvcnMgYW5kIGRhbmdlcm91cyBjaGFyYWN0ZXJzXG4gIGNvbnN0IHNhbml0aXplZCA9IGZpbGVuYW1lLnJlcGxhY2UoL1tcXC9cXFxcOio/XCI8PnxdL2csICcnKS5yZXBsYWNlKC9eXFwuKy8sICcnKTtcbiAgXG4gIGlmICghVkFMSURBVElPTl9QQVRURVJOUy5TQUZFX0ZJTEVOQU1FLnRlc3Qoc2FuaXRpemVkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBmaWxlbmFtZSBmb3JtYXQuIFVzZSBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgaHlwaGVucywgdW5kZXJzY29yZXMsIGFuZCBkb3RzIG9ubHkuJyk7XG4gIH1cbiAgXG4gIHJldHVybiBzYW5pdGl6ZWQ7XG59XG5cbi8qKlxuICogVmFsaWRhdGUgYW5kIHNhbml0aXplIGEgcGF0aFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVQYXRoKGlucHV0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKCFpbnB1dFBhdGggfHwgdHlwZW9mIGlucHV0UGF0aCAhPT0gJ3N0cmluZycpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1BhdGggbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmcnKTtcbiAgfVxuICBcbiAgLy8gUmVtb3ZlIGxlYWRpbmcvdHJhaWxpbmcgc2xhc2hlcyBhbmQgbm9ybWFsaXplXG4gIC8vIExlbmd0aCBsaW1pdHMgYWRkZWQgdG8gcHJldmVudCBSZURvUyBhdHRhY2tzXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBpbnB1dFBhdGgucmVwbGFjZSgvXlxcL3sxLDEwMH18XFwvezEsMTAwfSQvZywgJycpLnJlcGxhY2UoL1xcL3sxLDEwMH0vZywgJy8nKTtcbiAgXG4gIGlmICghVkFMSURBVElPTl9QQVRURVJOUy5TQUZFX1BBVEgudGVzdChub3JtYWxpemVkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwYXRoIGZvcm1hdC4gVXNlIGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzLCBoeXBoZW5zLCB1bmRlcnNjb3JlcywgZG90cywgYW5kIGZvcndhcmQgc2xhc2hlcyBvbmx5LicpO1xuICB9XG4gIFxuICAvLyBDaGVjayBmb3IgcGF0aCB0cmF2ZXJzYWwgYXR0ZW1wdHNcbiAgaWYgKG5vcm1hbGl6ZWQuaW5jbHVkZXMoJy4uJykgfHwgbm9ybWFsaXplZC5pbmNsdWRlcygnLi8nKSB8fCBub3JtYWxpemVkLmluY2x1ZGVzKCcvLicpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQYXRoIHRyYXZlcnNhbCBub3QgYWxsb3dlZCcpO1xuICB9XG4gIFxuICAvLyBWYWxpZGF0ZSBwYXRoIGRlcHRoXG4gIGNvbnN0IGRlcHRoID0gbm9ybWFsaXplZC5zcGxpdCgnLycpLmxlbmd0aDtcbiAgaWYgKGRlcHRoID4gU0VDVVJJVFlfTElNSVRTLk1BWF9QQVRIX0RFUFRIKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBQYXRoIHRvbyBkZWVwIChtYXggJHtTRUNVUklUWV9MSU1JVFMuTUFYX1BBVEhfREVQVEh9IGxldmVscylgKTtcbiAgfVxuICBcbiAgcmV0dXJuIG5vcm1hbGl6ZWQ7XG59XG5cbi8qKlxuICogVmFsaWRhdGUgYW5kIHNhbml0aXplIGEgdXNlcm5hbWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlVXNlcm5hbWUodXNlcm5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmICghdXNlcm5hbWUgfHwgdHlwZW9mIHVzZXJuYW1lICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBFcnJvcignVXNlcm5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmcnKTtcbiAgfVxuICBcbiAgaWYgKCFWQUxJREFUSU9OX1BBVFRFUk5TLlNBRkVfVVNFUk5BTUUudGVzdCh1c2VybmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdXNlcm5hbWUgZm9ybWF0LiBVc2UgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIGh5cGhlbnMsIHVuZGVyc2NvcmVzLCBhbmQgZG90cyBvbmx5LicpO1xuICB9XG4gIFxuICByZXR1cm4gdXNlcm5hbWUudG9Mb3dlckNhc2UoKTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBhIGNhdGVnb3J5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUNhdGVnb3J5KGNhdGVnb3J5OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoIWNhdGVnb3J5IHx8IHR5cGVvZiBjYXRlZ29yeSAhPT0gJ3N0cmluZycpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhdGVnb3J5IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG4gIH1cbiAgXG4gIGlmICghVkFMSURBVElPTl9QQVRURVJOUy5TQUZFX0NBVEVHT1JZLnRlc3QoY2F0ZWdvcnkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNhdGVnb3J5IGZvcm1hdC4gVXNlIGFscGhhYmV0aWMgY2hhcmFjdGVycywgaHlwaGVucywgYW5kIHVuZGVyc2NvcmVzIG9ubHkuJyk7XG4gIH1cbiAgXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBjYXRlZ29yeS50b0xvd2VyQ2FzZSgpO1xuICBcbiAgaWYgKCFWQUxJRF9DQVRFR09SSUVTLmluY2x1ZGVzKG5vcm1hbGl6ZWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNhdGVnb3J5LiBNdXN0IGJlIG9uZSBvZjogJHtWQUxJRF9DQVRFR09SSUVTLmpvaW4oJywgJyl9YCk7XG4gIH1cbiAgXG4gIHJldHVybiBub3JtYWxpemVkO1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIGNvbnRlbnQgc2l6ZVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVDb250ZW50U2l6ZShjb250ZW50OiBzdHJpbmcsIG1heFNpemU6IG51bWJlciA9IFNFQ1VSSVRZX0xJTUlUUy5NQVhfQ09OVEVOVF9MRU5HVEgpOiB2b2lkIHtcbiAgaWYgKCFjb250ZW50IHx8IHR5cGVvZiBjb250ZW50ICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBFcnJvcignQ29udGVudCBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZycpO1xuICB9XG4gIFxuICBjb25zdCBzaXplQnl0ZXMgPSBCdWZmZXIuYnl0ZUxlbmd0aChjb250ZW50LCAndXRmOCcpO1xuICBpZiAoc2l6ZUJ5dGVzID4gbWF4U2l6ZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ29udGVudCB0b28gbGFyZ2UgKCR7c2l6ZUJ5dGVzfSBieXRlcywgbWF4ICR7bWF4U2l6ZX0gYnl0ZXMpYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZW5lcmFsIGlucHV0IHNhbml0aXphdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemVJbnB1dChpbnB1dDogc3RyaW5nLCBtYXhMZW5ndGg6IG51bWJlciA9IDEwMDApOiBzdHJpbmcge1xuICBpZiAoIWlucHV0IHx8IHR5cGVvZiBpbnB1dCAhPT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cbiAgXG4gIC8vIFJlbW92ZSBwb3RlbnRpYWxseSBkYW5nZXJvdXMgY2hhcmFjdGVycyBhbmQgbGltaXQgbGVuZ3RoXG4gIHJldHVybiBpbnB1dFxuICAgIC5yZXBsYWNlKC9bXFx4MDAtXFx4MUZcXHg3Rl0vZywgJycpIC8vIFJlbW92ZSBjb250cm9sIGNoYXJhY3RlcnNcbiAgICAucmVwbGFjZSgvWzw+J1wiJl0vZywgJycpIC8vIFJlbW92ZSBIVE1MLWRhbmdlcm91cyBjaGFyYWN0ZXJzXG4gICAgLnN1YnN0cmluZygwLCBtYXhMZW5ndGgpXG4gICAgLnRyaW0oKTtcbn0iXX0=