@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.
166 lines • 20.9 kB
JavaScript
/**
* SecureErrorHandler - Sanitizes error messages to prevent information disclosure
*
* SECURITY: Addresses Issue #206 - Information Disclosure via Error Messages
* - Prevents exposure of file paths, system details, and internal structure
* - Maps system errors to safe user-friendly messages
* - Preserves full error details for secure logging
* - Different behavior for production vs development environments
*/
import { logger } from '../utils/logger.js';
export class SecureErrorHandler {
// Pre-compiled regex patterns for better performance
static SANITIZATION_PATTERNS = {
UNIX_PATHS: /\/(?:Users|home|var|etc|opt|usr)\/[^\s]+/gi,
WINDOWS_PATHS: /[A-Z]:\\[^\s]+/gi,
UNC_PATHS: /\\\\[^\s]+/gi,
FILE_URLS: /file:\/\/\/?[^\s]+/gi,
IP_ADDRESSES: /\b(?:(?:\d{1,3}\.){3}\d{1,3}|(?:0\d{1,2}\.){3}0\d{1,2})\b/g,
PORTS: /:\d{4,5}\b/g,
HOME_DIRS: /~\/[^\s]+/g,
USER_PATHS: /\/(?:Users|home)\/[^\/\s]+/gi,
TEMP_PATHS: /\/(?:tmp|var\/folders)\/[^\s]+/gi,
ENV_VARS: /\$[A-Z_][A-Z0-9_]*/g,
};
static ERROR_MAP = {
// File system errors
'ENOENT': 'Resource not found',
'EACCES': 'Access denied',
'EEXIST': 'Resource already exists',
'EISDIR': 'Invalid operation on directory',
'EMFILE': 'System resource limit reached',
'ENOMEM': 'Insufficient memory available',
'ENOSPC': 'Insufficient storage space',
'EPERM': 'Operation not permitted',
'EROFS': 'Read-only file system',
// Network errors
'ECONNREFUSED': 'Connection refused',
'ECONNRESET': 'Connection reset',
'ETIMEDOUT': 'Operation timed out',
'ENOTFOUND': 'Service not found',
// Application errors
'INVALID_INPUT': 'Invalid input provided',
'VALIDATION_ERROR': 'Validation failed',
'NOT_FOUND': 'Resource not found',
'UNAUTHORIZED': 'Authentication required',
'FORBIDDEN': 'Access forbidden',
'RATE_LIMITED': 'Too many requests',
};
/**
* Sanitize an error for safe display to users
*/
static sanitizeError(error, requestId) {
// Input validation
if (error === null || error === undefined) {
return {
message: process.env.NODE_ENV === 'production'
? 'An error occurred processing your request.'
: 'An unknown error occurred',
code: 'UNKNOWN_ERROR',
requestId
};
}
// Log the full error securely for debugging
logger.error('Error occurred:', {
error: error,
stack: error?.stack,
code: error?.code,
requestId
});
// Production mode: Return only safe messages
if (process.env.NODE_ENV === 'production') {
return {
message: this.getSafeErrorMessage(error),
code: error?.code || 'INTERNAL_ERROR',
requestId
};
}
// Development mode: Return sanitized but more detailed messages
return {
message: this.sanitizeErrorMessage(error?.message || String(error)),
code: error?.code || 'UNKNOWN_ERROR',
requestId
};
}
/**
* Get a safe, user-friendly error message
*/
static getSafeErrorMessage(error) {
// Check for known error codes
if (error?.code && this.ERROR_MAP[error.code]) {
return this.ERROR_MAP[error.code];
}
// Check for common error types
if (error?.name === 'ValidationError') {
return 'Validation failed. Please check your input.';
}
if (error?.name === 'TypeError') {
return 'Invalid operation requested.';
}
if (error?.name === 'RangeError') {
return 'Value out of acceptable range.';
}
// Default safe message
return 'An error occurred processing your request.';
}
/**
* Sanitize error messages to remove sensitive information
*/
static sanitizeErrorMessage(message) {
if (!message)
return 'Unknown error';
// Use pre-compiled patterns for better performance
// Apply more specific patterns first to avoid conflicts
let sanitized = message;
// Remove temp directory paths BEFORE general paths
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.TEMP_PATHS, '[TEMP]');
// Remove other specific paths
sanitized = sanitized
.replace(this.SANITIZATION_PATTERNS.UNIX_PATHS, '[PATH]')
.replace(this.SANITIZATION_PATTERNS.WINDOWS_PATHS, '[PATH]')
.replace(this.SANITIZATION_PATTERNS.UNC_PATHS, '[PATH]');
// Remove file URLs (including Windows file:///c:/ format)
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.FILE_URLS, '[FILE]');
// Remove potential IP addresses (including zero-padded)
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.IP_ADDRESSES, '[IP]');
// Remove potential ports
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.PORTS, ':[PORT]');
// Remove home directory references
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.HOME_DIRS, '[HOME]/...');
// Remove potential usernames from paths
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.USER_PATHS, '/[USER]');
// Remove potential environment variables
sanitized = sanitized.replace(this.SANITIZATION_PATTERNS.ENV_VARS, '[ENV]');
// Limit message length to prevent verbose error dumps
if (sanitized.length > 500) {
sanitized = sanitized.substring(0, 497) + '...';
}
return sanitized;
}
/**
* Create a user-friendly error response
*/
static createErrorResponse(error, requestId) {
return {
success: false,
error: this.sanitizeError(error, requestId)
};
}
/**
* Wrap an async function with error handling
*/
static wrapAsync(fn, context) {
return (async (...args) => {
try {
return await fn(...args);
}
catch (error) {
const sanitized = this.sanitizeError(error);
throw new Error(context
? `${context}: ${sanitized.message}`
: sanitized.message);
}
});
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlY3VyaXR5L2Vycm9ySGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQVE1QyxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCLHFEQUFxRDtJQUM3QyxNQUFNLENBQVUscUJBQXFCLEdBQUc7UUFDOUMsVUFBVSxFQUFFLDRDQUE0QztRQUN4RCxhQUFhLEVBQUUsa0JBQWtCO1FBQ2pDLFNBQVMsRUFBRSxjQUFjO1FBQ3pCLFNBQVMsRUFBRSxzQkFBc0I7UUFDakMsWUFBWSxFQUFFLDREQUE0RDtRQUMxRSxLQUFLLEVBQUUsYUFBYTtRQUNwQixTQUFTLEVBQUUsWUFBWTtRQUN2QixVQUFVLEVBQUUsOEJBQThCO1FBQzFDLFVBQVUsRUFBRSxrQ0FBa0M7UUFDOUMsUUFBUSxFQUFFLHFCQUFxQjtLQUNoQyxDQUFDO0lBRU0sTUFBTSxDQUFVLFNBQVMsR0FBMkI7UUFDMUQscUJBQXFCO1FBQ3JCLFFBQVEsRUFBRSxvQkFBb0I7UUFDOUIsUUFBUSxFQUFFLGVBQWU7UUFDekIsUUFBUSxFQUFFLHlCQUF5QjtRQUNuQyxRQUFRLEVBQUUsZ0NBQWdDO1FBQzFDLFFBQVEsRUFBRSwrQkFBK0I7UUFDekMsUUFBUSxFQUFFLCtCQUErQjtRQUN6QyxRQUFRLEVBQUUsNEJBQTRCO1FBQ3RDLE9BQU8sRUFBRSx5QkFBeUI7UUFDbEMsT0FBTyxFQUFFLHVCQUF1QjtRQUVoQyxpQkFBaUI7UUFDakIsY0FBYyxFQUFFLG9CQUFvQjtRQUNwQyxZQUFZLEVBQUUsa0JBQWtCO1FBQ2hDLFdBQVcsRUFBRSxxQkFBcUI7UUFDbEMsV0FBVyxFQUFFLG1CQUFtQjtRQUVoQyxxQkFBcUI7UUFDckIsZUFBZSxFQUFFLHdCQUF3QjtRQUN6QyxrQkFBa0IsRUFBRSxtQkFBbUI7UUFDdkMs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S0FBSztZQUNkLEtBQUssRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUM7U0FDNUMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxTQUFTLENBQ2QsRUFBSyxFQUNMLE9BQWdCO1FBRWhCLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxJQUFtQixFQUFFLEVBQUU7WUFDdkMsSUFBSSxDQUFDO2dCQUNILE9BQU8sTUFBTSxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUMzQixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUM1QyxNQUFNLElBQUksS0FBSyxDQUNiLE9BQU87b0JBQ0wsQ0FBQyxDQUFDLEdBQUcsT0FBTyxLQUFLLFNBQVMsQ0FBQyxPQUFPLEVBQUU7b0JBQ3BDLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUN0QixDQUFDO1lBQ0osQ0FBQztRQUNILENBQUMsQ0FBTSxDQUFDO0lBQ1YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VjdXJlRXJyb3JIYW5kbGVyIC0gU2FuaXRpemVzIGVycm9yIG1lc3NhZ2VzIHRvIHByZXZlbnQgaW5mb3JtYXRpb24gZGlzY2xvc3VyZVxuICogXG4gKiBTRUNVUklUWTogQWRkcmVzc2VzIElzc3VlICMyMDYgLSBJbmZvcm1hdGlvbiBEaXNjbG9zdXJlIHZpYSBFcnJvciBNZXNzYWdlc1xuICogLSBQcmV2ZW50cyBleHBvc3VyZSBvZiBmaWxlIHBhdGhzLCBzeXN0ZW0gZGV0YWlscywgYW5kIGludGVybmFsIHN0cnVjdHVyZVxuICogLSBNYXBzIHN5c3RlbSBlcnJvcnMgdG8gc2FmZSB1c2VyLWZyaWVuZGx5IG1lc3NhZ2VzXG4gKiAtIFByZXNlcnZlcyBmdWxsIGVycm9yIGRldGFpbHMgZm9yIHNlY3VyZSBsb2dnaW5nXG4gKiAtIERpZmZlcmVudCBiZWhhdmlvciBmb3IgcHJvZHVjdGlvbiB2cyBkZXZlbG9wbWVudCBlbnZpcm9ubWVudHNcbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNhbml0aXplZEVycm9yIHtcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBjb2RlPzogc3RyaW5nO1xuICByZXF1ZXN0SWQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBTZWN1cmVFcnJvckhhbmRsZXIge1xuICAvLyBQcmUtY29tcGlsZWQgcmVnZXggcGF0dGVybnMgZm9yIGJldHRlciBwZXJmb3JtYW5jZVxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBTQU5JVElaQVRJT05fUEFUVEVSTlMgPSB7XG4gICAgVU5JWF9QQVRIUzogL1xcLyg/OlVzZXJzfGhvbWV8dmFyfGV0Y3xvcHR8dXNyKVxcL1teXFxzXSsvZ2ksXG4gICAgV0lORE9XU19QQVRIUzogL1tBLVpdOlxcXFxbXlxcc10rL2dpLFxuICAgIFVOQ19QQVRIUzogL1xcXFxcXFxcW15cXHNdKy9naSxcbiAgICBGSUxFX1VSTFM6IC9maWxlOlxcL1xcL1xcLz9bXlxcc10rL2dpLFxuICAgIElQX0FERFJFU1NFUzogL1xcYig/Oig/OlxcZHsxLDN9XFwuKXszfVxcZHsxLDN9fCg/OjBcXGR7MSwyfVxcLil7M30wXFxkezEsMn0pXFxiL2csXG4gICAgUE9SVFM6IC86XFxkezQsNX1cXGIvZyxcbiAgICBIT01FX0RJUlM6IC9+XFwvW15cXHNdKy9nLFxuICAgIFVTRVJfUEFUSFM6IC9cXC8oPzpVc2Vyc3xob21lKVxcL1teXFwvXFxzXSsvZ2ksXG4gICAgVEVNUF9QQVRIUzogL1xcLyg/OnRtcHx2YXJcXC9mb2xkZXJzKVxcL1teXFxzXSsvZ2ksXG4gICAgRU5WX1ZBUlM6IC9cXCRbQS1aX11bQS1aMC05X10qL2csXG4gIH07XG4gIFxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBFUlJPUl9NQVA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgLy8gRmlsZSBzeXN0ZW0gZXJyb3JzXG4gICAgJ0VOT0VOVCc6ICdSZXNvdXJjZSBub3QgZm91bmQnLFxuICAgICdFQUNDRVMnOiAnQWNjZXNzIGRlbmllZCcsXG4gICAgJ0VFWElTVCc6ICdSZXNvdXJjZSBhbHJlYWR5IGV4aXN0cycsXG4gICAgJ0VJU0RJUic6ICdJbnZhbGlkIG9wZXJhdGlvbiBvbiBkaXJlY3RvcnknLFxuICAgICdFTUZJTEUnOiAnU3lzdGVtIHJlc291cmNlIGxpbWl0IHJlYWNoZWQnLFxuICAgICdFTk9NRU0nOiAnSW5zdWZmaWNpZW50IG1lbW9yeSBhdmFpbGFibGUnLFxuICAgICdFTk9TUEMnOiAnSW5zdWZmaWNpZW50IHN0b3JhZ2Ugc3BhY2UnLFxuICAgICdFUEVSTSc6ICdPcGVyYXRpb24gbm90IHBlcm1pdHRlZCcsXG4gICAgJ0VST0ZTJzogJ1JlYWQtb25seSBmaWxlIHN5c3RlbScsXG4gICAgXG4gICAgLy8gTmV0d29yayBlcnJvcnNcbiAgICAnRUNPTk5SRUZVU0VEJzogJ0Nvbm5lY3Rpb24gcmVmdXNlZCcsXG4gICAgJ0VDT05OUkVTRVQnOiAnQ29ubmVjdGlvbiByZXNldCcsXG4gICAgJ0VUSU1FRE9VVCc6ICdPcGVyYXRpb24gdGltZWQgb3V0JyxcbiAgICAnRU5PVEZPVU5EJzogJ1NlcnZpY2Ugbm90IGZvdW5kJyxcbiAgICBcbiAgICAvLyBBcHBsaWNhdGlvbiBlcnJvcnNcbiAgICAnSU5WQUxJRF9JTlBVVCc6ICdJbnZhbGlkIGlucHV0IHByb3ZpZGVkJyxcbiAgICAnVkFMSURBVElPTl9FUlJPUic6ICdWYWxpZGF0aW9uIGZhaWxlZCcsXG4gICAgJ05PVF9GT1VORCc6ICdSZXNvdXJjZSBub3QgZm91bmQnLFxuICAgICdVTkFVVEhPUklaRUQnOiAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLFxuICAgICdGT1JCSURERU4nOiAnQWNjZXNzIGZvcmJpZGRlbicsXG4gICAgJ1JBVEVfTElNSVRFRCc6ICdUb28gbWFueSByZXF1ZXN0cycsXG4gIH07XG5cbiAgLyoqXG4gICAqIFNhbml0aXplIGFuIGVycm9yIGZvciBzYWZlIGRpc3BsYXkgdG8gdXNlcnNcbiAgICovXG4gIHN0YXRpYyBzYW5pdGl6ZUVycm9yKGVycm9yOiBhbnksIHJlcXVlc3RJZD86IHN0cmluZyk6IFNhbml0aXplZEVycm9yIHtcbiAgICAvLyBJbnB1dCB2YWxpZGF0aW9uXG4gICAgaWYgKGVycm9yID09PSBudWxsIHx8IGVycm9yID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG1lc3NhZ2U6IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbicgXG4gICAgICAgICAgPyAnQW4gZXJyb3Igb2NjdXJyZWQgcHJvY2Vzc2luZyB5b3VyIHJlcXVlc3QuJ1xuICAgICAgICAgIDogJ0FuIHVua25vd24gZXJyb3Igb2NjdXJyZWQnLFxuICAgICAgICBjb2RlOiAnVU5LTk9XTl9FUlJPUicsXG4gICAgICAgIHJlcXVlc3RJZFxuICAgICAgfTtcbiAgICB9XG4gICAgLy8gTG9nIHRoZSBmdWxsIGVycm9yIHNlY3VyZWx5IGZvciBkZWJ1Z2dpbmdcbiAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIG9jY3VycmVkOicsIHtcbiAgICAgIGVycm9yOiBlcnJvcixcbiAgICAgIHN0YWNrOiBlcnJvcj8uc3RhY2ssXG4gICAgICBjb2RlOiBlcnJvcj8uY29kZSxcbiAgICAgIHJlcXVlc3RJZFxuICAgIH0pO1xuXG4gICAgLy8gUHJvZHVjdGlvbiBtb2RlOiBSZXR1cm4gb25seSBzYWZlIG1lc3NhZ2VzXG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbicpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG1lc3NhZ2U6IHRoaXMuZ2V0U2FmZUVycm9yTWVzc2FnZShlcnJvciksXG4gICAgICAgIGNvZGU6IGVycm9yPy5jb2RlIHx8ICdJTlRFUk5BTF9FUlJPUicsXG4gICAgICAgIHJlcXVlc3RJZFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBEZXZlbG9wbWVudCBtb2RlOiBSZXR1cm4gc2FuaXRpemVkIGJ1dCBtb3JlIGRldGFpbGVkIG1lc3NhZ2VzXG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2U6IHRoaXMuc2FuaXRpemVFcnJvck1lc3NhZ2UoZXJyb3I/Lm1lc3NhZ2UgfHwgU3RyaW5nKGVycm9yKSksXG4gICAgICBjb2RlOiBlcnJvcj8uY29kZSB8fCAnVU5LTk9XTl9FUlJPUicsXG4gICAgICByZXF1ZXN0SWRcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHNhZmUsIHVzZXItZnJpZW5kbHkgZXJyb3IgbWVzc2FnZVxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0U2FmZUVycm9yTWVzc2FnZShlcnJvcjogYW55KTogc3RyaW5nIHtcbiAgICAvLyBDaGVjayBmb3Iga25vd24gZXJyb3IgY29kZXNcbiAgICBpZiAoZXJyb3I/LmNvZGUgJiYgdGhpcy5FUlJPUl9NQVBbZXJyb3IuY29kZV0pIHtcbiAgICAgIHJldHVybiB0aGlzLkVSUk9SX01BUFtlcnJvci5jb2RlXTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgY29tbW9uIGVycm9yIHR5cGVzXG4gICAgaWYgKGVycm9yPy5uYW1lID09PSAnVmFsaWRhdGlvbkVycm9yJykge1xuICAgICAgcmV0dXJuICdWYWxpZGF0aW9uIGZhaWxlZC4gUGxlYXNlIGNoZWNrIHlvdXIgaW5wdXQuJztcbiAgICB9XG4gICAgXG4gICAgaWYgKGVycm9yPy5uYW1lID09PSAnVHlwZUVycm9yJykge1xuICAgICAgcmV0dXJuICdJbnZhbGlkIG9wZXJhdGlvbiByZXF1ZXN0ZWQuJztcbiAgICB9XG4gICAgXG4gICAgaWYgKGVycm9yPy5uYW1lID09PSAnUmFuZ2VFcnJvcicpIHtcbiAgICAgIHJldHVybiAnVmFsdWUgb3V0IG9mIGFjY2VwdGFibGUgcmFuZ2UuJztcbiAgICB9XG5cbiAgICAvLyBEZWZhdWx0IHNhZmUgbWVzc2FnZVxuICAgIHJldHVybiAnQW4gZXJyb3Igb2NjdXJyZWQgcHJvY2Vzc2luZyB5b3VyIHJlcXVlc3QuJztcbiAgfVxuXG4gIC8qKlxuICAgKiBTYW5pdGl6ZSBlcnJvciBtZXNzYWdlcyB0byByZW1vdmUgc2Vuc2l0aXZlIGluZm9ybWF0aW9uXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBzYW5pdGl6ZUVycm9yTWVzc2FnZShtZXNzYWdlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICghbWVzc2FnZSkgcmV0dXJuICdVbmtub3duIGVycm9yJztcblxuICAgIC8vIFVzZSBwcmUtY29tcGlsZWQgcGF0dGVybnMgZm9yIGJldHRlciBwZXJmb3JtYW5jZVxuICAgIC8vIEFwcGx5IG1vcmUgc3BlY2lmaWMgcGF0dGVybnMgZmlyc3QgdG8gYXZvaWQgY29uZmxpY3RzXG4gICAgbGV0IHNhbml0aXplZCA9IG1lc3NhZ2U7XG4gICAgXG4gICAgLy8gUmVtb3ZlIHRlbXAgZGlyZWN0b3J5IHBhdGhzIEJFRk9SRSBnZW5lcmFsIHBhdGhzXG4gICAgc2FuaXRpemVkID0gc2FuaXRpemVkLnJlcGxhY2UodGhpcy5TQU5JVElaQVRJT05fUEFUVEVSTlMuVEVNUF9QQVRIUywgJ1tURU1QXScpO1xuICAgIFxuICAgIC8vIFJlbW92ZSBvdGhlciBzcGVjaWZpYyBwYXRoc1xuICAgIHNhbml0aXplZCA9IHNhbml0aXplZFxuICAgICAgLnJlcGxhY2UodGhpcy5TQU5JVElaQVRJT05fUEFUVEVSTlMuVU5JWF9QQVRIUywgJ1tQQVRIXScpXG4gICAgICAucmVwbGFjZSh0aGlzLlNBTklUSVpBVElPTl9QQVRURVJOUy5XSU5ET1dTX1BBVEhTLCAnW1BBVEhdJylcbiAgICAgIC5yZXBsYWNlKHRoaXMuU0FOSVRJWkFUSU9OX1BBVFRFUk5TLlVOQ19QQVRIUywgJ1tQQVRIXScpO1xuXG4gICAgLy8gUmVtb3ZlIGZpbGUgVVJMcyAoaW5jbHVkaW5nIFdpbmRvd3MgZmlsZTovLy9jOi8gZm9ybWF0KVxuICAgIHNhbml0aXplZCA9IHNhbml0aXplZC5yZXBsYWNlKHRoaXMuU0FOSVRJWkFUSU9OX1BBVFRFUk5TLkZJTEVfVVJMUywgJ1tGSUxFXScpO1xuXG4gICAgLy8gUmVtb3ZlIHBvdGVudGlhbCBJUCBhZGRyZXNzZXMgKGluY2x1ZGluZyB6ZXJvLXBhZGRlZClcbiAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZSh0aGlzLlNBTklUSVpBVElPTl9QQVRURVJOUy5JUF9BRERSRVNTRVMsICdbSVBdJyk7XG5cbiAgICAvLyBSZW1vdmUgcG90ZW50aWFsIHBvcnRzXG4gICAgc2FuaXRpemVkID0gc2FuaXRpemVkLnJlcGxhY2UodGhpcy5TQU5JVElaQVRJT05fUEFUVEVSTlMuUE9SVFMsICc6W1BPUlRdJyk7XG5cbiAgICAvLyBSZW1vdmUgaG9tZSBkaXJlY3RvcnkgcmVmZXJlbmNlc1xuICAgIHNhbml0aXplZCA9IHNhbml0aXplZC5yZXBsYWNlKHRoaXMuU0FOSVRJWkFUSU9OX1BBVFRFUk5TLkhPTUVfRElSUywgJ1tIT01FXS8uLi4nKTtcblxuICAgIC8vIFJlbW92ZSBwb3RlbnRpYWwgdXNlcm5hbWVzIGZyb20gcGF0aHNcbiAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZSh0aGlzLlNBTklUSVpBVElPTl9QQVRURVJOUy5VU0VSX1BBVEhTLCAnL1tVU0VSXScpO1xuXG4gICAgLy8gUmVtb3ZlIHBvdGVudGlhbCBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZSh0aGlzLlNBTklUSVpBVElPTl9QQVRURVJOUy5FTlZfVkFSUywgJ1tFTlZdJyk7XG5cbiAgICAvLyBMaW1pdCBtZXNzYWdlIGxlbmd0aCB0byBwcmV2ZW50IHZlcmJvc2UgZXJyb3IgZHVtcHNcbiAgICBpZiAoc2FuaXRpemVkLmxlbmd0aCA+IDUwMCkge1xuICAgICAgc2FuaXRpemVkID0gc2FuaXRpemVkLnN1YnN0cmluZygwLCA0OTcpICsgJy4uLic7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNhbml0aXplZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSB1c2VyLWZyaWVuZGx5IGVycm9yIHJlc3BvbnNlXG4gICAqL1xuICBzdGF0aWMgY3JlYXRlRXJyb3JSZXNwb25zZShlcnJvcjogYW55LCByZXF1ZXN0SWQ/OiBzdHJpbmcpOiB7XG4gICAgc3VjY2VzczogZmFsc2U7XG4gICAgZXJyb3I6IFNhbml0aXplZEVycm9yO1xuICB9IHtcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICBlcnJvcjogdGhpcy5zYW5pdGl6ZUVycm9yKGVycm9yLCByZXF1ZXN0SWQpXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcmFwIGFuIGFzeW5jIGZ1bmN0aW9uIHdpdGggZXJyb3IgaGFuZGxpbmdcbiAgICovXG4gIHN0YXRpYyB3cmFwQXN5bmM8VCBleHRlbmRzICguLi5hcmdzOiBhbnlbXSkgPT4gUHJvbWlzZTxhbnk+PihcbiAgICBmbjogVCxcbiAgICBjb250ZXh0Pzogc3RyaW5nXG4gICk6IFQge1xuICAgIHJldHVybiAoYXN5bmMgKC4uLmFyZ3M6IFBhcmFtZXRlcnM8VD4pID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnN0IHNhbml0aXplZCA9IHRoaXMuc2FuaXRpemVFcnJvcihlcnJvcik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBjb250ZXh0IFxuICAgICAgICAgICAgPyBgJHtjb250ZXh0fTogJHtzYW5pdGl6ZWQubWVzc2FnZX1gXG4gICAgICAgICAgICA6IHNhbml0aXplZC5tZXNzYWdlXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSkgYXMgVDtcbiAgfVxufSJdfQ==