@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.
112 lines • 15.5 kB
JavaScript
/**
* Content Validation Pipeline for Web UI
*
* Composes the standalone security validators into a single pipeline
* for validating portfolio element content before serving to the browser.
*
* Uses the same validators as the MCPAQLHandler but without coupling
* to the handler's operation dispatch. This is the extraction point
* for the upcoming MCPAQLHandler decomposition.
*
* auto-dollhouse#5 / upstream #1679
* DMCP-SEC-004 compliant: uses UnicodeValidator.normalize() on all inputs
*/
import { extname } from 'node:path';
import { SecureYamlParser } from '../security/secureYamlParser.js';
import { ContentValidator } from '../security/contentValidator.js';
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
import { logger } from '../utils/logger.js';
/** Element types that map to content validation contexts */
const TYPE_TO_CONTEXT = {
personas: 'persona',
skills: 'skill',
templates: 'template',
agents: 'agent',
memories: 'memory',
};
/**
* Validate element content through the security pipeline.
*
* @param filename - The element filename (e.g., "alex-sterling.md")
* @param rawContent - The raw file content string
* @param elementType - The plural element type directory (e.g., "personas")
* @returns Validated content with parsed metadata, or rejection with reason
*/
export function validateElementContent(filename, rawContent, elementType) {
// DMCP-SEC-004: Normalize all inputs via UnicodeValidator to prevent
// homograph attacks, direction override bypasses, and suspicious patterns.
const filenameValidation = UnicodeValidator.normalize(filename);
const contentValidation = UnicodeValidator.normalize(rawContent);
const normalizedFilename = filenameValidation.normalizedContent;
const normalizedContent = contentValidation.normalizedContent;
const normalizedType = elementType.normalize('NFC');
const ext = extname(normalizedFilename);
const isYaml = ext === '.yaml' || ext === '.yml';
const contentContext = TYPE_TO_CONTEXT[normalizedType];
// Step 1: Parse and validate structure (YAML bomb detection, circular refs)
let metadata = {};
let body = '';
try {
if (isYaml) {
// Pure YAML file (memories) — use parseRawYaml for structural validation
// (bomb detection, circular refs, size limits).
// Skip ContentValidator.validateYamlContent() — it produces false positives
// on memory content that legitimately contains code patterns, security
// keywords, and technical documentation. Memories are locally-generated
// trusted content, not untrusted external submissions.
const parsed = SecureYamlParser.parseRawYaml(normalizedContent);
metadata = (typeof parsed === 'object' && parsed !== null) ? parsed : {};
}
else {
// Markdown with YAML frontmatter
const parsed = SecureYamlParser.parse(normalizedContent, { contentContext });
metadata = parsed.data;
body = parsed.content;
}
}
catch (err) {
return {
valid: false,
content: normalizedContent,
metadata: {},
body: '',
rejection: { reason: `Parse validation failed: ${err.message}`, severity: 'high' },
};
}
// Step 2: Content injection pattern detection (markdown elements only)
// YAML memories skip this — they contain legitimate code patterns and
// technical content that triggers false positives. The structural YAML
// parsing above (bomb/circular ref detection) is sufficient for local content.
if (!isYaml) {
const validation = ContentValidator.validateAndSanitize(normalizedContent, {
contentContext,
});
if (!validation.isValid) {
logger.warn('[ContentPipeline] Content rejected', {
filename,
elementType,
patterns: validation.detectedPatterns,
severity: validation.severity,
});
return {
valid: false,
content: normalizedContent,
metadata,
body,
rejection: {
reason: 'Content failed security validation',
severity: validation.severity,
patterns: validation.detectedPatterns,
},
};
}
}
// Step 3: Return validated content
return {
valid: true,
content: rawContent,
metadata,
body,
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGVudFBpcGVsaW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dlYi9jb250ZW50UGlwZWxpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBRUgsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNuRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQWdDLE1BQU0saUNBQWlDLENBQUM7QUFDakcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLDREQUE0RDtBQUM1RCxNQUFNLGVBQWUsR0FBMEU7SUFDN0YsUUFBUSxFQUFFLFNBQVM7SUFDbkIsTUFBTSxFQUFFLE9BQU87SUFDZixTQUFTLEVBQUUsVUFBVTtJQUNyQixNQUFNLEVBQUUsT0FBTztJQUNmLFFBQVEsRUFBRSxRQUFRO0NBQ25CLENBQUM7QUF1Q0Y7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxzQkFBc0IsQ0FDcEMsUUFBZ0IsRUFDaEIsVUFBa0IsRUFDbEIsV0FBbUI7SUFFbkIscUVBQXFFO0lBQ3JFLDJFQUEyRTtJQUMzRSxNQUFNLGtCQUFrQixHQUFHLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNoRSxNQUFNLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNqRSxNQUFNLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDLGlCQUFpQixDQUFDO0lBQ2hFLE1BQU0saUJBQWlCLEdBQUcsaUJBQWlCLENBQUMsaUJBQWlCLENBQUM7SUFDOUQsTUFBTSxjQUFjLEdBQUcsV0FBVyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUVwRCxNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUN4QyxNQUFNLE1BQU0sR0FBRyxHQUFHLEtBQUssT0FBTyxJQUFJLEdBQUcsS0FBSyxNQUFNLENBQUM7SUFDakQsTUFBTSxjQUFjLEdBQUcsZUFBZSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBRXZELDRFQUE0RTtJQUM1RSxJQUFJLFFBQVEsR0FBMkIsRUFBRSxDQUFDO0lBQzFDLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUVkLElBQUksQ0FBQztRQUNILElBQUksTUFBTSxFQUFFLENBQUM7WUFDWCx5RUFBeUU7WUFDekUsZ0RBQWdEO1lBQ2hELDRFQUE0RTtZQUM1RSx1RUFBdUU7WUFDdkUsd0VBQXdFO1lBQ3hFLHVEQUF1RDtZQUN2RCxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsaUJBQWlCLENBQUMsQ0FBQztZQUNoRSxRQUFRLEdBQUcsQ0FBQyxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksTUFBTSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMzRSxDQUFDO2FBQU0sQ0FBQztZQUNOLGlDQUFpQztZQUNqQyxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO1lBQzdFLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDO1lBQ3ZCLElBQUksR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO1FBQ3hCLENBQUM7SUFDSCxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU87WUFDTCxLQUFLLEVBQUUsS0FBSztZQUNaLE9BQU8sRUFBRSxpQkFBaUI7WUFDMUIsUUFBUSxFQUFFLEVBQUU7WUFDWixJQUFJLEVBQUUsRUFBRTtZQUNSLFNBQVMsRUFBRSxFQUFFLE1BQU0sRUFBRSw0QkFBNkIsR0FBYSxDQUFDLE9BQU8sRUFBRSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUU7U0FDOUYsQ0FBQztJQUNKLENBQUM7SUFFRCx1RUFBdUU7SUFDdkUsc0VBQXNFO0lBQ3RFLHVFQUF1RTtJQUN2RSwrRUFBK0U7SUFDL0UsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ1osTUFBTSxVQUFVLEdBQTRCLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLGlCQUFpQixFQUFFO1lBQ2xHLGNBQWM7U0FDZixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0NBQW9DLEVBQUU7Z0JBQ2hELFFBQVE7Z0JBQ1IsV0FBVztnQkFDWCxRQUFRLEVBQUUsVUFBVSxDQUFDLGdCQUFnQjtnQkFDckMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxRQUFRO2FBQzlCLENBQUMsQ0FBQztZQUNILE9BQU87Z0JBQ0wsS0FBSyxFQUFFLEtBQUs7Z0JBQ1osT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsUUFBUTtnQkFDUixJQUFJO2dCQUNKLFNBQVMsRUFBRTtvQkFDVCxNQUFNLEVBQUUsb0NBQW9DO29CQUM1QyxRQUFRLEVBQUUsVUFBVSxDQUFDLFFBQVE7b0JBQzdCLFFBQVEsRUFBRSxVQUFVLENBQUMsZ0JBQWdCO2lCQUN0QzthQUNGLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELG1DQUFtQztJQUNuQyxPQUFPO1FBQ0wsS0FBSyxFQUFFLElBQUk7UUFDWCxPQUFPLEVBQUUsVUFBVTtRQUNuQixRQUFRO1FBQ1IsSUFBSTtLQUNMLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb250ZW50IFZhbGlkYXRpb24gUGlwZWxpbmUgZm9yIFdlYiBVSVxuICpcbiAqIENvbXBvc2VzIHRoZSBzdGFuZGFsb25lIHNlY3VyaXR5IHZhbGlkYXRvcnMgaW50byBhIHNpbmdsZSBwaXBlbGluZVxuICogZm9yIHZhbGlkYXRpbmcgcG9ydGZvbGlvIGVsZW1lbnQgY29udGVudCBiZWZvcmUgc2VydmluZyB0byB0aGUgYnJvd3Nlci5cbiAqXG4gKiBVc2VzIHRoZSBzYW1lIHZhbGlkYXRvcnMgYXMgdGhlIE1DUEFRTEhhbmRsZXIgYnV0IHdpdGhvdXQgY291cGxpbmdcbiAqIHRvIHRoZSBoYW5kbGVyJ3Mgb3BlcmF0aW9uIGRpc3BhdGNoLiBUaGlzIGlzIHRoZSBleHRyYWN0aW9uIHBvaW50XG4gKiBmb3IgdGhlIHVwY29taW5nIE1DUEFRTEhhbmRsZXIgZGVjb21wb3NpdGlvbi5cbiAqXG4gKiBhdXRvLWRvbGxob3VzZSM1IC8gdXBzdHJlYW0gIzE2NzlcbiAqIERNQ1AtU0VDLTAwNCBjb21wbGlhbnQ6IHVzZXMgVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoKSBvbiBhbGwgaW5wdXRzXG4gKi9cblxuaW1wb3J0IHsgZXh0bmFtZSB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yLCB0eXBlIENvbnRlbnRWYWxpZGF0aW9uUmVzdWx0IH0gZnJvbSAnLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbi8qKiBFbGVtZW50IHR5cGVzIHRoYXQgbWFwIHRvIGNvbnRlbnQgdmFsaWRhdGlvbiBjb250ZXh0cyAqL1xuY29uc3QgVFlQRV9UT19DT05URVhUOiBSZWNvcmQ8c3RyaW5nLCAncGVyc29uYScgfCAnc2tpbGwnIHwgJ3RlbXBsYXRlJyB8ICdhZ2VudCcgfCAnbWVtb3J5Jz4gPSB7XG4gIHBlcnNvbmFzOiAncGVyc29uYScsXG4gIHNraWxsczogJ3NraWxsJyxcbiAgdGVtcGxhdGVzOiAndGVtcGxhdGUnLFxuICBhZ2VudHM6ICdhZ2VudCcsXG4gIG1lbW9yaWVzOiAnbWVtb3J5Jyxcbn07XG5cbi8qKiBLbm93biBtZXRhZGF0YSBmaWVsZHMgZXh0cmFjdGVkIGZyb20gWUFNTCBmcm9udG1hdHRlciBmb3Igd2ViIGRpc3BsYXkgKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWxlbWVudERpc3BsYXlNZXRhZGF0YSB7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBhdXRob3I/OiBzdHJpbmc7XG4gIGNhdGVnb3J5Pzogc3RyaW5nO1xuICBjcmVhdGVkPzogc3RyaW5nO1xuICBjcmVhdGVkX2RhdGU/OiBzdHJpbmc7XG4gIG1vZGlmaWVkPzogc3RyaW5nO1xuICB0YWdzPzogc3RyaW5nW107XG4gIGxpY2Vuc2U/OiBzdHJpbmc7XG4gIGFnZV9yYXRpbmc/OiBzdHJpbmc7XG4gIHRyaWdnZXJzPzogc3RyaW5nW107XG4gIGluc3RydWN0aW9ucz86IHN0cmluZztcbiAgY29vcmRpbmF0aW9uX3N0cmF0ZWd5Pzogc3RyaW5nO1xuICB1c2VfY2FzZXM/OiBzdHJpbmdbXTtcbiAgcHJvZmljaWVuY3lfbGV2ZWxzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgZ2F0ZWtlZXBlcj86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBnb2FsPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGF1dG9ub215PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIG1lbW9yeVR5cGU/OiBzdHJpbmc7XG4gIFtrZXk6IHN0cmluZ106IHVua25vd247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGlwZWxpbmVSZXN1bHQge1xuICB2YWxpZDogYm9vbGVhbjtcbiAgY29udGVudDogc3RyaW5nO1xuICBtZXRhZGF0YTogRWxlbWVudERpc3BsYXlNZXRhZGF0YTtcbiAgYm9keTogc3RyaW5nO1xuICByZWplY3Rpb24/OiB7XG4gICAgcmVhc29uOiBzdHJpbmc7XG4gICAgc2V2ZXJpdHk/OiBzdHJpbmc7XG4gICAgcGF0dGVybnM/OiBzdHJpbmdbXTtcbiAgfTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBlbGVtZW50IGNvbnRlbnQgdGhyb3VnaCB0aGUgc2VjdXJpdHkgcGlwZWxpbmUuXG4gKlxuICogQHBhcmFtIGZpbGVuYW1lIC0gVGhlIGVsZW1lbnQgZmlsZW5hbWUgKGUuZy4sIFwiYWxleC1zdGVybGluZy5tZFwiKVxuICogQHBhcmFtIHJhd0NvbnRlbnQgLSBUaGUgcmF3IGZpbGUgY29udGVudCBzdHJpbmdcbiAqIEBwYXJhbSBlbGVtZW50VHlwZSAtIFRoZSBwbHVyYWwgZWxlbWVudCB0eXBlIGRpcmVjdG9yeSAoZS5nLiwgXCJwZXJzb25hc1wiKVxuICogQHJldHVybnMgVmFsaWRhdGVkIGNvbnRlbnQgd2l0aCBwYXJzZWQgbWV0YWRhdGEsIG9yIHJlamVjdGlvbiB3aXRoIHJlYXNvblxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVFbGVtZW50Q29udGVudChcbiAgZmlsZW5hbWU6IHN0cmluZyxcbiAgcmF3Q29udGVudDogc3RyaW5nLFxuICBlbGVtZW50VHlwZTogc3RyaW5nLFxuKTogUGlwZWxpbmVSZXN1bHQge1xuICAvLyBETUNQLVNFQy0wMDQ6IE5vcm1hbGl6ZSBhbGwgaW5wdXRzIHZpYSBVbmljb2RlVmFsaWRhdG9yIHRvIHByZXZlbnRcbiAgLy8gaG9tb2dyYXBoIGF0dGFja3MsIGRpcmVjdGlvbiBvdmVycmlkZSBieXBhc3NlcywgYW5kIHN1c3BpY2lvdXMgcGF0dGVybnMuXG4gIGNvbnN0IGZpbGVuYW1lVmFsaWRhdGlvbiA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGZpbGVuYW1lKTtcbiAgY29uc3QgY29udGVudFZhbGlkYXRpb24gPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShyYXdDb250ZW50KTtcbiAgY29uc3Qgbm9ybWFsaXplZEZpbGVuYW1lID0gZmlsZW5hbWVWYWxpZGF0aW9uLm5vcm1hbGl6ZWRDb250ZW50O1xuICBjb25zdCBub3JtYWxpemVkQ29udGVudCA9IGNvbnRlbnRWYWxpZGF0aW9uLm5vcm1hbGl6ZWRDb250ZW50O1xuICBjb25zdCBub3JtYWxpemVkVHlwZSA9IGVsZW1lbnRUeXBlLm5vcm1hbGl6ZSgnTkZDJyk7XG5cbiAgY29uc3QgZXh0ID0gZXh0bmFtZShub3JtYWxpemVkRmlsZW5hbWUpO1xuICBjb25zdCBpc1lhbWwgPSBleHQgPT09ICcueWFtbCcgfHwgZXh0ID09PSAnLnltbCc7XG4gIGNvbnN0IGNvbnRlbnRDb250ZXh0ID0gVFlQRV9UT19DT05URVhUW25vcm1hbGl6ZWRUeXBlXTtcblxuICAvLyBTdGVwIDE6IFBhcnNlIGFuZCB2YWxpZGF0ZSBzdHJ1Y3R1cmUgKFlBTUwgYm9tYiBkZXRlY3Rpb24sIGNpcmN1bGFyIHJlZnMpXG4gIGxldCBtZXRhZGF0YTogRWxlbWVudERpc3BsYXlNZXRhZGF0YSA9IHt9O1xuICBsZXQgYm9keSA9ICcnO1xuXG4gIHRyeSB7XG4gICAgaWYgKGlzWWFtbCkge1xuICAgICAgLy8gUHVyZSBZQU1MIGZpbGUgKG1lbW9yaWVzKSDigJQgdXNlIHBhcnNlUmF3WWFtbCBmb3Igc3RydWN0dXJhbCB2YWxpZGF0aW9uXG4gICAgICAvLyAoYm9tYiBkZXRlY3Rpb24sIGNpcmN1bGFyIHJlZnMsIHNpemUgbGltaXRzKS5cbiAgICAgIC8vIFNraXAgQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZVlhbWxDb250ZW50KCkg4oCUIGl0IHByb2R1Y2VzIGZhbHNlIHBvc2l0aXZlc1xuICAgICAgLy8gb24gbWVtb3J5IGNvbnRlbnQgdGhhdCBsZWdpdGltYXRlbHkgY29udGFpbnMgY29kZSBwYXR0ZXJucywgc2VjdXJpdHlcbiAgICAgIC8vIGtleXdvcmRzLCBhbmQgdGVjaG5pY2FsIGRvY3VtZW50YXRpb24uIE1lbW9yaWVzIGFyZSBsb2NhbGx5LWdlbmVyYXRlZFxuICAgICAgLy8gdHJ1c3RlZCBjb250ZW50LCBub3QgdW50cnVzdGVkIGV4dGVybmFsIHN1Ym1pc3Npb25zLlxuICAgICAgY29uc3QgcGFyc2VkID0gU2VjdXJlWWFtbFBhcnNlci5wYXJzZVJhd1lhbWwobm9ybWFsaXplZENvbnRlbnQpO1xuICAgICAgbWV0YWRhdGEgPSAodHlwZW9mIHBhcnNlZCA9PT0gJ29iamVjdCcgJiYgcGFyc2VkICE9PSBudWxsKSA/IHBhcnNlZCA6IHt9O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBNYXJrZG93biB3aXRoIFlBTUwgZnJvbnRtYXR0ZXJcbiAgICAgIGNvbnN0IHBhcnNlZCA9IFNlY3VyZVlhbWxQYXJzZXIucGFyc2Uobm9ybWFsaXplZENvbnRlbnQsIHsgY29udGVudENvbnRleHQgfSk7XG4gICAgICBtZXRhZGF0YSA9IHBhcnNlZC5kYXRhO1xuICAgICAgYm9keSA9IHBhcnNlZC5jb250ZW50O1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHZhbGlkOiBmYWxzZSxcbiAgICAgIGNvbnRlbnQ6IG5vcm1hbGl6ZWRDb250ZW50LFxuICAgICAgbWV0YWRhdGE6IHt9LFxuICAgICAgYm9keTogJycsXG4gICAgICByZWplY3Rpb246IHsgcmVhc29uOiBgUGFyc2UgdmFsaWRhdGlvbiBmYWlsZWQ6ICR7KGVyciBhcyBFcnJvcikubWVzc2FnZX1gLCBzZXZlcml0eTogJ2hpZ2gnIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8vIFN0ZXAgMjogQ29udGVudCBpbmplY3Rpb24gcGF0dGVybiBkZXRlY3Rpb24gKG1hcmtkb3duIGVsZW1lbnRzIG9ubHkpXG4gIC8vIFlBTUwgbWVtb3JpZXMgc2tpcCB0aGlzIOKAlCB0aGV5IGNvbnRhaW4gbGVnaXRpbWF0ZSBjb2RlIHBhdHRlcm5zIGFuZFxuICAvLyB0ZWNobmljYWwgY29udGVudCB0aGF0IHRyaWdnZXJzIGZhbHNlIHBvc2l0aXZlcy4gVGhlIHN0cnVjdHVyYWwgWUFNTFxuICAvLyBwYXJzaW5nIGFib3ZlIChib21iL2NpcmN1bGFyIHJlZiBkZXRlY3Rpb24pIGlzIHN1ZmZpY2llbnQgZm9yIGxvY2FsIGNvbnRlbnQuXG4gIGlmICghaXNZYW1sKSB7XG4gICAgY29uc3QgdmFsaWRhdGlvbjogQ29udGVudFZhbGlkYXRpb25SZXN1bHQgPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUobm9ybWFsaXplZENvbnRlbnQsIHtcbiAgICAgIGNvbnRlbnRDb250ZXh0LFxuICAgIH0pO1xuXG4gICAgaWYgKCF2YWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKCdbQ29udGVudFBpcGVsaW5lXSBDb250ZW50IHJlamVjdGVkJywge1xuICAgICAgICBmaWxlbmFtZSxcbiAgICAgICAgZWxlbWVudFR5cGUsXG4gICAgICAgIHBhdHRlcm5zOiB2YWxpZGF0aW9uLmRldGVjdGVkUGF0dGVybnMsXG4gICAgICAgIHNldmVyaXR5OiB2YWxpZGF0aW9uLnNldmVyaXR5LFxuICAgICAgfSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWxpZDogZmFsc2UsXG4gICAgICAgIGNvbnRlbnQ6IG5vcm1hbGl6ZWRDb250ZW50LFxuICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAgYm9keSxcbiAgICAgICAgcmVqZWN0aW9uOiB7XG4gICAgICAgICAgcmVhc29uOiAnQ29udGVudCBmYWlsZWQgc2VjdXJpdHkgdmFsaWRhdGlvbicsXG4gICAgICAgICAgc2V2ZXJpdHk6IHZhbGlkYXRpb24uc2V2ZXJpdHksXG4gICAgICAgICAgcGF0dGVybnM6IHZhbGlkYXRpb24uZGV0ZWN0ZWRQYXR0ZXJucyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLy8gU3RlcCAzOiBSZXR1cm4gdmFsaWRhdGVkIGNvbnRlbnRcbiAgcmV0dXJuIHtcbiAgICB2YWxpZDogdHJ1ZSxcbiAgICBjb250ZW50OiByYXdDb250ZW50LFxuICAgIG1ldGFkYXRhLFxuICAgIGJvZHksXG4gIH07XG59XG4iXX0=