UNPKG

@dollhousemcp/mcp-server

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.

257 lines 31 kB
/** * ElementValidation - Common validation logic for element managers * * Provides shared validation patterns for all element types: * - Name, description, category validation * - Trigger word validation * - Author and version validation * * SECURITY: All validation uses sanitizeInput and proper type checking * UNICODE HANDLING: Uses UnicodeValidator for safe string processing * * FIX: DMCP-SEC-006 - Security audit suppression * This file provides validation utilities only. * No audit logging is required - logging happens in the calling managers. * @security-audit-suppress DMCP-SEC-006 */ import { sanitizeInput } from '../../security/InputValidator.js'; import { UnicodeValidator } from '../../security/validators/unicodeValidator.js'; import { logger } from '../../utils/logger.js'; import { SecurityMonitor } from '../../security/securityMonitor.js'; /** * Validation constants shared across element types */ export const VALIDATION_CONSTANTS = { MAX_NAME_LENGTH: 100, MAX_DESCRIPTION_LENGTH: 500, MAX_CATEGORY_LENGTH: 50, MAX_TAG_LENGTH: 50, MAX_AUTHOR_LENGTH: 100, MAX_VERSION_LENGTH: 20, MAX_TRIGGER_LENGTH: 50, MAX_TRIGGERS: 20, // Allows alphanumeric, hyphens, underscores, @ (mentions/emails), . (domains) TRIGGER_VALIDATION_REGEX: /^[a-zA-Z0-9\-_@.]+$/ }; /** * Static utility class for common validation operations */ export class ElementValidation { /** * Validate and sanitize a name field * Applies Unicode normalization and length limits * * @param name - Raw name value * @param maxLength - Maximum length (default: 100) * @returns Sanitized name */ static validateName(name, maxLength = VALIDATION_CONSTANTS.MAX_NAME_LENGTH) { if (!name) { throw new Error('Name is required'); } const normalized = UnicodeValidator.normalize(String(name)); const sanitized = sanitizeInput(normalized.normalizedContent, maxLength); if (!sanitized) { throw new Error('Name is empty after sanitization'); } return sanitized; } /** * Validate and sanitize a description field * * @param description - Raw description value * @param maxLength - Maximum length (default: 500) * @returns Sanitized description or undefined */ static validateDescription(description, maxLength = VALIDATION_CONSTANTS.MAX_DESCRIPTION_LENGTH) { if (!description) { return undefined; } const normalized = UnicodeValidator.normalize(String(description)); return sanitizeInput(normalized.normalizedContent, maxLength) || undefined; } /** * Validate and sanitize an author field * * @param author - Raw author value * @returns Sanitized author or undefined */ static validateAuthor(author) { if (!author) { return undefined; } return sanitizeInput(String(author), VALIDATION_CONSTANTS.MAX_AUTHOR_LENGTH) || undefined; } /** * Validate and sanitize a version string * * @param version - Raw version value * @returns Sanitized version or undefined */ static validateVersion(version) { if (!version) { return undefined; } return sanitizeInput(String(version), VALIDATION_CONSTANTS.MAX_VERSION_LENGTH) || undefined; } /** * Validate and sanitize an array of tags * * @param tags - Raw tags array * @returns Sanitized tags array */ static validateTags(tags) { if (!Array.isArray(tags)) { return []; } return tags .filter(tag => tag !== null && tag !== undefined && tag !== '') // Filter out null/undefined/empty BEFORE converting .map(tag => sanitizeInput(String(tag), VALIDATION_CONSTANTS.MAX_TAG_LENGTH)) .filter((tag) => tag !== null && tag.length > 0); } /** * Validate and process triggers with detailed logging * Follows pattern from SkillManager (Issue #1139) and MemoryManager (Issue #1133) * * @param triggers - Raw triggers array * @param elementName - Element name for logging * @param maxTriggers - Maximum number of triggers (default: 20) * @returns Validation result with valid and rejected triggers */ static validateTriggers(triggers, elementName = 'unknown', maxTriggers = VALIDATION_CONSTANTS.MAX_TRIGGERS) { const result = { valid: [], rejected: [], warnings: [] }; if (!Array.isArray(triggers) || triggers.length === 0) { return result; } // Limit to max triggers const rawTriggers = triggers.slice(0, maxTriggers); // Validate each trigger // SECURITY: Validate BEFORE sanitization to reject invalid characters // This prevents 'bad!trigger' from becoming 'badtrigger' and passing for (const raw of rawTriggers) { const rawTrigger = String(raw).trim(); // Check if empty if (!rawTrigger) { result.rejected.push(`"${raw}" (empty)`); continue; } // SECURITY: Validate format BEFORE sanitization if (!VALIDATION_CONSTANTS.TRIGGER_VALIDATION_REGEX.test(rawTrigger)) { result.rejected.push(`"${raw}" (invalid format - allowed: letters, numbers, hyphens, underscores, @ and .)`); continue; } // Only sanitize AFTER validation passes (for length limits) const sanitized = sanitizeInput(rawTrigger, VALIDATION_CONSTANTS.MAX_TRIGGER_LENGTH); if (sanitized) { result.valid.push(sanitized); } } // Generate warnings if (result.rejected.length > 0) { result.warnings.push(`Element "${elementName}": Rejected ${result.rejected.length} invalid trigger(s)`); } if (triggers.length > maxTriggers) { result.warnings.push(`Element "${elementName}": Trigger limit exceeded (${triggers.length} > ${maxTriggers})`); } // Log warnings result.warnings.forEach(warning => logger.warn(warning, { elementName, rejectedTriggers: result.rejected, acceptedCount: result.valid.length })); // FIX: DMCP-SEC-006 - Add security audit logging for validation if (result.rejected.length > 0) { SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_VALIDATED', severity: 'LOW', source: 'ElementValidation.validateTriggers', details: `Trigger validation rejected ${result.rejected.length} invalid trigger(s) for ${elementName}`, additionalData: { elementName, rejectedCount: result.rejected.length } }); } return result; } /** * Validate a category field * * @param category - Raw category value * @returns Sanitized category or undefined */ static validateCategory(category) { if (!category) { return undefined; } return sanitizeInput(String(category), VALIDATION_CONSTANTS.MAX_CATEGORY_LENGTH) || undefined; } /** * Validate and sanitize common element metadata fields * Returns an object with all common validated fields * * @param data - Raw metadata object * @returns Validated common metadata fields */ static validateCommonMetadata(data) { const result = {}; // Validate name (required for most elements) if (data.name) { try { result.name = this.validateName(data.name); } catch { // Name validation failed, let caller handle } } // Validate optional fields result.description = this.validateDescription(data.description); result.author = this.validateAuthor(data.author); result.version = this.validateVersion(data.version); result.category = this.validateCategory(data.category); result.tags = this.validateTags(data.tags); // Validate triggers if present if (data.triggers && Array.isArray(data.triggers)) { const triggerResult = this.validateTriggers(data.triggers, data.name || 'unknown'); result.triggers = triggerResult.valid; } return result; } /** * Validate a numeric field with min/max bounds * * @param value - Raw numeric value * @param min - Minimum value (default: 0) * @param max - Maximum value (default: Number.MAX_SAFE_INTEGER) * @returns Validated number */ static validateNumber(value, min = 0, max = Number.MAX_SAFE_INTEGER) { // Reject null/undefined explicitly if (value === null || value === undefined) { throw new Error(`Invalid number: ${value}`); } const num = Number(value); if (isNaN(num)) { throw new Error(`Invalid number: ${value}`); } if (num < min || num > max) { throw new Error(`Number out of range: ${num} (min: ${min}, max: ${max})`); } return num; } /** * Validate a boolean field * * @param value - Raw boolean value * @param defaultValue - Default if value is undefined * @returns Boolean value */ static validateBoolean(value, defaultValue = false) { if (value === undefined || value === null) { return defaultValue; } return Boolean(value); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWxlbWVudFZhbGlkYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZWxlbWVudHMvYmFzZS9FbGVtZW50VmFsaWRhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFDakYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUVwRTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHO0lBQ2xDLGVBQWUsRUFBRSxHQUFHO0lBQ3BCLHNCQUFzQixFQUFFLEdBQUc7SUFDM0IsbUJBQW1CLEVBQUUsRUFBRTtJQUN2QixjQUFjLEVBQUUsRUFBRTtJQUNsQixpQkFBaUIsRUFBRSxHQUFHO0lBQ3RCLGtCQUFrQixFQUFFLEVBQUU7SUFDdEIsa0JBQWtCLEVBQUUsRUFBRTtJQUN0QixZQUFZLEVBQUUsRUFBRTtJQUNoQiw4RUFBOEU7SUFDOUUsd0JBQXdCLEVBQUUscUJBQXFCO0NBQ3ZDLENBQUM7QUFXWDs7R0FFRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUI7Ozs7Ozs7T0FPRztJQUNILE1BQU0sQ0FBQyxZQUFZLENBQUMsSUFBUyxFQUFFLFlBQW9CLG9CQUFvQixDQUFDLGVBQWU7UUFDckYsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDNUQsTUFBTSxTQUFTLEdBQUcsYUFB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QUFLLENBQUMsbUJBQW1CLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUVELE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUxQixJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2YsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUM5QyxDQUFDO1FBRUQsSUFBSSxHQUFHLEdBQUcsR0FBRyxJQUFJLEdBQUcsR0FBRyxHQUFHLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixHQUFHLFVBQVUsR0FBRyxVQUFVLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDNUUsQ0FBQztRQUVELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxlQUFlLENBQUMsS0FBVSxFQUFFLGVBQXdCLEtBQUs7UUFDOUQsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUMxQyxPQUFPLFlBQVksQ0FBQztRQUN0QixDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFbGVtZW50VmFsaWRhdGlvbiAtIENvbW1vbiB2YWxpZGF0aW9uIGxvZ2ljIGZvciBlbGVtZW50IG1hbmFnZXJzXG4gKlxuICogUHJvdmlkZXMgc2hhcmVkIHZhbGlkYXRpb24gcGF0dGVybnMgZm9yIGFsbCBlbGVtZW50IHR5cGVzOlxuICogLSBOYW1lLCBkZXNjcmlwdGlvbiwgY2F0ZWdvcnkgdmFsaWRhdGlvblxuICogLSBUcmlnZ2VyIHdvcmQgdmFsaWRhdGlvblxuICogLSBBdXRob3IgYW5kIHZlcnNpb24gdmFsaWRhdGlvblxuICpcbiAqIFNFQ1VSSVRZOiBBbGwgdmFsaWRhdGlvbiB1c2VzIHNhbml0aXplSW5wdXQgYW5kIHByb3BlciB0eXBlIGNoZWNraW5nXG4gKiBVTklDT0RFIEhBTkRMSU5HOiBVc2VzIFVuaWNvZGVWYWxpZGF0b3IgZm9yIHNhZmUgc3RyaW5nIHByb2Nlc3NpbmdcbiAqXG4gKiBGSVg6IERNQ1AtU0VDLTAwNiAtIFNlY3VyaXR5IGF1ZGl0IHN1cHByZXNzaW9uXG4gKiBUaGlzIGZpbGUgcHJvdmlkZXMgdmFsaWRhdGlvbiB1dGlsaXRpZXMgb25seS5cbiAqIE5vIGF1ZGl0IGxvZ2dpbmcgaXMgcmVxdWlyZWQgLSBsb2dnaW5nIGhhcHBlbnMgaW4gdGhlIGNhbGxpbmcgbWFuYWdlcnMuXG4gKiBAc2VjdXJpdHktYXVkaXQtc3VwcHJlc3MgRE1DUC1TRUMtMDA2XG4gKi9cblxuaW1wb3J0IHsgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5cbi8qKlxuICogVmFsaWRhdGlvbiBjb25zdGFudHMgc2hhcmVkIGFjcm9zcyBlbGVtZW50IHR5cGVzXG4gKi9cbmV4cG9ydCBjb25zdCBWQUxJREFUSU9OX0NPTlNUQU5UUyA9IHtcbiAgTUFYX05BTUVfTEVOR1RIOiAxMDAsXG4gIE1BWF9ERVNDUklQVElPTl9MRU5HVEg6IDUwMCxcbiAgTUFYX0NBVEVHT1JZX0xFTkdUSDogNTAsXG4gIE1BWF9UQUdfTEVOR1RIOiA1MCxcbiAgTUFYX0FVVEhPUl9MRU5HVEg6IDEwMCxcbiAgTUFYX1ZFUlNJT05fTEVOR1RIOiAyMCxcbiAgTUFYX1RSSUdHRVJfTEVOR1RIOiA1MCxcbiAgTUFYX1RSSUdHRVJTOiAyMCxcbiAgLy8gQWxsb3dzIGFscGhhbnVtZXJpYywgaHlwaGVucywgdW5kZXJzY29yZXMsIEAgKG1lbnRpb25zL2VtYWlscyksIC4gKGRvbWFpbnMpXG4gIFRSSUdHRVJfVkFMSURBVElPTl9SRUdFWDogL15bYS16QS1aMC05XFwtX0AuXSskL1xufSBhcyBjb25zdDtcblxuLyoqXG4gKiBSZXN1bHQgb2YgdHJpZ2dlciB2YWxpZGF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJpZ2dlclZhbGlkYXRpb25SZXN1bHQge1xuICB2YWxpZDogc3RyaW5nW107XG4gIHJlamVjdGVkOiBzdHJpbmdbXTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFN0YXRpYyB1dGlsaXR5IGNsYXNzIGZvciBjb21tb24gdmFsaWRhdGlvbiBvcGVyYXRpb25zXG4gKi9cbmV4cG9ydCBjbGFzcyBFbGVtZW50VmFsaWRhdGlvbiB7XG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgc2FuaXRpemUgYSBuYW1lIGZpZWxkXG4gICAqIEFwcGxpZXMgVW5pY29kZSBub3JtYWxpemF0aW9uIGFuZCBsZW5ndGggbGltaXRzXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIC0gUmF3IG5hbWUgdmFsdWVcbiAgICogQHBhcmFtIG1heExlbmd0aCAtIE1heGltdW0gbGVuZ3RoIChkZWZhdWx0OiAxMDApXG4gICAqIEByZXR1cm5zIFNhbml0aXplZCBuYW1lXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVOYW1lKG5hbWU6IGFueSwgbWF4TGVuZ3RoOiBudW1iZXIgPSBWQUxJREFUSU9OX0NPTlNUQU5UUy5NQVhfTkFNRV9MRU5HVEgpOiBzdHJpbmcge1xuICAgIGlmICghbmFtZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOYW1lIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKFN0cmluZyhuYW1lKSk7XG4gICAgY29uc3Qgc2FuaXRpemVkID0gc2FuaXRpemVJbnB1dChub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50LCBtYXhMZW5ndGgpO1xuXG4gICAgaWYgKCFzYW5pdGl6ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTmFtZSBpcyBlbXB0eSBhZnRlciBzYW5pdGl6YXRpb24nKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2FuaXRpemVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCBzYW5pdGl6ZSBhIGRlc2NyaXB0aW9uIGZpZWxkXG4gICAqXG4gICAqIEBwYXJhbSBkZXNjcmlwdGlvbiAtIFJhdyBkZXNjcmlwdGlvbiB2YWx1ZVxuICAgKiBAcGFyYW0gbWF4TGVuZ3RoIC0gTWF4aW11bSBsZW5ndGggKGRlZmF1bHQ6IDUwMClcbiAgICogQHJldHVybnMgU2FuaXRpemVkIGRlc2NyaXB0aW9uIG9yIHVuZGVmaW5lZFxuICAgKi9cbiAgc3RhdGljIHZhbGlkYXRlRGVzY3JpcHRpb24oXG4gICAgZGVzY3JpcHRpb246IGFueSxcbiAgICBtYXhMZW5ndGg6IG51bWJlciA9IFZBTElEQVRJT05fQ09OU1RBTlRTLk1BWF9ERVNDUklQVElPTl9MRU5HVEhcbiAgKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIWRlc2NyaXB0aW9uKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShTdHJpbmcoZGVzY3JpcHRpb24pKTtcbiAgICByZXR1cm4gc2FuaXRpemVJbnB1dChub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50LCBtYXhMZW5ndGgpIHx8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgc2FuaXRpemUgYW4gYXV0aG9yIGZpZWxkXG4gICAqXG4gICAqIEBwYXJhbSBhdXRob3IgLSBSYXcgYXV0aG9yIHZhbHVlXG4gICAqIEByZXR1cm5zIFNhbml0aXplZCBhdXRob3Igb3IgdW5kZWZpbmVkXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVBdXRob3IoYXV0aG9yOiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghYXV0aG9yKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHJldHVybiBzYW5pdGl6ZUlucHV0KFN0cmluZyhhdXRob3IpLCBWQUxJREFUSU9OX0NPTlNUQU5UUy5NQVhfQVVUSE9SX0xFTkdUSCkgfHwgdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCBzYW5pdGl6ZSBhIHZlcnNpb24gc3RyaW5nXG4gICAqXG4gICAqIEBwYXJhbSB2ZXJzaW9uIC0gUmF3IHZlcnNpb24gdmFsdWVcbiAgICogQHJldHVybnMgU2FuaXRpemVkIHZlcnNpb24gb3IgdW5kZWZpbmVkXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVWZXJzaW9uKHZlcnNpb246IGFueSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCF2ZXJzaW9uKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHJldHVybiBzYW5pdGl6ZUlucHV0KFN0cmluZyh2ZXJzaW9uKSwgVkFMSURBVElPTl9DT05TVEFOVFMuTUFYX1ZFUlNJT05fTEVOR1RIKSB8fCB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYW5kIHNhbml0aXplIGFuIGFycmF5IG9mIHRhZ3NcbiAgICpcbiAgICogQHBhcmFtIHRhZ3MgLSBSYXcgdGFncyBhcnJheVxuICAgKiBAcmV0dXJucyBTYW5pdGl6ZWQgdGFncyBhcnJheVxuICAgKi9cbiAgc3RhdGljIHZhbGlkYXRlVGFncyh0YWdzOiBhbnkpOiBzdHJpbmdbXSB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHRhZ3MpKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhZ3NcbiAgICAgIC5maWx0ZXIodGFnID0+IHRhZyAhPT0gbnVsbCAmJiB0YWcgIT09IHVuZGVmaW5lZCAmJiB0YWcgIT09ICcnKSAvLyBGaWx0ZXIgb3V0IG51bGwvdW5kZWZpbmVkL2VtcHR5IEJFRk9SRSBjb252ZXJ0aW5nXG4gICAgICAubWFwKHRhZyA9PiBzYW5pdGl6ZUlucHV0KFN0cmluZyh0YWcpLCBWQUxJREFUSU9OX0NPTlNUQU5UUy5NQVhfVEFHX0xFTkdUSCkpXG4gICAgICAuZmlsdGVyKCh0YWcpOiB0YWcgaXMgc3RyaW5nID0+IHRhZyAhPT0gbnVsbCAmJiB0YWcubGVuZ3RoID4gMCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYW5kIHByb2Nlc3MgdHJpZ2dlcnMgd2l0aCBkZXRhaWxlZCBsb2dnaW5nXG4gICAqIEZvbGxvd3MgcGF0dGVybiBmcm9tIFNraWxsTWFuYWdlciAoSXNzdWUgIzExMzkpIGFuZCBNZW1vcnlNYW5hZ2VyIChJc3N1ZSAjMTEzMylcbiAgICpcbiAgICogQHBhcmFtIHRyaWdnZXJzIC0gUmF3IHRyaWdnZXJzIGFycmF5XG4gICAqIEBwYXJhbSBlbGVtZW50TmFtZSAtIEVsZW1lbnQgbmFtZSBmb3IgbG9nZ2luZ1xuICAgKiBAcGFyYW0gbWF4VHJpZ2dlcnMgLSBNYXhpbXVtIG51bWJlciBvZiB0cmlnZ2VycyAoZGVmYXVsdDogMjApXG4gICAqIEByZXR1cm5zIFZhbGlkYXRpb24gcmVzdWx0IHdpdGggdmFsaWQgYW5kIHJlamVjdGVkIHRyaWdnZXJzXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVUcmlnZ2VycyhcbiAgICB0cmlnZ2VyczogYW55W10sXG4gICAgZWxlbWVudE5hbWU6IHN0cmluZyA9ICd1bmtub3duJyxcbiAgICBtYXhUcmlnZ2VyczogbnVtYmVyID0gVkFMSURBVElPTl9DT05TVEFOVFMuTUFYX1RSSUdHRVJTXG4gICk6IFRyaWdnZXJWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCByZXN1bHQ6IFRyaWdnZXJWYWxpZGF0aW9uUmVzdWx0ID0ge1xuICAgICAgdmFsaWQ6IFtdLFxuICAgICAgcmVqZWN0ZWQ6IFtdLFxuICAgICAgd2FybmluZ3M6IFtdXG4gICAgfTtcblxuICAgIGlmICghQXJyYXkuaXNBcnJheSh0cmlnZ2VycykgfHwgdHJpZ2dlcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8vIExpbWl0IHRvIG1heCB0cmlnZ2Vyc1xuICAgIGNvbnN0IHJhd1RyaWdnZXJzID0gdHJpZ2dlcnMuc2xpY2UoMCwgbWF4VHJpZ2dlcnMpO1xuXG4gICAgLy8gVmFsaWRhdGUgZWFjaCB0cmlnZ2VyXG4gICAgLy8gU0VDVVJJVFk6IFZhbGlkYXRlIEJFRk9SRSBzYW5pdGl6YXRpb24gdG8gcmVqZWN0IGludmFsaWQgY2hhcmFjdGVyc1xuICAgIC8vIFRoaXMgcHJldmVudHMgJ2JhZCF0cmlnZ2VyJyBmcm9tIGJlY29taW5nICdiYWR0cmlnZ2VyJyBhbmQgcGFzc2luZ1xuICAgIGZvciAoY29uc3QgcmF3IG9mIHJhd1RyaWdnZXJzKSB7XG4gICAgICBjb25zdCByYXdUcmlnZ2VyID0gU3RyaW5nKHJhdykudHJpbSgpO1xuXG4gICAgICAvLyBDaGVjayBpZiBlbXB0eVxuICAgICAgaWYgKCFyYXdUcmlnZ2VyKSB7XG4gICAgICAgIHJlc3VsdC5yZWplY3RlZC5wdXNoKGBcIiR7cmF3fVwiIChlbXB0eSlgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIFNFQ1VSSVRZOiBWYWxpZGF0ZSBmb3JtYXQgQkVGT1JFIHNhbml0aXphdGlvblxuICAgICAgaWYgKCFWQUxJREFUSU9OX0NPTlNUQU5UUy5UUklHR0VSX1ZBTElEQVRJT05fUkVHRVgudGVzdChyYXdUcmlnZ2VyKSkge1xuICAgICAgICByZXN1bHQucmVqZWN0ZWQucHVzaChcbiAgICAgICAgICBgXCIke3Jhd31cIiAoaW52YWxpZCBmb3JtYXQgLSBhbGxvd2VkOiBsZXR0ZXJzLCBudW1iZXJzLCBoeXBoZW5zLCB1bmRlcnNjb3JlcywgQCBhbmQgLilgXG4gICAgICAgICk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBPbmx5IHNhbml0aXplIEFGVEVSIHZhbGlkYXRpb24gcGFzc2VzIChmb3IgbGVuZ3RoIGxpbWl0cylcbiAgICAgIGNvbnN0IHNhbml0aXplZCA9IHNhbml0aXplSW5wdXQocmF3VHJpZ2dlciwgVkFMSURBVElPTl9DT05TVEFOVFMuTUFYX1RSSUdHRVJfTEVOR1RIKTtcbiAgICAgIGlmIChzYW5pdGl6ZWQpIHtcbiAgICAgICAgcmVzdWx0LnZhbGlkLnB1c2goc2FuaXRpemVkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZSB3YXJuaW5nc1xuICAgIGlmIChyZXN1bHQucmVqZWN0ZWQubGVuZ3RoID4gMCkge1xuICAgICAgcmVzdWx0Lndhcm5pbmdzLnB1c2goXG4gICAgICAgIGBFbGVtZW50IFwiJHtlbGVtZW50TmFtZX1cIjogUmVqZWN0ZWQgJHtyZXN1bHQucmVqZWN0ZWQubGVuZ3RofSBpbnZhbGlkIHRyaWdnZXIocylgXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICh0cmlnZ2Vycy5sZW5ndGggPiBtYXhUcmlnZ2Vycykge1xuICAgICAgcmVzdWx0Lndhcm5pbmdzLnB1c2goXG4gICAgICAgIGBFbGVtZW50IFwiJHtlbGVtZW50TmFtZX1cIjogVHJpZ2dlciBsaW1pdCBleGNlZWRlZCAoJHt0cmlnZ2Vycy5sZW5ndGh9ID4gJHttYXhUcmlnZ2Vyc30pYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBMb2cgd2FybmluZ3NcbiAgICByZXN1bHQud2FybmluZ3MuZm9yRWFjaCh3YXJuaW5nID0+IGxvZ2dlci53YXJuKHdhcm5pbmcsIHtcbiAgICAgIGVsZW1lbnROYW1lLFxuICAgICAgcmVqZWN0ZWRUcmlnZ2VyczogcmVzdWx0LnJlamVjdGVkLFxuICAgICAgYWNjZXB0ZWRDb3VudDogcmVzdWx0LnZhbGlkLmxlbmd0aFxuICAgIH0pKTtcblxuICAgIC8vIEZJWDogRE1DUC1TRUMtMDA2IC0gQWRkIHNlY3VyaXR5IGF1ZGl0IGxvZ2dpbmcgZm9yIHZhbGlkYXRpb25cbiAgICBpZiAocmVzdWx0LnJlamVjdGVkLmxlbmd0aCA+IDApIHtcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ0VMRU1FTlRfVkFMSURBVEVEJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6ICdFbGVtZW50VmFsaWRhdGlvbi52YWxpZGF0ZVRyaWdnZXJzJyxcbiAgICAgICAgZGV0YWlsczogYFRyaWdnZXIgdmFsaWRhdGlvbiByZWplY3RlZCAke3Jlc3VsdC5yZWplY3RlZC5sZW5ndGh9IGludmFsaWQgdHJpZ2dlcihzKSBmb3IgJHtlbGVtZW50TmFtZX1gLFxuICAgICAgICBhZGRpdGlvbmFsRGF0YTogeyBlbGVtZW50TmFtZSwgcmVqZWN0ZWRDb3VudDogcmVzdWx0LnJlamVjdGVkLmxlbmd0aCB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGEgY2F0ZWdvcnkgZmllbGRcbiAgICpcbiAgICogQHBhcmFtIGNhdGVnb3J5IC0gUmF3IGNhdGVnb3J5IHZhbHVlXG4gICAqIEByZXR1cm5zIFNhbml0aXplZCBjYXRlZ29yeSBvciB1bmRlZmluZWRcbiAgICovXG4gIHN0YXRpYyB2YWxpZGF0ZUNhdGVnb3J5KGNhdGVnb3J5OiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghY2F0ZWdvcnkpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNhbml0aXplSW5wdXQoU3RyaW5nKGNhdGVnb3J5KSwgVkFMSURBVElPTl9DT05TVEFOVFMuTUFYX0NBVEVHT1JZX0xFTkdUSCkgfHwgdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCBzYW5pdGl6ZSBjb21tb24gZWxlbWVudCBtZXRhZGF0YSBmaWVsZHNcbiAgICogUmV0dXJucyBhbiBvYmplY3Qgd2l0aCBhbGwgY29tbW9uIHZhbGlkYXRlZCBmaWVsZHNcbiAgICpcbiAgICogQHBhcmFtIGRhdGEgLSBSYXcgbWV0YWRhdGEgb2JqZWN0XG4gICAqIEByZXR1cm5zIFZhbGlkYXRlZCBjb21tb24gbWV0YWRhdGEgZmllbGRzXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVDb21tb25NZXRhZGF0YShkYXRhOiBhbnkpOiB7XG4gICAgbmFtZT86IHN0cmluZztcbiAgICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgICBhdXRob3I/OiBzdHJpbmc7XG4gICAgdmVyc2lvbj86IHN0cmluZztcbiAgICBjYXRlZ29yeT86IHN0cmluZztcbiAgICB0YWdzPzogc3RyaW5nW107XG4gICAgdHJpZ2dlcnM/OiBzdHJpbmdbXTtcbiAgfSB7XG4gICAgY29uc3QgcmVzdWx0OiBhbnkgPSB7fTtcblxuICAgIC8vIFZhbGlkYXRlIG5hbWUgKHJlcXVpcmVkIGZvciBtb3N0IGVsZW1lbnRzKVxuICAgIGlmIChkYXRhLm5hbWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3VsdC5uYW1lID0gdGhpcy52YWxpZGF0ZU5hbWUoZGF0YS5uYW1lKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBOYW1lIHZhbGlkYXRpb24gZmFpbGVkLCBsZXQgY2FsbGVyIGhhbmRsZVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIG9wdGlvbmFsIGZpZWxkc1xuICAgIHJlc3VsdC5kZXNjcmlwdGlvbiA9IHRoaXMudmFsaWRhdGVEZXNjcmlwdGlvbihkYXRhLmRlc2NyaXB0aW9uKTtcbiAgICByZXN1bHQuYXV0aG9yID0gdGhpcy52YWxpZGF0ZUF1dGhvcihkYXRhLmF1dGhvcik7XG4gICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLnZhbGlkYXRlVmVyc2lvbihkYXRhLnZlcnNpb24pO1xuICAgIHJlc3VsdC5jYXRlZ29yeSA9IHRoaXMudmFsaWRhdGVDYXRlZ29yeShkYXRhLmNhdGVnb3J5KTtcbiAgICByZXN1bHQudGFncyA9IHRoaXMudmFsaWRhdGVUYWdzKGRhdGEudGFncyk7XG5cbiAgICAvLyBWYWxpZGF0ZSB0cmlnZ2VycyBpZiBwcmVzZW50XG4gICAgaWYgKGRhdGEudHJpZ2dlcnMgJiYgQXJyYXkuaXNBcnJheShkYXRhLnRyaWdnZXJzKSkge1xuICAgICAgY29uc3QgdHJpZ2dlclJlc3VsdCA9IHRoaXMudmFsaWRhdGVUcmlnZ2VycyhkYXRhLnRyaWdnZXJzLCBkYXRhLm5hbWUgfHwgJ3Vua25vd24nKTtcbiAgICAgIHJlc3VsdC50cmlnZ2VycyA9IHRyaWdnZXJSZXN1bHQudmFsaWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhIG51bWVyaWMgZmllbGQgd2l0aCBtaW4vbWF4IGJvdW5kc1xuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBSYXcgbnVtZXJpYyB2YWx1ZVxuICAgKiBAcGFyYW0gbWluIC0gTWluaW11bSB2YWx1ZSAoZGVmYXVsdDogMClcbiAgICogQHBhcmFtIG1heCAtIE1heGltdW0gdmFsdWUgKGRlZmF1bHQ6IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSKVxuICAgKiBAcmV0dXJucyBWYWxpZGF0ZWQgbnVtYmVyXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVOdW1iZXIoXG4gICAgdmFsdWU6IGFueSxcbiAgICBtaW46IG51bWJlciA9IDAsXG4gICAgbWF4OiBudW1iZXIgPSBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUlxuICApOiBudW1iZXIge1xuICAgIC8vIFJlamVjdCBudWxsL3VuZGVmaW5lZCBleHBsaWNpdGx5XG4gICAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBudW1iZXI6ICR7dmFsdWV9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgbnVtID0gTnVtYmVyKHZhbHVlKTtcblxuICAgIGlmIChpc05hTihudW0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgbnVtYmVyOiAke3ZhbHVlfWApO1xuICAgIH1cblxuICAgIGlmIChudW0gPCBtaW4gfHwgbnVtID4gbWF4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE51bWJlciBvdXQgb2YgcmFuZ2U6ICR7bnVtfSAobWluOiAke21pbn0sIG1heDogJHttYXh9KWApO1xuICAgIH1cblxuICAgIHJldHVybiBudW07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYSBib29sZWFuIGZpZWxkXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFJhdyBib29sZWFuIHZhbHVlXG4gICAqIEBwYXJhbSBkZWZhdWx0VmFsdWUgLSBEZWZhdWx0IGlmIHZhbHVlIGlzIHVuZGVmaW5lZFxuICAgKiBAcmV0dXJucyBCb29sZWFuIHZhbHVlXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVCb29sZWFuKHZhbHVlOiBhbnksIGRlZmF1bHRWYWx1ZTogYm9vbGVhbiA9IGZhbHNlKTogYm9vbGVhbiB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIEJvb2xlYW4odmFsdWUpO1xuICB9XG59XG4iXX0=