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.

174 lines 20.6 kB
/** * Code Scanner - Static code analysis for security vulnerabilities * Detects common security issues in source code */ import { SecurityRules } from '../rules/SecurityRules.js'; import fs from 'fs/promises'; import path from 'path'; import { glob } from 'glob'; export class CodeScanner { name = 'CodeScanner'; config; rules = []; constructor(config) { this.config = config; this.loadRules(); } /** * Load security rules based on configuration */ loadRules() { const ruleLoader = new SecurityRules(); for (const ruleSet of this.config.rules) { switch (ruleSet) { case 'OWASP-Top-10': this.rules.push(...ruleLoader.getOWASPRules()); break; case 'CWE-Top-25': this.rules.push(...ruleLoader.getCWERules()); break; case 'DollhouseMCP-Security': this.rules.push(...ruleLoader.getDollhouseMCPRules()); break; default: // Custom rule sets can be added here break; } } } /** * Scan files for security vulnerabilities */ async scan(context) { const findings = []; const files = await this.getFilesToScan(context.projectRoot); for (const file of files) { try { const content = await fs.readFile(file, 'utf-8'); const fileFindings = await this.scanFile(file, content, context); findings.push(...fileFindings); } catch (error) { // Skip files that can't be read continue; } } return findings; } /** * Get list of files to scan */ async getFilesToScan(projectRoot) { const patterns = ['**/*.ts', '**/*.js', '**/*.jsx', '**/*.tsx', '**/*.json', '**/*.yml', '**/*.yaml']; const ignore = this.config.exclude || ['node_modules/**', 'dist/**', 'coverage/**']; const files = []; for (const pattern of patterns) { const matches = await glob(pattern, { cwd: projectRoot, ignore, absolute: true }); files.push(...matches); } return files; } /** * Scan a single file for vulnerabilities */ async scanFile(filePath, content, context) { const findings = []; const lines = content.split('\n'); const fileContext = { ...context, fileType: path.extname(filePath), isTest: filePath.includes('test') || filePath.includes('spec') }; for (const rule of this.rules) { // Skip test-specific rules in non-test files if (rule.tags?.includes('test-only') && !fileContext.isTest) { continue; } // Pattern-based detection if (rule.pattern) { const matches = this.findPatternMatches(content, lines, rule); for (const match of matches) { findings.push({ ruleId: rule.id, severity: rule.severity, message: `${rule.name}: ${match.message}`, file: filePath, line: match.line, column: match.column, code: match.code, remediation: rule.remediation, confidence: this.calculateConfidence(match, rule, fileContext) }); } } // Custom check function if (rule.check) { const customFindings = rule.check(content, fileContext); findings.push(...customFindings.map(f => ({ ...f, file: filePath }))); } } return findings; } /** * Find pattern matches in content */ findPatternMatches(content, lines, rule) { const matches = []; if (!rule.pattern) return matches; // Reset regex state rule.pattern.lastIndex = 0; let match; while ((match = rule.pattern.exec(content)) !== null) { const position = this.getLineAndColumn(content, match.index); const code = lines[position.line - 1]?.trim() || ''; matches.push({ line: position.line, column: position.column, code: code.substring(0, 100), // Limit code snippet length message: rule.description }); } return matches; } /** * Convert string index to line and column */ getLineAndColumn(content, index) { const lines = content.substring(0, index).split('\n'); return { line: lines.length, column: lines[lines.length - 1].length + 1 }; } /** * Calculate confidence level for a finding */ calculateConfidence(match, rule, context) { // High confidence for exact pattern matches if (rule.tags?.includes('high-confidence')) { return 'high'; } // Low confidence in test files if (context.isTest) { return 'low'; } // Check for common false positive indicators const code = match.code.toLowerCase(); if (code.includes('example') || code.includes('test') || code.includes('demo')) { return 'low'; } return 'medium'; } isEnabled() { return this.config.enabled; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29kZVNjYW5uZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VjdXJpdHkvYXVkaXQvc2Nhbm5lcnMvQ29kZVNjYW5uZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBR0gsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM3QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQVE1QixNQUFNLE9BQU8sV0FBVztJQUN0QixJQUFJLEdBQUcsYUFBYSxDQUFDO0lBQ2IsTUFBTSxDQUFvQjtJQUMxQixLQUFLLEdBQW1CLEVBQUUsQ0FBQztJQUVuQyxZQUFZLE1BQXlCO1FBQ25DLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxTQUFTO1FBQ2YsTUFBTSxVQUFVLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUV2QyxLQUFLLE1BQU0sT0FBTyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDeEMsUUFBUSxPQUFPLEVBQUUsQ0FBQztnQkFDaEIsS0FBSyxjQUFjO29CQUNqQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO29CQUMvQyxNQUFNO2dCQUNSLEtBQUssWUFBWTtvQkFDZixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO29CQUM3QyxNQUFNO2dCQUNSLEtBQUssdUJBQXVCO29CQUMxQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUs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LFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUM7WUFDM0MsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUVELCtCQUErQjtRQUMvQixJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNuQixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCw2Q0FBNkM7UUFDN0MsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0QyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDL0UsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELFNBQVM7UUFDUCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO0lBQzdCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29kZSBTY2FubmVyIC0gU3RhdGljIGNvZGUgYW5hbHlzaXMgZm9yIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdGllc1xuICogRGV0ZWN0cyBjb21tb24gc2VjdXJpdHkgaXNzdWVzIGluIHNvdXJjZSBjb2RlXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBTZWN1cml0eVNjYW5uZXIsIFNlY3VyaXR5RmluZGluZywgU2NhbkNvbnRleHQsIFNlY3VyaXR5UnVsZSB9IGZyb20gJy4uL3R5cGVzLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5UnVsZXMgfSBmcm9tICcuLi9ydWxlcy9TZWN1cml0eVJ1bGVzLmpzJztcbmltcG9ydCBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGdsb2IgfSBmcm9tICdnbG9iJztcblxuaW50ZXJmYWNlIENvZGVTY2FubmVyQ29uZmlnIHtcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgcnVsZXM6IHN0cmluZ1tdO1xuICBleGNsdWRlPzogc3RyaW5nW107XG59XG5cbmV4cG9ydCBjbGFzcyBDb2RlU2Nhbm5lciBpbXBsZW1lbnRzIFNlY3VyaXR5U2Nhbm5lciB7XG4gIG5hbWUgPSAnQ29kZVNjYW5uZXInO1xuICBwcml2YXRlIGNvbmZpZzogQ29kZVNjYW5uZXJDb25maWc7XG4gIHByaXZhdGUgcnVsZXM6IFNlY3VyaXR5UnVsZVtdID0gW107XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBDb2RlU2Nhbm5lckNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMubG9hZFJ1bGVzKCk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZCBzZWN1cml0eSBydWxlcyBiYXNlZCBvbiBjb25maWd1cmF0aW9uXG4gICAqL1xuICBwcml2YXRlIGxvYWRSdWxlcygpOiB2b2lkIHtcbiAgICBjb25zdCBydWxlTG9hZGVyID0gbmV3IFNlY3VyaXR5UnVsZXMoKTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHJ1bGVTZXQgb2YgdGhpcy5jb25maWcucnVsZXMpIHtcbiAgICAgIHN3aXRjaCAocnVsZVNldCkge1xuICAgICAgICBjYXNlICdPV0FTUC1Ub3AtMTAnOlxuICAgICAgICAgIHRoaXMucnVsZXMucHVzaCguLi5ydWxlTG9hZGVyLmdldE9XQVNQUnVsZXMoKSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ0NXRS1Ub3AtMjUnOlxuICAgICAgICAgIHRoaXMucnVsZXMucHVzaCguLi5ydWxlTG9hZGVyLmdldENXRVJ1bGVzKCkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdEb2xsaG91c2VNQ1AtU2VjdXJpdHknOlxuICAgICAgICAgIHRoaXMucnVsZXMucHVzaCguLi5ydWxlTG9hZGVyLmdldERvbGxob3VzZU1DUFJ1bGVzKCkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIC8vIEN1c3RvbSBydWxlIHNldHMgY2FuIGJlIGFkZGVkIGhlcmVcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2NhbiBmaWxlcyBmb3Igc2VjdXJpdHkgdnVsbmVyYWJpbGl0aWVzXG4gICAqL1xuICBhc3luYyBzY2FuKGNvbnRleHQ6IFNjYW5Db250ZXh0KTogUHJvbWlzZTxTZWN1cml0eUZpbmRpbmdbXT4ge1xuICAgIGNvbnN0IGZpbmRpbmdzOiBTZWN1cml0eUZpbmRpbmdbXSA9IFtdO1xuICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgdGhpcy5nZXRGaWxlc1RvU2Nhbihjb250ZXh0LnByb2plY3RSb290KTtcblxuICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGZpbGUsICd1dGYtOCcpO1xuICAgICAgICBjb25zdCBmaWxlRmluZGluZ3MgPSBhd2FpdCB0aGlzLnNjYW5GaWxlKGZpbGUsIGNvbnRlbnQsIGNvbnRleHQpO1xuICAgICAgICBmaW5kaW5ncy5wdXNoKC4uLmZpbGVGaW5kaW5ncyk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBTa2lwIGZpbGVzIHRoYXQgY2FuJ3QgYmUgcmVhZFxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmluZGluZ3M7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGxpc3Qgb2YgZmlsZXMgdG8gc2NhblxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRGaWxlc1RvU2Nhbihwcm9qZWN0Um9vdDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IHBhdHRlcm5zID0gWycqKi8qLnRzJywgJyoqLyouanMnLCAnKiovKi5qc3gnLCAnKiovKi50c3gnLCAnKiovKi5qc29uJywgJyoqLyoueW1sJywgJyoqLyoueWFtbCddO1xuICAgIGNvbnN0IGlnbm9yZSA9IHRoaXMuY29uZmlnLmV4Y2x1ZGUgfHwgWydub2RlX21vZHVsZXMvKionLCAnZGlzdC8qKicsICdjb3ZlcmFnZS8qKiddO1xuICAgIFxuICAgIGNvbnN0IGZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcGF0dGVybiBvZiBwYXR0ZXJucykge1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IGF3YWl0IGdsb2IocGF0dGVybiwge1xuICAgICAgICBjd2Q6IHByb2plY3RSb290LFxuICAgICAgICBpZ25vcmUsXG4gICAgICAgIGFic29sdXRlOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIGZpbGVzLnB1c2goLi4ubWF0Y2hlcyk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBmaWxlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTY2FuIGEgc2luZ2xlIGZpbGUgZm9yIHZ1bG5lcmFiaWxpdGllc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzY2FuRmlsZShcbiAgICBmaWxlUGF0aDogc3RyaW5nLCBcbiAgICBjb250ZW50OiBzdHJpbmcsIFxuICAgIGNvbnRleHQ6IFNjYW5Db250ZXh0XG4gICk6IFByb21pc2U8U2VjdXJpdHlGaW5kaW5nW10+IHtcbiAgICBjb25zdCBmaW5kaW5nczogU2VjdXJpdHlGaW5kaW5nW10gPSBbXTtcbiAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpO1xuICAgIGNvbnN0IGZpbGVDb250ZXh0ID0ge1xuICAgICAgLi4uY29udGV4dCxcbiAgICAgIGZpbGVUeXBlOiBwYXRoLmV4dG5hbWUoZmlsZVBhdGgpLFxuICAgICAgaXNUZXN0OiBmaWxlUGF0aC5pbmNsdWRlcygndGVzdCcpIHx8IGZpbGVQYXRoLmluY2x1ZGVzKCdzcGVjJylcbiAgICB9O1xuXG4gICAgZm9yIChjb25zdCBydWxlIG9mIHRoaXMucnVsZXMpIHtcbiAgICAgIC8vIFNraXAgdGVzdC1zcGVjaWZpYyBydWxlcyBpbiBub24tdGVzdCBmaWxlc1xuICAgICAgaWYgKHJ1bGUudGFncz8uaW5jbHVkZXMoJ3Rlc3Qtb25seScpICYmICFmaWxlQ29udGV4dC5pc1Rlc3QpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIFBhdHRlcm4tYmFzZWQgZGV0ZWN0aW9uXG4gICAgICBpZiAocnVsZS5wYXR0ZXJuKSB7XG4gICAgICAgIGNvbnN0IG1hdGNoZXMgPSB0aGlzLmZpbmRQYXR0ZXJuTWF0Y2hlcyhjb250ZW50LCBsaW5lcywgcnVsZSk7XG4gICAgICAgIGZvciAoY29uc3QgbWF0Y2ggb2YgbWF0Y2hlcykge1xuICAgICAgICAgIGZpbmRpbmdzLnB1c2goe1xuICAgICAgICAgICAgcnVsZUlkOiBydWxlLmlkLFxuICAgICAgICAgICAgc2V2ZXJpdHk6IHJ1bGUuc2V2ZXJpdHksXG4gICAgICAgICAgICBtZXNzYWdlOiBgJHtydWxlLm5hbWV9OiAke21hdGNoLm1lc3NhZ2V9YCxcbiAgICAgICAgICAgIGZpbGU6IGZpbGVQYXRoLFxuICAgICAgICAgICAgbGluZTogbWF0Y2gubGluZSxcbiAgICAgICAgICAgIGNvbHVtbjogbWF0Y2guY29sdW1uLFxuICAgICAgICAgICAgY29kZTogbWF0Y2guY29kZSxcbiAgICAgICAgICAgIHJlbWVkaWF0aW9uOiBydWxlLnJlbWVkaWF0aW9uLFxuICAgICAgICAgICAgY29uZmlkZW5jZTogdGhpcy5jYWxjdWxhdGVDb25maWRlbmNlKG1hdGNoLCBydWxlLCBmaWxlQ29udGV4dClcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBDdXN0b20gY2hlY2sgZnVuY3Rpb25cbiAgICAgIGlmIChydWxlLmNoZWNrKSB7XG4gICAgICAgIGNvbnN0IGN1c3RvbUZpbmRpbmdzID0gcnVsZS5jaGVjayhjb250ZW50LCBmaWxlQ29udGV4dCk7XG4gICAgICAgIGZpbmRpbmdzLnB1c2goLi4uY3VzdG9tRmluZGluZ3MubWFwKGYgPT4gKHtcbiAgICAgICAgICAuLi5mLFxuICAgICAgICAgIGZpbGU6IGZpbGVQYXRoXG4gICAgICAgIH0pKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbmRpbmdzO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgcGF0dGVybiBtYXRjaGVzIGluIGNvbnRlbnRcbiAgICovXG4gIHByaXZhdGUgZmluZFBhdHRlcm5NYXRjaGVzKFxuICAgIGNvbnRlbnQ6IHN0cmluZywgXG4gICAgbGluZXM6IHN0cmluZ1tdLCBcbiAgICBydWxlOiBTZWN1cml0eVJ1bGVcbiAgKTogQXJyYXk8e2xpbmU6IG51bWJlcjsgY29sdW1uOiBudW1iZXI7IGNvZGU6IHN0cmluZzsgbWVzc2FnZTogc3RyaW5nfT4ge1xuICAgIGNvbnN0IG1hdGNoZXM6IEFycmF5PHtsaW5lOiBudW1iZXI7IGNvbHVtbjogbnVtYmVyOyBjb2RlOiBzdHJpbmc7IG1lc3NhZ2U6IHN0cmluZ30+ID0gW107XG4gICAgXG4gICAgaWYgKCFydWxlLnBhdHRlcm4pIHJldHVybiBtYXRjaGVzO1xuXG4gICAgLy8gUmVzZXQgcmVnZXggc3RhdGVcbiAgICBydWxlLnBhdHRlcm4ubGFzdEluZGV4ID0gMDtcbiAgICBcbiAgICBsZXQgbWF0Y2g7XG4gICAgd2hpbGUgKChtYXRjaCA9IHJ1bGUucGF0dGVybi5leGVjKGNvbnRlbnQpKSAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgcG9zaXRpb24gPSB0aGlzLmdldExpbmVBbmRDb2x1bW4oY29udGVudCwgbWF0Y2guaW5kZXgpO1xuICAgICAgY29uc3QgY29kZSA9IGxpbmVzW3Bvc2l0aW9uLmxpbmUgLSAxXT8udHJpbSgpIHx8ICcnO1xuICAgICAgXG4gICAgICBtYXRjaGVzLnB1c2goe1xuICAgICAgICBsaW5lOiBwb3NpdGlvbi5saW5lLFxuICAgICAgICBjb2x1bW46IHBvc2l0aW9uLmNvbHVtbixcbiAgICAgICAgY29kZTogY29kZS5zdWJzdHJpbmcoMCwgMTAwKSwgLy8gTGltaXQgY29kZSBzbmlwcGV0IGxlbmd0aFxuICAgICAgICBtZXNzYWdlOiBydWxlLmRlc2NyaXB0aW9uXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbWF0Y2hlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHN0cmluZyBpbmRleCB0byBsaW5lIGFuZCBjb2x1bW5cbiAgICovXG4gIHByaXZhdGUgZ2V0TGluZUFuZENvbHVtbihjb250ZW50OiBzdHJpbmcsIGluZGV4OiBudW1iZXIpOiB7bGluZTogbnVtYmVyOyBjb2x1bW46IG51bWJlcn0ge1xuICAgIGNvbnN0IGxpbmVzID0gY29udGVudC5zdWJzdHJpbmcoMCwgaW5kZXgpLnNwbGl0KCdcXG4nKTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluZTogbGluZXMubGVuZ3RoLFxuICAgICAgY29sdW1uOiBsaW5lc1tsaW5lcy5sZW5ndGggLSAxXS5sZW5ndGggKyAxXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgY29uZmlkZW5jZSBsZXZlbCBmb3IgYSBmaW5kaW5nXG4gICAqL1xuICBwcml2YXRlIGNhbGN1bGF0ZUNvbmZpZGVuY2UoXG4gICAgbWF0Y2g6IGFueSwgXG4gICAgcnVsZTogU2VjdXJpdHlSdWxlLCBcbiAgICBjb250ZXh0OiBTY2FuQ29udGV4dFxuICApOiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHtcbiAgICAvLyBIaWdoIGNvbmZpZGVuY2UgZm9yIGV4YWN0IHBhdHRlcm4gbWF0Y2hlc1xuICAgIGlmIChydWxlLnRhZ3M/LmluY2x1ZGVzKCdoaWdoLWNvbmZpZGVuY2UnKSkge1xuICAgICAgcmV0dXJuICdoaWdoJztcbiAgICB9XG5cbiAgICAvLyBMb3cgY29uZmlkZW5jZSBpbiB0ZXN0IGZpbGVzXG4gICAgaWYgKGNvbnRleHQuaXNUZXN0KSB7XG4gICAgICByZXR1cm4gJ2xvdyc7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIGNvbW1vbiBmYWxzZSBwb3NpdGl2ZSBpbmRpY2F0b3JzXG4gICAgY29uc3QgY29kZSA9IG1hdGNoLmNvZGUudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoY29kZS5pbmNsdWRlcygnZXhhbXBsZScpIHx8IGNvZGUuaW5jbHVkZXMoJ3Rlc3QnKSB8fCBjb2RlLmluY2x1ZGVzKCdkZW1vJykpIHtcbiAgICAgIHJldHVybiAnbG93JztcbiAgICB9XG5cbiAgICByZXR1cm4gJ21lZGl1bSc7XG4gIH1cblxuICBpc0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmVuYWJsZWQ7XG4gIH1cbn0iXX0=