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.

231 lines 31.9 kB
/** * Adapter to convert simple portfolio elements to full IElement interface * This resolves type safety issues without complex type casting * * FIXES IMPLEMENTED (PR #503): * 1. TYPE SAFETY (Issue #497): Eliminates complex type casting with adapter pattern * 2. SECURITY FIX DMCP-SEC-004 (MEDIUM): Added Unicode normalization for all user input * 3. SECURITY FIX DMCP-SEC-006 (LOW): Added audit logging for element creation * 4. PERFORMANCE: Helper methods for efficient string normalization */ import { ElementStatus } from '../../types/elements/IElement.js'; import { UnicodeValidator } from '../../security/validators/unicodeValidator.js'; import { SecurityMonitor } from '../../security/securityMonitor.js'; import { logger } from '../../utils/logger.js'; import * as yaml from 'js-yaml'; import { ContentValidator } from '../../security/contentValidator.js'; import { SecureYamlParser } from '../../security/secureYamlParser.js'; /** * Adapter class that wraps a simple PortfolioElement and implements IElement * This allows us to pass portfolio elements to methods expecting IElement * without complex type casting */ export class PortfolioElementAdapter { id; type; version; metadata; portfolioElement; constructor(element) { // SECURITY FIX #2 (DMCP-SEC-004): Normalize and validate all user input // Previously: User input was used directly without validation // Now: All string inputs go through UnicodeValidator to prevent homograph attacks const normalizedName = UnicodeValidator.normalize(element.metadata.name); if (!normalizedName.isValid) { // Log security event for invalid Unicode SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'PortfolioElementAdapter.constructor', details: `Invalid Unicode in element name: ${normalizedName.detectedIssues?.[0] || 'unknown'}` }); logger.warn('Invalid Unicode detected in element name', { issues: normalizedName.detectedIssues }); } this.portfolioElement = element; this.type = element.type; this.version = element.metadata.version || '1.0.0'; // Generate ID from type and normalized name const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-'); const safeName = normalizedName.normalizedContent || element.metadata.name; const nameSlug = safeName.toLowerCase().replaceAll(/\s+/g, '-'); this.id = `${element.type}_${nameSlug}_${timestamp}`; // Convert metadata to IElementMetadata format with normalized values this.metadata = { name: safeName, description: this.normalizeString(element.metadata.description || ''), author: this.normalizeString(element.metadata.author || ''), version: element.metadata.version, created: element.metadata.created, modified: element.metadata.updated, tags: [] }; // SECURITY FIX #3 (DMCP-SEC-006): Log element creation for audit trail // Previously: No audit logging for portfolio operations // Now: Complete audit trail using SecurityMonitor.logSecurityEvent() SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_CREATED', severity: 'LOW', source: 'PortfolioElementAdapter.constructor', details: `Created portfolio element adapter: ${this.id}`, metadata: { elementType: this.type, elementId: this.id } }); } /** * Helper to normalize string values safely */ normalizeString(value) { if (!value) return value; const normalized = UnicodeValidator.normalize(value); return normalized.normalizedContent || value; } /** * Validate the element */ validate() { const errors = []; const warnings = []; if (!this.metadata.name) { errors.push({ field: 'name', message: 'Element name is required' }); } if (!this.portfolioElement.content) { errors.push({ field: 'content', message: 'Element content is required' }); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : undefined, warnings: warnings.length > 0 ? warnings : undefined }; } /** * Serialize the element to markdown with YAML frontmatter * FIX: Changed from JSON to markdown format for GitHub portfolio compatibility * SECURITY FIX #544: Parse and validate existing frontmatter instead of returning as-is * SECURITY FIX #543: Use SecureYamlParser for robust frontmatter detection */ serialize() { // SECURITY FIX #543: Use SecureYamlParser for robust frontmatter detection // This handles different line endings, whitespace variations, and malformed YAML let contentToProcess = this.portfolioElement.content; let existingMetadata = {}; let bodyContent = contentToProcess; // Try to parse existing frontmatter if present try { // SecureYamlParser handles all edge cases: // - Different line endings (\n, \r\n) // - Whitespace variations // - Malformed YAML (returns empty data object) // - Missing closing delimiter const parsed = SecureYamlParser.safeMatter(contentToProcess); if (parsed.data && Object.keys(parsed.data).length > 0) { // SECURITY FIX #544: Validate existing frontmatter instead of bypassing logger.debug('Found existing frontmatter, validating before merge'); // Validate the parsed frontmatter const validationResult = ContentValidator.validateAndSanitize(yaml.dump(parsed.data)); if (!validationResult.isValid && validationResult.severity === 'critical') { // Log security event for malicious frontmatter SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'HIGH', source: 'PortfolioElementAdapter.serialize', details: `Critical security issues in frontmatter: ${validationResult.detectedPatterns?.join(', ')}`, metadata: { elementId: this.id, elementType: this.type } }); // Don't use the malicious frontmatter, create new existingMetadata = {}; bodyContent = contentToProcess; // Use original content } else { // Frontmatter is safe, merge with our metadata existingMetadata = parsed.data; bodyContent = parsed.content; } } } catch (error) { // If SecureYamlParser fails to parse, treat as content without frontmatter logger.warn('Failed to parse potential frontmatter, treating as plain content', { error: error instanceof Error ? error.message : String(error) }); // Continue with empty metadata and full content } // Merge metadata, with our metadata taking precedence for security // This ensures critical fields like ID and type are always from our validated source const mergedMetadata = { ...existingMetadata, // Existing metadata first ...this.metadata, // Our validated metadata overwrites id: this.id, // Always use our ID unique_id: this.id, // CRITICAL FIX: Add unique_id for collection workflow compatibility type: this.type, // Always use our type version: this.version // Always use our version }; // Validate the final merged metadata const metadataYaml = yaml.dump(mergedMetadata, { noRefs: true, sortKeys: false, lineWidth: -1 }); // Final security check on the complete metadata const finalValidation = ContentValidator.validateAndSanitize(metadataYaml); if (!finalValidation.isValid && finalValidation.severity === 'critical') { // This shouldn't happen with our sanitized data, but log if it does SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'PortfolioElementAdapter.serialize', details: 'Final metadata validation failed after merge', metadata: { elementId: this.id } }); // Fall back to minimal safe metadata const safeMetadata = { id: this.id, unique_id: this.id, // CRITICAL FIX: Include unique_id for collection workflow type: this.type, version: this.version, name: this.normalizeString(this.metadata.name || 'Untitled'), description: this.normalizeString(this.metadata.description || '') }; const safeFrontmatter = yaml.dump(safeMetadata, { noRefs: true, sortKeys: false, lineWidth: -1 }); return `---\n${safeFrontmatter}---\n\n${bodyContent}`; } // Return validated and sanitized markdown with frontmatter return `---\n${metadataYaml}---\n\n${bodyContent}`; } /** * Deserialize from string (not implemented for adapter) */ deserialize(_data) { throw new Error('Deserialization not supported for PortfolioElementAdapter'); } /** * Get element status */ getStatus() { return ElementStatus.INACTIVE; } /** * Get the original portfolio element content */ getContent() { return this.portfolioElement.content; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdG9vbHMvcG9ydGZvbGlvL1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sRUFJTCxhQUFhLEVBR2QsTUFBTSxrQ0FBa0MsQ0FBQztBQUcxQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUNqRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBRXRFOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sdUJBQXVCO0lBQ2xCLEVBQUUsQ0FBUztJQUNYLElBQUksQ0FBYztJQUNsQixPQUFPLENBQVM7SUFDaEIsUUFBUSxDQUFtQjtJQUMxQixnQkFBZ0IsQ0FBbUI7SUFFcEQsWUFBWSxPQUF5QjtRQUNuQyx3RUFBd0U7UUFDeEUsOERBQThEO1FBQzlELGtGQUFrRjtRQUNsRixNQUFNLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzVCLHlDQUF5QztZQUN6QyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLElBQUksRUFBRSwwQkFBMEI7Z0JBQ2hDLFFBQVEsRUFBRSxRQUFRO2dCQUNsQixNQUFNLEVBQUUscUNBQXFDO2dCQUM3QyxPQUFPLEVBQUUsb0NB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QVEsQ0FBQyxJQUFJLElBQUksVUFBVSxDQUFDO2dCQUM1RCxXQUFXLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7YUFDbkUsQ0FBQztZQUVGLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFO2dCQUM5QyxNQUFNLEVBQUUsSUFBSTtnQkFDWixRQUFRLEVBQUUsS0FBSztnQkFDZixTQUFTLEVBQUUsQ0FBQyxDQUFDO2FBQ2QsQ0FBQyxDQUFDO1lBRUgsT0FBTyxRQUFRLGVBQWUsVUFBVSxXQUFXLEVBQUUsQ0FBQztRQUN4RCxDQUFDO1FBRUQsMkRBQTJEO1FBQzNELE9BQU8sUUFBUSxZQUFZLFVBQVUsV0FBVyxFQUFFLENBQUM7SUFDckQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsV0FBVyxDQUFDLEtBQWE7UUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQywyREFBMkQsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVM7UUFDUCxPQUFPLGFBQWEsQ0FBQyxRQUFRLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVTtRQUNSLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQztJQUN2QyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFkYXB0ZXIgdG8gY29udmVydCBzaW1wbGUgcG9ydGZvbGlvIGVsZW1lbnRzIHRvIGZ1bGwgSUVsZW1lbnQgaW50ZXJmYWNlXG4gKiBUaGlzIHJlc29sdmVzIHR5cGUgc2FmZXR5IGlzc3VlcyB3aXRob3V0IGNvbXBsZXggdHlwZSBjYXN0aW5nXG4gKiBcbiAqIEZJWEVTIElNUExFTUVOVEVEIChQUiAjNTAzKTpcbiAqIDEuIFRZUEUgU0FGRVRZIChJc3N1ZSAjNDk3KTogRWxpbWluYXRlcyBjb21wbGV4IHR5cGUgY2FzdGluZyB3aXRoIGFkYXB0ZXIgcGF0dGVyblxuICogMi4gU0VDVVJJVFkgRklYIERNQ1AtU0VDLTAwNCAoTUVESVVNKTogQWRkZWQgVW5pY29kZSBub3JtYWxpemF0aW9uIGZvciBhbGwgdXNlciBpbnB1dFxuICogMy4gU0VDVVJJVFkgRklYIERNQ1AtU0VDLTAwNiAoTE9XKTogQWRkZWQgYXVkaXQgbG9nZ2luZyBmb3IgZWxlbWVudCBjcmVhdGlvblxuICogNC4gUEVSRk9STUFOQ0U6IEhlbHBlciBtZXRob2RzIGZvciBlZmZpY2llbnQgc3RyaW5nIG5vcm1hbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQge1xuICBJRWxlbWVudCxcbiAgSUVsZW1lbnRNZXRhZGF0YSxcbiAgRWxlbWVudFZhbGlkYXRpb25SZXN1bHQsXG4gIEVsZW1lbnRTdGF0dXMsXG4gIFZhbGlkYXRpb25FcnJvcixcbiAgVmFsaWRhdGlvbldhcm5pbmdcbn0gZnJvbSAnLi4vLi4vdHlwZXMvZWxlbWVudHMvSUVsZW1lbnQuanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuLi8uLi9wb3J0Zm9saW8vdHlwZXMuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvRWxlbWVudCB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5cbi8qKlxuICogQWRhcHRlciBjbGFzcyB0aGF0IHdyYXBzIGEgc2ltcGxlIFBvcnRmb2xpb0VsZW1lbnQgYW5kIGltcGxlbWVudHMgSUVsZW1lbnRcbiAqIFRoaXMgYWxsb3dzIHVzIHRvIHBhc3MgcG9ydGZvbGlvIGVsZW1lbnRzIHRvIG1ldGhvZHMgZXhwZWN0aW5nIElFbGVtZW50XG4gKiB3aXRob3V0IGNvbXBsZXggdHlwZSBjYXN0aW5nXG4gKi9cbmV4cG9ydCBjbGFzcyBQb3J0Zm9saW9FbGVtZW50QWRhcHRlciBpbXBsZW1lbnRzIElFbGVtZW50IHtcbiAgcHVibGljIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG4gIHB1YmxpYyByZWFkb25seSB0eXBlOiBFbGVtZW50VHlwZTtcbiAgcHVibGljIHJlYWRvbmx5IHZlcnNpb246IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IG1ldGFkYXRhOiBJRWxlbWVudE1ldGFkYXRhO1xuICBwcml2YXRlIHJlYWRvbmx5IHBvcnRmb2xpb0VsZW1lbnQ6IFBvcnRmb2xpb0VsZW1lbnQ7XG5cbiAgY29uc3RydWN0b3IoZWxlbWVudDogUG9ydGZvbGlvRWxlbWVudCkge1xuICAgIC8vIFNFQ1VSSVRZIEZJWCAjMiAoRE1DUC1TRUMtMDA0KTogTm9ybWFsaXplIGFuZCB2YWxpZGF0ZSBhbGwgdXNlciBpbnB1dFxuICAgIC8vIFByZXZpb3VzbHk6IFVzZXIgaW5wdXQgd2FzIHVzZWQgZGlyZWN0bHkgd2l0aG91dCB2YWxpZGF0aW9uXG4gICAgLy8gTm93OiBBbGwgc3RyaW5nIGlucHV0cyBnbyB0aHJvdWdoIFVuaWNvZGVWYWxpZGF0b3IgdG8gcHJldmVudCBob21vZ3JhcGggYXR0YWNrc1xuICAgIGNvbnN0IG5vcm1hbGl6ZWROYW1lID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoZWxlbWVudC5tZXRhZGF0YS5uYW1lKTtcbiAgICBpZiAoIW5vcm1hbGl6ZWROYW1lLmlzVmFsaWQpIHtcbiAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgaW52YWxpZCBVbmljb2RlXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdVTklDT0RFX1ZBTElEQVRJT05fRVJST1InLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLmNvbnN0cnVjdG9yJyxcbiAgICAgICAgZGV0YWlsczogYEludmFsaWQgVW5pY29kZSBpbiBlbGVtZW50IG5hbWU6ICR7bm9ybWFsaXplZE5hbWUuZGV0ZWN0ZWRJc3N1ZXM/LlswXSB8fCAndW5rbm93bid9YFxuICAgICAgfSk7XG4gICAgICBsb2dnZXIud2FybignSW52YWxpZCBVbmljb2RlIGRldGVjdGVkIGluIGVsZW1lbnQgbmFtZScsIHtcbiAgICAgICAgaXNzdWVzOiBub3JtYWxpemVkTmFtZS5kZXRlY3RlZElzc3Vlc1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIHRoaXMucG9ydGZvbGlvRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgdGhpcy50eXBlID0gZWxlbWVudC50eXBlO1xuICAgIHRoaXMudmVyc2lvbiA9IGVsZW1lbnQubWV0YWRhdGEudmVyc2lvbiB8fCAnMS4wLjAnO1xuICAgIFxuICAgIC8vIEdlbmVyYXRlIElEIGZyb20gdHlwZSBhbmQgbm9ybWFsaXplZCBuYW1lXG4gICAgY29uc3QgdGltZXN0YW1wID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnJlcGxhY2VBbGwoL1s6Ll0vZywgJy0nKTtcbiAgICBjb25zdCBzYWZlTmFtZSA9IG5vcm1hbGl6ZWROYW1lLm5vcm1hbGl6ZWRDb250ZW50IHx8IGVsZW1lbnQubWV0YWRhdGEubmFtZTtcbiAgICBjb25zdCBuYW1lU2x1ZyA9IHNhZmVOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZUFsbCgvXFxzKy9nLCAnLScpO1xuICAgIHRoaXMuaWQgPSBgJHtlbGVtZW50LnR5cGV9XyR7bmFtZVNsdWd9XyR7dGltZXN0YW1wfWA7XG4gICAgXG4gICAgLy8gQ29udmVydCBtZXRhZGF0YSB0byBJRWxlbWVudE1ldGFkYXRhIGZvcm1hdCB3aXRoIG5vcm1hbGl6ZWQgdmFsdWVzXG4gICAgdGhpcy5tZXRhZGF0YSA9IHtcbiAgICAgIG5hbWU6IHNhZmVOYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHRoaXMubm9ybWFsaXplU3RyaW5nKGVsZW1lbnQubWV0YWRhdGEuZGVzY3JpcHRpb24gfHwgJycpLFxuICAgICAgYXV0aG9yOiB0aGlzLm5vcm1hbGl6ZVN0cmluZyhlbGVtZW50Lm1ldGFkYXRhLmF1dGhvciB8fCAnJyksXG4gICAgICB2ZXJzaW9uOiBlbGVtZW50Lm1ldGFkYXRhLnZlcnNpb24sXG4gICAgICBjcmVhdGVkOiBlbGVtZW50Lm1ldGFkYXRhLmNyZWF0ZWQsXG4gICAgICBtb2RpZmllZDogZWxlbWVudC5tZXRhZGF0YS51cGRhdGVkLFxuICAgICAgdGFnczogW11cbiAgICB9O1xuICAgIFxuICAgIC8vIFNFQ1VSSVRZIEZJWCAjMyAoRE1DUC1TRUMtMDA2KTogTG9nIGVsZW1lbnQgY3JlYXRpb24gZm9yIGF1ZGl0IHRyYWlsXG4gICAgLy8gUHJldmlvdXNseTogTm8gYXVkaXQgbG9nZ2luZyBmb3IgcG9ydGZvbGlvIG9wZXJhdGlvbnNcbiAgICAvLyBOb3c6IENvbXBsZXRlIGF1ZGl0IHRyYWlsIHVzaW5nIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KClcbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiAnRUxFTUVOVF9DUkVBVEVEJyxcbiAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLmNvbnN0cnVjdG9yJyxcbiAgICAgIGRldGFpbHM6IGBDcmVhdGVkIHBvcnRmb2xpbyBlbGVtZW50IGFkYXB0ZXI6ICR7dGhpcy5pZH1gLFxuICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgZWxlbWVudFR5cGU6IHRoaXMudHlwZSxcbiAgICAgICAgZWxlbWVudElkOiB0aGlzLmlkXG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gbm9ybWFsaXplIHN0cmluZyB2YWx1ZXMgc2FmZWx5XG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZVN0cmluZyh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoIXZhbHVlKSByZXR1cm4gdmFsdWU7XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKHZhbHVlKTtcbiAgICByZXR1cm4gbm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudCB8fCB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgZWxlbWVudFxuICAgKi9cbiAgdmFsaWRhdGUoKTogRWxlbWVudFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGNvbnN0IGVycm9yczogVmFsaWRhdGlvbkVycm9yW10gPSBbXTtcbiAgICBjb25zdCB3YXJuaW5nczogVmFsaWRhdGlvbldhcm5pbmdbXSA9IFtdO1xuXG4gICAgaWYgKCF0aGlzLm1ldGFkYXRhLm5hbWUpIHtcbiAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgZmllbGQ6ICduYW1lJyxcbiAgICAgICAgbWVzc2FnZTogJ0VsZW1lbnQgbmFtZSBpcyByZXF1aXJlZCdcbiAgICAgIH0pO1xuICAgIH1cbiAgICBcbiAgICBpZiAoIXRoaXMucG9ydGZvbGlvRWxlbWVudC5jb250ZW50KSB7XG4gICAgICBlcnJvcnMucHVzaCh7XG4gICAgICAgIGZpZWxkOiAnY29udGVudCcsXG4gICAgICAgIG1lc3NhZ2U6ICdFbGVtZW50IGNvbnRlbnQgaXMgcmVxdWlyZWQnXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnM6IGVycm9ycy5sZW5ndGggPiAwID8gZXJyb3JzIDogdW5kZWZpbmVkLFxuICAgICAgd2FybmluZ3M6IHdhcm5pbmdzLmxlbmd0aCA+IDAgPyB3YXJuaW5ncyA6IHVuZGVmaW5lZFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2VyaWFsaXplIHRoZSBlbGVtZW50IHRvIG1hcmtkb3duIHdpdGggWUFNTCBmcm9udG1hdHRlclxuICAgKiBGSVg6IENoYW5nZWQgZnJvbSBKU09OIHRvIG1hcmtkb3duIGZvcm1hdCBmb3IgR2l0SHViIHBvcnRmb2xpbyBjb21wYXRpYmlsaXR5XG4gICAqIFNFQ1VSSVRZIEZJWCAjNTQ0OiBQYXJzZSBhbmQgdmFsaWRhdGUgZXhpc3RpbmcgZnJvbnRtYXR0ZXIgaW5zdGVhZCBvZiByZXR1cm5pbmcgYXMtaXNcbiAgICogU0VDVVJJVFkgRklYICM1NDM6IFVzZSBTZWN1cmVZYW1sUGFyc2VyIGZvciByb2J1c3QgZnJvbnRtYXR0ZXIgZGV0ZWN0aW9uXG4gICAqL1xuICBzZXJpYWxpemUoKTogc3RyaW5nIHtcbiAgICAvLyBTRUNVUklUWSBGSVggIzU0MzogVXNlIFNlY3VyZVlhbWxQYXJzZXIgZm9yIHJvYnVzdCBmcm9udG1hdHRlciBkZXRlY3Rpb25cbiAgICAvLyBUaGlzIGhhbmRsZXMgZGlmZmVyZW50IGxpbmUgZW5kaW5ncywgd2hpdGVzcGFjZSB2YXJpYXRpb25zLCBhbmQgbWFsZm9ybWVkIFlBTUxcbiAgICBsZXQgY29udGVudFRvUHJvY2VzcyA9IHRoaXMucG9ydGZvbGlvRWxlbWVudC5jb250ZW50O1xuICAgIGxldCBleGlzdGluZ01ldGFkYXRhOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgbGV0IGJvZHlDb250ZW50ID0gY29udGVudFRvUHJvY2VzcztcbiAgICBcbiAgICAvLyBUcnkgdG8gcGFyc2UgZXhpc3RpbmcgZnJvbnRtYXR0ZXIgaWYgcHJlc2VudFxuICAgIHRyeSB7XG4gICAgICAvLyBTZWN1cmVZYW1sUGFyc2VyIGhhbmRsZXMgYWxsIGVkZ2UgY2FzZXM6XG4gICAgICAvLyAtIERpZmZlcmVudCBsaW5lIGVuZGluZ3MgKFxcbiwgXFxyXFxuKVxuICAgICAgLy8gLSBXaGl0ZXNwYWNlIHZhcmlhdGlvbnNcbiAgICAgIC8vIC0gTWFsZm9ybWVkIFlBTUwgKHJldHVybnMgZW1wdHkgZGF0YSBvYmplY3QpXG4gICAgICAvLyAtIE1pc3NpbmcgY2xvc2luZyBkZWxpbWl0ZXJcbiAgICAgIGNvbnN0IHBhcnNlZCA9IFNlY3VyZVlhbWxQYXJzZXIuc2FmZU1hdHRlcihjb250ZW50VG9Qcm9jZXNzKTtcbiAgICAgIFxuICAgICAgaWYgKHBhcnNlZC5kYXRhICYmIE9iamVjdC5rZXlzKHBhcnNlZC5kYXRhKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIC8vIFNFQ1VSSVRZIEZJWCAjNTQ0OiBWYWxpZGF0ZSBleGlzdGluZyBmcm9udG1hdHRlciBpbnN0ZWFkIG9mIGJ5cGFzc2luZ1xuICAgICAgICBsb2dnZXIuZGVidWcoJ0ZvdW5kIGV4aXN0aW5nIGZyb250bWF0dGVyLCB2YWxpZGF0aW5nIGJlZm9yZSBtZXJnZScpO1xuICAgICAgICBcbiAgICAgICAgLy8gVmFsaWRhdGUgdGhlIHBhcnNlZCBmcm9udG1hdHRlclxuICAgICAgICBjb25zdCB2YWxpZGF0aW9uUmVzdWx0ID0gQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplKFxuICAgICAgICAgIHlhbWwuZHVtcChwYXJzZWQuZGF0YSlcbiAgICAgICAgKTtcbiAgICAgICAgXG4gICAgICAgIGlmICghdmFsaWRhdGlvblJlc3VsdC5pc1ZhbGlkICYmIHZhbGlkYXRpb25SZXN1bHQuc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpIHtcbiAgICAgICAgICAvLyBMb2cgc2VjdXJpdHkgZXZlbnQgZm9yIG1hbGljaW91cyBmcm9udG1hdHRlclxuICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6ICdDT05URU5UX0lOSkVDVElPTl9BVFRFTVBUJyxcbiAgICAgICAgICAgIHNldmVyaXR5OiAnSElHSCcsXG4gICAgICAgICAgICBzb3VyY2U6ICdQb3J0Zm9saW9FbGVtZW50QWRhcHRlci5zZXJpYWxpemUnLFxuICAgICAgICAgICAgZGV0YWlsczogYENyaXRpY2FsIHNlY3VyaXR5IGlzc3VlcyBpbiBmcm9udG1hdHRlcjogJHt2YWxpZGF0aW9uUmVzdWx0LmRldGVjdGVkUGF0dGVybnM/LmpvaW4oJywgJyl9YCxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICAgIGVsZW1lbnRJZDogdGhpcy5pZCxcbiAgICAgICAgICAgICAgZWxlbWVudFR5cGU6IHRoaXMudHlwZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIERvbid0IHVzZSB0aGUgbWFsaWNpb3VzIGZyb250bWF0dGVyLCBjcmVhdGUgbmV3XG4gICAgICAgICAgZXhpc3RpbmdNZXRhZGF0YSA9IHt9O1xuICAgICAgICAgIGJvZHlDb250ZW50ID0gY29udGVudFRvUHJvY2VzczsgLy8gVXNlIG9yaWdpbmFsIGNvbnRlbnRcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBGcm9udG1hdHRlciBpcyBzYWZlLCBtZXJnZSB3aXRoIG91ciBtZXRhZGF0YVxuICAgICAgICAgIGV4aXN0aW5nTWV0YWRhdGEgPSBwYXJzZWQuZGF0YTtcbiAgICAgICAgICBib2R5Q29udGVudCA9IHBhcnNlZC5jb250ZW50O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIElmIFNlY3VyZVlhbWxQYXJzZXIgZmFpbHMgdG8gcGFyc2UsIHRyZWF0IGFzIGNvbnRlbnQgd2l0aG91dCBmcm9udG1hdHRlclxuICAgICAgbG9nZ2VyLndhcm4oJ0ZhaWxlZCB0byBwYXJzZSBwb3RlbnRpYWwgZnJvbnRtYXR0ZXIsIHRyZWF0aW5nIGFzIHBsYWluIGNvbnRlbnQnLCB7XG4gICAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgIH0pO1xuICAgICAgLy8gQ29udGludWUgd2l0aCBlbXB0eSBtZXRhZGF0YSBhbmQgZnVsbCBjb250ZW50XG4gICAgfVxuICAgIFxuICAgIC8vIE1lcmdlIG1ldGFkYXRhLCB3aXRoIG91ciBtZXRhZGF0YSB0YWtpbmcgcHJlY2VkZW5jZSBmb3Igc2VjdXJpdHlcbiAgICAvLyBUaGlzIGVuc3VyZXMgY3JpdGljYWwgZmllbGRzIGxpa2UgSUQgYW5kIHR5cGUgYXJlIGFsd2F5cyBmcm9tIG91ciB2YWxpZGF0ZWQgc291cmNlXG4gICAgY29uc3QgbWVyZ2VkTWV0YWRhdGEgPSB7XG4gICAgICAuLi5leGlzdGluZ01ldGFkYXRhLCAvLyBFeGlzdGluZyBtZXRhZGF0YSBmaXJzdFxuICAgICAgLi4udGhpcy5tZXRhZGF0YSwgICAgLy8gT3VyIHZhbGlkYXRlZCBtZXRhZGF0YSBvdmVyd3JpdGVzXG4gICAgICBpZDogdGhpcy5pZCwgICAgICAgICAvLyBBbHdheXMgdXNlIG91ciBJRFxuICAgICAgdW5pcXVlX2lkOiB0aGlzLmlkLCAgLy8gQ1JJVElDQUwgRklYOiBBZGQgdW5pcXVlX2lkIGZvciBjb2xsZWN0aW9uIHdvcmtmbG93IGNvbXBhdGliaWxpdHlcbiAgICAgIHR5cGU6IHRoaXMudHlwZSwgICAgIC8vIEFsd2F5cyB1c2Ugb3VyIHR5cGVcbiAgICAgIHZlcnNpb246IHRoaXMudmVyc2lvbiAvLyBBbHdheXMgdXNlIG91ciB2ZXJzaW9uXG4gICAgfTtcbiAgICBcbiAgICAvLyBWYWxpZGF0ZSB0aGUgZmluYWwgbWVyZ2VkIG1ldGFkYXRhXG4gICAgY29uc3QgbWV0YWRhdGFZYW1sID0geWFtbC5kdW1wKG1lcmdlZE1ldGFkYXRhLCB7XG4gICAgICBub1JlZnM6IHRydWUsXG4gICAgICBzb3J0S2V5czogZmFsc2UsXG4gICAgICBsaW5lV2lkdGg6IC0xXG4gICAgfSk7XG4gICAgXG4gICAgLy8gRmluYWwgc2VjdXJpdHkgY2hlY2sgb24gdGhlIGNvbXBsZXRlIG1ldGFkYXRhXG4gICAgY29uc3QgZmluYWxWYWxpZGF0aW9uID0gQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplKG1ldGFkYXRhWWFtbCk7XG4gICAgXG4gICAgaWYgKCFmaW5hbFZhbGlkYXRpb24uaXNWYWxpZCAmJiBmaW5hbFZhbGlkYXRpb24uc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpIHtcbiAgICAgIC8vIFRoaXMgc2hvdWxkbid0IGhhcHBlbiB3aXRoIG91ciBzYW5pdGl6ZWQgZGF0YSwgYnV0IGxvZyBpZiBpdCBkb2VzXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdVTklDT0RFX1ZBTElEQVRJT05fRVJST1InLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnNlcmlhbGl6ZScsXG4gICAgICAgIGRldGFpbHM6ICdGaW5hbCBtZXRhZGF0YSB2YWxpZGF0aW9uIGZhaWxlZCBhZnRlciBtZXJnZScsXG4gICAgICAgIG1ldGFkYXRhOiB7IGVsZW1lbnRJZDogdGhpcy5pZCB9XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgLy8gRmFsbCBiYWNrIHRvIG1pbmltYWwgc2FmZSBtZXRhZGF0YVxuICAgICAgY29uc3Qgc2FmZU1ldGFkYXRhID0ge1xuICAgICAgICBpZDogdGhpcy5pZCxcbiAgICAgICAgdW5pcXVlX2lkOiB0aGlzLmlkLCAgLy8gQ1JJVElDQUwgRklYOiBJbmNsdWRlIHVuaXF1ZV9pZCBmb3IgY29sbGVjdGlvbiB3b3JrZmxvd1xuICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgIHZlcnNpb246IHRoaXMudmVyc2lvbixcbiAgICAgICAgbmFtZTogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5uYW1lIHx8ICdVbnRpdGxlZCcpLFxuICAgICAgICBkZXNjcmlwdGlvbjogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCAnJylcbiAgICAgIH07XG4gICAgICBcbiAgICAgIGNvbnN0IHNhZmVGcm9udG1hdHRlciA9IHlhbWwuZHVtcChzYWZlTWV0YWRhdGEsIHtcbiAgICAgICAgbm9SZWZzOiB0cnVlLFxuICAgICAgICBzb3J0S2V5czogZmFsc2UsXG4gICAgICAgIGxpbmVXaWR0aDogLTFcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICByZXR1cm4gYC0tLVxcbiR7c2FmZUZyb250bWF0dGVyfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgICB9XG4gICAgXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBhbmQgc2FuaXRpemVkIG1hcmtkb3duIHdpdGggZnJvbnRtYXR0ZXJcbiAgICByZXR1cm4gYC0tLVxcbiR7bWV0YWRhdGFZYW1sfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNlcmlhbGl6ZSBmcm9tIHN0cmluZyAobm90IGltcGxlbWVudGVkIGZvciBhZGFwdGVyKVxuICAgKi9cbiAgZGVzZXJpYWxpemUoX2RhdGE6IHN0cmluZyk6IHZvaWQge1xuICAgIHRocm93IG5ldyBFcnJvcignRGVzZXJpYWxpemF0aW9uIG5vdCBzdXBwb3J0ZWQgZm9yIFBvcnRmb2xpb0VsZW1lbnRBZGFwdGVyJyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGVsZW1lbnQgc3RhdHVzXG4gICAqL1xuICBnZXRTdGF0dXMoKTogRWxlbWVudFN0YXR1cyB7XG4gICAgcmV0dXJuIEVsZW1lbnRTdGF0dXMuSU5BQ1RJVkU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBvcmlnaW5hbCBwb3J0Zm9saW8gZWxlbWVudCBjb250ZW50XG4gICAqL1xuICBnZXRDb250ZW50KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucG9ydGZvbGlvRWxlbWVudC5jb250ZW50O1xuICB9XG59XG4iXX0=