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.

165 lines 25.5 kB
import yaml from 'js-yaml'; import { z } from 'zod'; import { logger } from '../utils/logger.js'; import DOMPurify from 'dompurify'; import { JSDOM } from 'jsdom'; import { SECURITY_LIMITS } from './constants.js'; const PersonaMetadataSchema = z.object({ name: z.string().min(1).max(100), description: z.string().min(1).max(1000), unique_id: z.string().optional(), author: z.string().max(50).optional(), triggers: z.array(z.string().max(50)).max(20).optional(), version: z.string().regex(/^\d+\.\d+\.\d+$/).optional(), category: z.enum(['creative', 'professional', 'educational', 'gaming', 'personal']).optional(), age_rating: z.enum(['all', '13+', '18+']).optional(), content_flags: z.array(z.string()).optional(), ai_generated: z.boolean().optional(), generation_method: z.string().max(50).optional(), price: z.string().max(20).optional(), license: z.string().max(100).optional(), created_date: z.string().optional() }); export class YamlValidator { // YAML bomb detection limits - extracted from Issue #164 review feedback static YAML_BOMB_LIMITS = { MAX_ANCHORS: 10, // Maximum allowed anchor definitions (&name) MAX_ALIASES: 20, // Maximum allowed alias references (*name) MAX_MERGE_KEYS: 5, // Maximum allowed merge key operations (<<:) MAX_DOCUMENTS: 3 // Maximum allowed documents in a single YAML }; // Static cache for DOMPurify to improve performance static purifyWindow = null; static purify = null; static parsePersonaMetadataSafely(yamlContent) { if (!yamlContent || typeof yamlContent !== 'string') { throw new Error('YAML content must be a non-empty string'); } // Size check if (yamlContent.length > SECURITY_LIMITS.MAX_YAML_LENGTH) { throw new Error(`YAML content too large: ${yamlContent.length} bytes (max: ${SECURITY_LIMITS.MAX_YAML_LENGTH})`); } // Check for dangerous tags - expanded from Issue #164 const dangerousTags = [ '!!js/', '!!python/', '!!ruby/', '!!perl/', '!!php/', '!!java', '!!javax', '!!com.sun', '!!exec', '!!eval', '!!new', '!!construct', '!!apply', '!!call', '!!invoke', '!!binary', '!!merge' ]; for (const tag of dangerousTags) { if (yamlContent.includes(tag)) { throw new Error(`Dangerous YAML tag detected: ${tag}`); } } // Enhanced YAML bomb protection - Issue #164 const anchorCount = (yamlContent.match(/&\w+/g) || []).length; const aliasCount = (yamlContent.match(/\*\w+/g) || []).length; const mergeKeyCount = (yamlContent.match(/<<:/g) || []).length; const documentCount = (yamlContent.match(/^---/gm) || []).length; if (anchorCount > this.YAML_BOMB_LIMITS.MAX_ANCHORS || aliasCount > this.YAML_BOMB_LIMITS.MAX_ALIASES || mergeKeyCount > this.YAML_BOMB_LIMITS.MAX_MERGE_KEYS || documentCount > this.YAML_BOMB_LIMITS.MAX_DOCUMENTS) { throw new Error(`Potential YAML bomb detected: anchors=${anchorCount}, aliases=${aliasCount}, merges=${mergeKeyCount}, documents=${documentCount}`); } // Check for nested tag combinations const nestedTagPattern = /[&*]\w+\s*!!/; if (nestedTagPattern.test(yamlContent)) { throw new Error('Dangerous nested YAML tag combination detected'); } try { // Use safe load with restricted schema const rawData = yaml.load(yamlContent, { schema: yaml.CORE_SCHEMA, // No functions, only basic types onWarning: (warning) => { logger.warn('YAML parsing warning:', warning); } }); // Validate against schema const validatedData = PersonaMetadataSchema.parse(rawData); // Additional sanitization return this.sanitizeMetadata(validatedData); } catch (error) { if (error instanceof Error && error.name === 'YAMLException') { throw new Error(`Invalid YAML syntax: ${error.message}`); } throw new Error(`Invalid persona metadata: ${error instanceof Error ? error.message : String(error)}`); } } static sanitizeMetadata(data) { const sanitized = { ...data }; // Sanitize string fields const stringFields = ['name', 'description', 'author', 'unique_id']; for (const field of stringFields) { if (sanitized[field]) { sanitized[field] = this.sanitizeString(sanitized[field]); } } // Sanitize array fields if (sanitized.triggers) { sanitized.triggers = sanitized.triggers.map((t) => this.sanitizeString(t)); } return sanitized; } /** * Initialize DOMPurify instance if not already initialized */ static initializePurify() { if (!this.purifyWindow || !this.purify) { const dom = new JSDOM(''); this.purifyWindow = dom.window; this.purify = DOMPurify(this.purifyWindow); } } /** * Sanitize string input using DOMPurify to prevent XSS attacks * This replaces the regex-based approach with a more robust solution */ static sanitizeString(input) { // Limit input length to prevent DoS if (input.length > 10000) { input = input.substring(0, 10000); } // Initialize DOMPurify if needed this.initializePurify(); // Use DOMPurify with strict configuration // ALLOWED_TAGS: [] strips all HTML tags // ALLOWED_ATTR: [] strips all attributes // FORBID_TAGS/FORBID_ATTR provide additional protection let sanitized = this.purify.sanitize(input, { ALLOWED_TAGS: [], // Strip all HTML tags ALLOWED_ATTR: [], // Strip all attributes FORBID_TAGS: ['style', 'script', 'iframe', 'object', 'embed', 'link'], FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'style', 'href', 'src'] }); // Additional protection against command injection patterns // These patterns might not be caught by DOMPurify const commandInjectionPatterns = [ /`[^`]{0,1000}`/g, // Backtick expressions /\$\([^)]{0,1000}\)/g, // Command substitution /\$\{[^}]{0,1000}\}/g, // Variable expansion /\\x[0-9a-fA-F]{2}/g, // Hex escapes /\\u[0-9a-fA-F]{4}/g, // Unicode escapes /\\[0-7]{1,3}/g // Octal escapes ]; for (const pattern of commandInjectionPatterns) { sanitized = sanitized.replace(pattern, ''); } // Remove null bytes and normalize whitespace sanitized = sanitized // eslint-disable-next-line no-control-regex -- Intentionally removing null bytes for security .replaceAll(/\u0000/g, '') // NOSONAR - Remove null bytes for security .replaceAll(/[\r\n]+/g, ' ') // Replace newlines with spaces .trim(); return sanitized; } /** * Reset static DOMPurify cache (useful for long-running processes) */ static resetCache() { this.purifyWindow = null; this.purify = null; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieWFtbFZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZWN1cml0eS95YW1sVmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sSUFBSSxNQUFNLFNBQVMsQ0FBQztBQUMzQixPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLFNBQVMsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUM5QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFakQsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3JDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7SUFDaEMsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQztJQUN4QyxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNoQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDckMsUUFBUSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDeEQsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxRQUFRLEVB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RixDQUFDLENBQUM7UUFFSCwyREFBMkQ7UUFDM0Qsa0RBQWtEO1FBQ2xELE1BQU0sd0JBQXdCLEdBQUc7WUFDL0IsaUJBQWlCLEVBQVksdUJBQXVCO1lBQ3BELHFCQUFxQixFQUFRLHVCQUF1QjtZQUNwRCxxQkFBcUIsRUFBUSxxQkFBcUI7WUFDbEQsb0JBQW9CLEVBQVMsY0FBYztZQUMzQyxvQkFBb0IsRUFBUyxrQkFBa0I7WUFDL0MsZUFBZSxDQUFjLGdCQUFnQjtTQUM5QyxDQUFDO1FBRUYsS0FBSyxNQUFNLE9BQU8sSUFBSSx3QkFBd0IsRUFBRSxDQUFDO1lBQy9DLFNBQVMsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQztRQUM3QyxDQUFDO1FBRUQsNkNBQTZDO1FBQzdDLFNBQVMsR0FBRyxTQUFTO1lBQ25CLDhGQUE4RjthQUM3RixVQUFVLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFVLDJDQUEyQzthQUM5RSxVQUFVLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFNLCtCQUErQjthQUNoRSxJQUFJLEVBQUUsQ0FBQztRQUVWLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxVQUFVO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO0lBQ3JCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeWFtbCBmcm9tICdqcy15YW1sJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xuaW1wb3J0IHsgU0VDVVJJVFlfTElNSVRTIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xuXG5jb25zdCBQZXJzb25hTWV0YWRhdGFTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIG5hbWU6IHouc3RyaW5nKCkubWluKDEpLm1heCgxMDApLFxuICBkZXNjcmlwdGlvbjogei5zdHJpbmcoKS5taW4oMSkubWF4KDEwMDApLFxuICB1bmlxdWVfaWQ6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgYXV0aG9yOiB6LnN0cmluZygpLm1heCg1MCkub3B0aW9uYWwoKSxcbiAgdHJpZ2dlcnM6IHouYXJyYXkoei5zdHJpbmcoKS5tYXgoNTApKS5tYXgoMjApLm9wdGlvbmFsKCksXG4gIHZlcnNpb246IHouc3RyaW5nKCkucmVnZXgoL15cXGQrXFwuXFxkK1xcLlxcZCskLykub3B0aW9uYWwoKSxcbiAgY2F0ZWdvcnk6IHouZW51bShbJ2NyZWF0aXZlJywgJ3Byb2Zlc3Npb25hbCcsICdlZHVjYXRpb25hbCcsICdnYW1pbmcnLCAncGVyc29uYWwnXSkub3B0aW9uYWwoKSxcbiAgYWdlX3JhdGluZzogei5lbnVtKFsnYWxsJywgJzEzKycsICcxOCsnXSkub3B0aW9uYWwoKSxcbiAgY29udGVudF9mbGFnczogei5hcnJheSh6LnN0cmluZygpKS5vcHRpb25hbCgpLFxuICBhaV9nZW5lcmF0ZWQ6IHouYm9vbGVhbigpLm9wdGlvbmFsKCksXG4gIGdlbmVyYXRpb25fbWV0aG9kOiB6LnN0cmluZygpLm1heCg1MCkub3B0aW9uYWwoKSxcbiAgcHJpY2U6IHouc3RyaW5nKCkubWF4KDIwKS5vcHRpb25hbCgpLFxuICBsaWNlbnNlOiB6LnN0cmluZygpLm1heCgxMDApLm9wdGlvbmFsKCksXG4gIGNyZWF0ZWRfZGF0ZTogei5zdHJpbmcoKS5vcHRpb25hbCgpXG59KTtcblxuLy8gVHlwZSBkZWNsYXJhdGlvbnMgZm9yIGJldHRlciB0eXBlIHNhZmV0eVxudHlwZSBET01QdXJpZnlJbnN0YW5jZSA9IFJldHVyblR5cGU8dHlwZW9mIERPTVB1cmlmeT47XG5cbmV4cG9ydCBjbGFzcyBZYW1sVmFsaWRhdG9yIHtcbiAgLy8gWUFNTCBib21iIGRldGVjdGlvbiBsaW1pdHMgLSBleHRyYWN0ZWQgZnJvbSBJc3N1ZSAjMTY0IHJldmlldyBmZWVkYmFja1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBZQU1MX0JPTUJfTElNSVRTID0ge1xuICAgIE1BWF9BTkNIT1JTOiAxMCwgICAgICAgIC8vIE1heGltdW0gYWxsb3dlZCBhbmNob3IgZGVmaW5pdGlvbnMgKCZuYW1lKVxuICAgIE1BWF9BTElBU0VTOiAyMCwgICAgICAgIC8vIE1heGltdW0gYWxsb3dlZCBhbGlhcyByZWZlcmVuY2VzICgqbmFtZSlcbiAgICBNQVhfTUVSR0VfS0VZUzogNSwgICAgICAvLyBNYXhpbXVtIGFsbG93ZWQgbWVyZ2Uga2V5IG9wZXJhdGlvbnMgKDw8OilcbiAgICBNQVhfRE9DVU1FTlRTOiAzICAgICAgICAvLyBNYXhpbXVtIGFsbG93ZWQgZG9jdW1lbnRzIGluIGEgc2luZ2xlIFlBTUxcbiAgfTtcblxuICAvLyBTdGF0aWMgY2FjaGUgZm9yIERPTVB1cmlmeSB0byBpbXByb3ZlIHBlcmZvcm1hbmNlXG4gIHByaXZhdGUgc3RhdGljIHB1cmlmeVdpbmRvdzogYW55ID0gbnVsbDtcbiAgcHJpdmF0ZSBzdGF0aWMgcHVyaWZ5OiBET01QdXJpZnlJbnN0YW5jZSB8IG51bGwgPSBudWxsO1xuXG4gIHN0YXRpYyBwYXJzZVBlcnNvbmFNZXRhZGF0YVNhZmVseSh5YW1sQ29udGVudDogc3RyaW5nKTogYW55IHtcbiAgICBpZiAoIXlhbWxDb250ZW50IHx8IHR5cGVvZiB5YW1sQ29udGVudCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignWUFNTCBjb250ZW50IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG4gICAgfVxuICAgIFxuICAgIC8vIFNpemUgY2hlY2tcbiAgICBpZiAoeWFtbENvbnRlbnQubGVuZ3RoID4gU0VDVVJJVFlfTElNSVRTLk1BWF9ZQU1MX0xFTkdUSCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBZQU1MIGNvbnRlbnQgdG9vIGxhcmdlOiAke3lhbWxDb250ZW50Lmxlbmd0aH0gYnl0ZXMgKG1heDogJHtTRUNVUklUWV9MSU1JVFMuTUFYX1lBTUxfTEVOR1RIfSlgKTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ2hlY2sgZm9yIGRhbmdlcm91cyB0YWdzIC0gZXhwYW5kZWQgZnJvbSBJc3N1ZSAjMTY0XG4gICAgY29uc3QgZGFuZ2Vyb3VzVGFncyA9IFtcbiAgICAgICchIWpzLycsICchIXB5dGhvbi8nLCAnISFydWJ5LycsICchIXBlcmwvJywgJyEhcGhwLycsXG4gICAgICAnISFqYXZhJywgJyEhamF2YXgnLCAnISFjb20uc3VuJyxcbiAgICAgICchIWV4ZWMnLCAnISFldmFsJywgJyEhbmV3JywgJyEhY29uc3RydWN0JywgJyEhYXBwbHknLFxuICAgICAgJyEhY2FsbCcsICchIWludm9rZScsICchIWJpbmFyeScsICchIW1lcmdlJ1xuICAgIF07XG4gICAgXG4gICAgZm9yIChjb25zdCB0YWcgb2YgZGFuZ2Vyb3VzVGFncykge1xuICAgICAgaWYgKHlhbWxDb250ZW50LmluY2x1ZGVzKHRhZykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBEYW5nZXJvdXMgWUFNTCB0YWcgZGV0ZWN0ZWQ6ICR7dGFnfWApO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBFbmhhbmNlZCBZQU1MIGJvbWIgcHJvdGVjdGlvbiAtIElzc3VlICMxNjRcbiAgICBjb25zdCBhbmNob3JDb3VudCA9ICh5YW1sQ29udGVudC5tYXRjaCgvJlxcdysvZykgfHwgW10pLmxlbmd0aDtcbiAgICBjb25zdCBhbGlhc0NvdW50ID0gKHlhbWxDb250ZW50Lm1hdGNoKC9cXCpcXHcrL2cpIHx8IFtdKS5sZW5ndGg7XG4gICAgY29uc3QgbWVyZ2VLZXlDb3VudCA9ICh5YW1sQ29udGVudC5tYXRjaCgvPDw6L2cpIHx8IFtdKS5sZW5ndGg7XG4gICAgY29uc3QgZG9jdW1lbnRDb3VudCA9ICh5YW1sQ29udGVudC5tYXRjaCgvXi0tLS9nbSkgfHwgW10pLmxlbmd0aDtcbiAgICBcbiAgICBpZiAoYW5jaG9yQ291bnQgPiB0aGlzLllBTUxfQk9NQl9MSU1JVFMuTUFYX0FOQ0hPUlMgfHwgXG4gICAgICAgIGFsaWFzQ291bnQgPiB0aGlzLllBTUxfQk9NQl9MSU1JVFMuTUFYX0FMSUFTRVMgfHwgXG4gICAgICAgIG1lcmdlS2V5Q291bnQgPiB0aGlzLllBTUxfQk9NQl9MSU1JVFMuTUFYX01FUkdFX0tFWVMgfHwgXG4gICAgICAgIGRvY3VtZW50Q291bnQgPiB0aGlzLllBTUxfQk9NQl9MSU1JVFMuTUFYX0RPQ1VNRU5UUykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBQb3RlbnRpYWwgWUFNTCBib21iIGRldGVjdGVkOiBhbmNob3JzPSR7YW5jaG9yQ291bnR9LCBhbGlhc2VzPSR7YWxpYXNDb3VudH0sIG1lcmdlcz0ke21lcmdlS2V5Q291bnR9LCBkb2N1bWVudHM9JHtkb2N1bWVudENvdW50fWApO1xuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBmb3IgbmVzdGVkIHRhZyBjb21iaW5hdGlvbnNcbiAgICBjb25zdCBuZXN0ZWRUYWdQYXR0ZXJuID0gL1smKl1cXHcrXFxzKiEhLztcbiAgICBpZiAobmVzdGVkVGFnUGF0dGVybi50ZXN0KHlhbWxDb250ZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEYW5nZXJvdXMgbmVzdGVkIFlBTUwgdGFnIGNvbWJpbmF0aW9uIGRldGVjdGVkJyk7XG4gICAgfVxuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBVc2Ugc2FmZSBsb2FkIHdpdGggcmVzdHJpY3RlZCBzY2hlbWFcbiAgICAgIGNvbnN0IHJhd0RhdGEgPSB5YW1sLmxvYWQoeWFtbENvbnRlbnQsIHtcbiAgICAgICAgc2NoZW1hOiB5YW1sLkNPUkVfU0NIRU1BLCAvLyBObyBmdW5jdGlvbnMsIG9ubHkgYmFzaWMgdHlwZXNcbiAgICAgICAgb25XYXJuaW5nOiAod2FybmluZykgPT4ge1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdZQU1MIHBhcnNpbmcgd2FybmluZzonLCB3YXJuaW5nKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIC8vIFZhbGlkYXRlIGFnYWluc3Qgc2NoZW1hXG4gICAgICBjb25zdCB2YWxpZGF0ZWREYXRhID0gUGVyc29uYU1ldGFkYXRhU2NoZW1hLnBhcnNlKHJhd0RhdGEpO1xuICAgICAgXG4gICAgICAvLyBBZGRpdGlvbmFsIHNhbml0aXphdGlvblxuICAgICAgcmV0dXJuIHRoaXMuc2FuaXRpemVNZXRhZGF0YSh2YWxpZGF0ZWREYXRhKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubmFtZSA9PT0gJ1lBTUxFeGNlcHRpb24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBZQU1MIHN5bnRheDogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBlcnNvbmEgbWV0YWRhdGE6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHNhbml0aXplTWV0YWRhdGEoZGF0YTogYW55KTogYW55IHtcbiAgICBjb25zdCBzYW5pdGl6ZWQgPSB7IC4uLmRhdGEgfTtcbiAgICBcbiAgICAvLyBTYW5pdGl6ZSBzdHJpbmcgZmllbGRzXG4gICAgY29uc3Qgc3RyaW5nRmllbGRzID0gWyduYW1lJywgJ2Rlc2NyaXB0aW9uJywgJ2F1dGhvcicsICd1bmlxdWVfaWQnXTtcbiAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHN0cmluZ0ZpZWxkcykge1xuICAgICAgaWYgKHNhbml0aXplZFtmaWVsZF0pIHtcbiAgICAgICAgc2FuaXRpemVkW2ZpZWxkXSA9IHRoaXMuc2FuaXRpemVTdHJpbmcoc2FuaXRpemVkW2ZpZWxkXSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIFNhbml0aXplIGFycmF5IGZpZWxkc1xuICAgIGlmIChzYW5pdGl6ZWQudHJpZ2dlcnMpIHtcbiAgICAgIHNhbml0aXplZC50cmlnZ2VycyA9IHNhbml0aXplZC50cmlnZ2Vycy5tYXAoKHQ6IHN0cmluZykgPT4gdGhpcy5zYW5pdGl6ZVN0cmluZyh0KSk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBzYW5pdGl6ZWQ7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSBET01QdXJpZnkgaW5zdGFuY2UgaWYgbm90IGFscmVhZHkgaW5pdGlhbGl6ZWRcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGluaXRpYWxpemVQdXJpZnkoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnB1cmlmeVdpbmRvdyB8fCAhdGhpcy5wdXJpZnkpIHtcbiAgICAgIGNvbnN0IGRvbSA9IG5ldyBKU0RPTSgnJyk7XG4gICAgICB0aGlzLnB1cmlmeVdpbmRvdyA9IGRvbS53aW5kb3c7XG4gICAgICB0aGlzLnB1cmlmeSA9IERPTVB1cmlmeSh0aGlzLnB1cmlmeVdpbmRvdyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNhbml0aXplIHN0cmluZyBpbnB1dCB1c2luZyBET01QdXJpZnkgdG8gcHJldmVudCBYU1MgYXR0YWNrc1xuICAgKiBUaGlzIHJlcGxhY2VzIHRoZSByZWdleC1iYXNlZCBhcHByb2FjaCB3aXRoIGEgbW9yZSByb2J1c3Qgc29sdXRpb25cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIHNhbml0aXplU3RyaW5nKGlucHV0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIExpbWl0IGlucHV0IGxlbmd0aCB0byBwcmV2ZW50IERvU1xuICAgIGlmIChpbnB1dC5sZW5ndGggPiAxMDAwMCkge1xuICAgICAgaW5wdXQgPSBpbnB1dC5zdWJzdHJpbmcoMCwgMTAwMDApO1xuICAgIH1cbiAgICBcbiAgICAvLyBJbml0aWFsaXplIERPTVB1cmlmeSBpZiBuZWVkZWRcbiAgICB0aGlzLmluaXRpYWxpemVQdXJpZnkoKTtcbiAgICBcbiAgICAvLyBVc2UgRE9NUHVyaWZ5IHdpdGggc3RyaWN0IGNvbmZpZ3VyYXRpb25cbiAgICAvLyBBTExPV0VEX1RBR1M6IFtdIHN0cmlwcyBhbGwgSFRNTCB0YWdzXG4gICAgLy8gQUxMT1dFRF9BVFRSOiBbXSBzdHJpcHMgYWxsIGF0dHJpYnV0ZXNcbiAgICAvLyBGT1JCSURfVEFHUy9GT1JCSURfQVRUUiBwcm92aWRlIGFkZGl0aW9uYWwgcHJvdGVjdGlvblxuICAgIGxldCBzYW5pdGl6ZWQgPSB0aGlzLnB1cmlmeSEuc2FuaXRpemUoaW5wdXQsIHtcbiAgICAgIEFMTE9XRURfVEFHUzogW10sICAgICAgLy8gU3RyaXAgYWxsIEhUTUwgdGFnc1xuICAgICAgQUxMT1dFRF9BVFRSOiBbXSwgICAgICAvLyBTdHJpcCBhbGwgYXR0cmlidXRlc1xuICAgICAgRk9SQklEX1RBR1M6IFsnc3R5bGUnLCAnc2NyaXB0JywgJ2lmcmFtZScsICdvYmplY3QnLCAnZW1iZWQnLCAnbGluayddLFxuICAgICAgRk9SQklEX0FUVFI6IFsnb25lcnJvcicsICdvbmxvYWQnLCAnb25jbGljaycsICdvbm1vdXNlb3ZlcicsICdzdHlsZScsICdocmVmJywgJ3NyYyddXG4gICAgfSk7XG4gICAgXG4gICAgLy8gQWRkaXRpb25hbCBwcm90ZWN0aW9uIGFnYWluc3QgY29tbWFuZCBpbmplY3Rpb24gcGF0dGVybnNcbiAgICAvLyBUaGVzZSBwYXR0ZXJucyBtaWdodCBub3QgYmUgY2F1Z2h0IGJ5IERPTVB1cmlmeVxuICAgIGNvbnN0IGNvbW1hbmRJbmplY3Rpb25QYXR0ZXJucyA9IFtcbiAgICAgIC9gW15gXXswLDEwMDB9YC9nLCAgICAgICAgICAgLy8gQmFja3RpY2sgZXhwcmVzc2lvbnNcbiAgICAgIC9cXCRcXChbXildezAsMTAwMH1cXCkvZywgICAgICAgLy8gQ29tbWFuZCBzdWJzdGl0dXRpb25cbiAgICAgIC9cXCRcXHtbXn1dezAsMTAwMH1cXH0vZywgICAgICAgLy8gVmFyaWFibGUgZXhwYW5zaW9uXG4gICAgICAvXFxcXHhbMC05YS1mQS1GXXsyfS9nLCAgICAgICAgLy8gSGV4IGVzY2FwZXNcbiAgICAgIC9cXFxcdVswLTlhLWZBLUZdezR9L2csICAgICAgICAvLyBVbmljb2RlIGVzY2FwZXNcbiAgICAgIC9cXFxcWzAtN117MSwzfS9nICAgICAgICAgICAgICAvLyBPY3RhbCBlc2NhcGVzXG4gICAgXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgY29tbWFuZEluamVjdGlvblBhdHRlcm5zKSB7XG4gICAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZShwYXR0ZXJuLCAnJyk7XG4gICAgfVxuICAgIFxuICAgIC8vIFJlbW92ZSBudWxsIGJ5dGVzIGFuZCBub3JtYWxpemUgd2hpdGVzcGFjZVxuICAgIHNhbml0aXplZCA9IHNhbml0aXplZFxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnRyb2wtcmVnZXggLS0gSW50ZW50aW9uYWxseSByZW1vdmluZyBudWxsIGJ5dGVzIGZvciBzZWN1cml0eVxuICAgICAgLnJlcGxhY2VBbGwoL1xcdTAwMDAvZywgJycpICAgICAgICAgIC8vIE5PU09OQVIgLSBSZW1vdmUgbnVsbCBieXRlcyBmb3Igc2VjdXJpdHlcbiAgICAgIC5yZXBsYWNlQWxsKC9bXFxyXFxuXSsvZywgJyAnKSAgICAgIC8vIFJlcGxhY2UgbmV3bGluZXMgd2l0aCBzcGFjZXNcbiAgICAgIC50cmltKCk7XG4gICAgXG4gICAgcmV0dXJuIHNhbml0aXplZDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlc2V0IHN0YXRpYyBET01QdXJpZnkgY2FjaGUgKHVzZWZ1bCBmb3IgbG9uZy1ydW5uaW5nIHByb2Nlc3NlcylcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcmVzZXRDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLnB1cmlmeVdpbmRvdyA9IG51bGw7XG4gICAgdGhpcy5wdXJpZnkgPSBudWxsO1xuICB9XG59Il19