@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.
178 lines • 20.7 kB
JavaScript
/**
* Code Scanner - Static code analysis for security vulnerabilities
* Detects common security issues in source code
*/
import { SecurityRules } from '../rules/SecurityRules.js';
import * as fs from 'fs/promises';
import * as 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 {
// 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29kZVNjYW5uZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VjdXJpdHkvYXVkaXQvc2Nhbm5lcnMvQ29kZVNjYW5uZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBR0gsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFRNUIsTUFBTSxPQUFPLFdBQVc7SUFDdEIsSUFBSSxHQUFHLGFBQWEsQ0FBQztJQUNiLE1BQU0sQ0FBb0I7SUFDMUIsS0FBSyxHQUFtQixFQUFFLENBQUM7SUFFbkMsWUFBWSxNQUF5QjtRQUNuQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssU0FBUztRQUNmLE1BQU0sVUFBVSxHQUFHLElBQUksYUFBYSxFQUFFLENBQUM7UUFFdkMsS0FBSyxNQUFNLE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3hDLFFBQVEsT0FBTyxFQUFFLENBQUM7Z0JBQ2hCLEtBQUssY0FBYztvQkFDakIsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxVQUFVLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztvQkFDL0MsTUFBTTtnQkFDUixLQUFLLFlBQVk7b0JBQ2YsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztvQkFDN0MsTUFBTTtnQkFDUixLQUFLLHVCQUF1QjtvQkFDMUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMs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RUFBRSxRQUFRLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO1lBQzNDLE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkIsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsNkNBQTZDO1FBQzdDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDdEMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQy9FLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxTQUFTO1FBQ1AsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQztJQUM3QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvZGUgU2Nhbm5lciAtIFN0YXRpYyBjb2RlIGFuYWx5c2lzIGZvciBzZWN1cml0eSB2dWxuZXJhYmlsaXRpZXNcbiAqIERldGVjdHMgY29tbW9uIHNlY3VyaXR5IGlzc3VlcyBpbiBzb3VyY2UgY29kZVxuICovXG5cbmltcG9ydCB0eXBlIHsgU2VjdXJpdHlTY2FubmVyLCBTZWN1cml0eUZpbmRpbmcsIFNjYW5Db250ZXh0LCBTZWN1cml0eVJ1bGUgfSBmcm9tICcuLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eVJ1bGVzIH0gZnJvbSAnLi4vcnVsZXMvU2VjdXJpdHlSdWxlcy5qcyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZ2xvYiB9IGZyb20gJ2dsb2InO1xuXG5pbnRlcmZhY2UgQ29kZVNjYW5uZXJDb25maWcge1xuICBlbmFibGVkOiBib29sZWFuO1xuICBydWxlczogc3RyaW5nW107XG4gIGV4Y2x1ZGU/OiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGNsYXNzIENvZGVTY2FubmVyIGltcGxlbWVudHMgU2VjdXJpdHlTY2FubmVyIHtcbiAgbmFtZSA9ICdDb2RlU2Nhbm5lcic7XG4gIHByaXZhdGUgY29uZmlnOiBDb2RlU2Nhbm5lckNvbmZpZztcbiAgcHJpdmF0ZSBydWxlczogU2VjdXJpdHlSdWxlW10gPSBbXTtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IENvZGVTY2FubmVyQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgdGhpcy5sb2FkUnVsZXMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkIHNlY3VyaXR5IHJ1bGVzIGJhc2VkIG9uIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHByaXZhdGUgbG9hZFJ1bGVzKCk6IHZvaWQge1xuICAgIGNvbnN0IHJ1bGVMb2FkZXIgPSBuZXcgU2VjdXJpdHlSdWxlcygpO1xuICAgIFxuICAgIGZvciAoY29uc3QgcnVsZVNldCBvZiB0aGlzLmNvbmZpZy5ydWxlcykge1xuICAgICAgc3dpdGNoIChydWxlU2V0KSB7XG4gICAgICAgIGNhc2UgJ09XQVNQLVRvcC0xMCc6XG4gICAgICAgICAgdGhpcy5ydWxlcy5wdXNoKC4uLnJ1bGVMb2FkZXIuZ2V0T1dBU1BSdWxlcygpKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnQ1dFLVRvcC0yNSc6XG4gICAgICAgICAgdGhpcy5ydWxlcy5wdXNoKC4uLnJ1bGVMb2FkZXIuZ2V0Q1dFUnVsZXMoKSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ0RvbGxob3VzZU1DUC1TZWN1cml0eSc6XG4gICAgICAgICAgdGhpcy5ydWxlcy5wdXNoKC4uLnJ1bGVMb2FkZXIuZ2V0RG9sbGhvdXNlTUNQUnVsZXMoKSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgLy8gQ3VzdG9tIHJ1bGUgc2V0cyBjYW4gYmUgYWRkZWQgaGVyZVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTY2FuIGZpbGVzIGZvciBzZWN1cml0eSB2dWxuZXJhYmlsaXRpZXNcbiAgICovXG4gIGFzeW5jIHNjYW4oY29udGV4dDogU2NhbkNvbnRleHQpOiBQcm9taXNlPFNlY3VyaXR5RmluZGluZ1tdPiB7XG4gICAgY29uc3QgZmluZGluZ3M6IFNlY3VyaXR5RmluZGluZ1tdID0gW107XG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCB0aGlzLmdldEZpbGVzVG9TY2FuKGNvbnRleHQucHJvamVjdFJvb3QpO1xuXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZSwgJ3V0Zi04Jyk7XG4gICAgICAgIGNvbnN0IGZpbGVGaW5kaW5ncyA9IGF3YWl0IHRoaXMuc2NhbkZpbGUoZmlsZSwgY29udGVudCwgY29udGV4dCk7XG4gICAgICAgIGZpbmRpbmdzLnB1c2goLi4uZmlsZUZpbmRpbmdzKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBTa2lwIGZpbGVzIHRoYXQgY2FuJ3QgYmUgcmVhZFxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmluZGluZ3M7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGxpc3Qgb2YgZmlsZXMgdG8gc2NhblxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRGaWxlc1RvU2Nhbihwcm9qZWN0Um9vdDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IHBhdHRlcm5zID0gWycqKi8qLnRzJywgJyoqLyouanMnLCAnKiovKi5qc3gnLCAnKiovKi50c3gnLCAnKiovKi5qc29uJywgJyoqLyoueW1sJywgJyoqLyoueWFtbCddO1xuICAgIGNvbnN0IGlnbm9yZSA9IHRoaXMuY29uZmlnLmV4Y2x1ZGUgfHwgW1xuICAgICAgJyoqL25vZGVfbW9kdWxlcy8qKicsXG4gICAgICAnKiovZGlzdC8qKicsXG4gICAgICAnKiovY292ZXJhZ2UvKionXG4gICAgXTtcblxuICAgIGNvbnN0IGZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcGF0dGVybiBvZiBwYXR0ZXJucykge1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IGF3YWl0IGdsb2IocGF0dGVybiwge1xuICAgICAgICBjd2Q6IHByb2plY3RSb290LFxuICAgICAgICBpZ25vcmUsXG4gICAgICAgIGFic29sdXRlOiB0cnVlXG4gICAgICB9KTtcbiAgICAgIGZpbGVzLnB1c2goLi4ubWF0Y2hlcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNjYW4gYSBzaW5nbGUgZmlsZSBmb3IgdnVsbmVyYWJpbGl0aWVzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNjYW5GaWxlKFxuICAgIGZpbGVQYXRoOiBzdHJpbmcsIFxuICAgIGNvbnRlbnQ6IHN0cmluZywgXG4gICAgY29udGV4dDogU2NhbkNvbnRleHRcbiAgKTogUHJvbWlzZTxTZWN1cml0eUZpbmRpbmdbXT4ge1xuICAgIGNvbnN0IGZpbmRpbmdzOiBTZWN1cml0eUZpbmRpbmdbXSA9IFtdO1xuICAgIGNvbnN0IGxpbmVzID0gY29udGVudC5zcGxpdCgnXFxuJyk7XG4gICAgY29uc3QgZmlsZUNvbnRleHQgPSB7XG4gICAgICAuLi5jb250ZXh0LFxuICAgICAgZmlsZVR5cGU6IHBhdGguZXh0bmFtZShmaWxlUGF0aCksXG4gICAgICBpc1Rlc3Q6IGZpbGVQYXRoLmluY2x1ZGVzKCd0ZXN0JykgfHwgZmlsZVBhdGguaW5jbHVkZXMoJ3NwZWMnKVxuICAgIH07XG5cbiAgICBmb3IgKGNvbnN0IHJ1bGUgb2YgdGhpcy5ydWxlcykge1xuICAgICAgLy8gU2tpcCB0ZXN0LXNwZWNpZmljIHJ1bGVzIGluIG5vbi10ZXN0IGZpbGVzXG4gICAgICBpZiAocnVsZS50YWdzPy5pbmNsdWRlcygndGVzdC1vbmx5JykgJiYgIWZpbGVDb250ZXh0LmlzVGVzdCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gUGF0dGVybi1iYXNlZCBkZXRlY3Rpb25cbiAgICAgIGlmIChydWxlLnBhdHRlcm4pIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlcyA9IHRoaXMuZmluZFBhdHRlcm5NYXRjaGVzKGNvbnRlbnQsIGxpbmVzLCBydWxlKTtcbiAgICAgICAgZm9yIChjb25zdCBtYXRjaCBvZiBtYXRjaGVzKSB7XG4gICAgICAgICAgZmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgICBydWxlSWQ6IHJ1bGUuaWQsXG4gICAgICAgICAgICBzZXZlcml0eTogcnVsZS5zZXZlcml0eSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGAke3J1bGUubmFtZX06ICR7bWF0Y2gubWVzc2FnZX1gLFxuICAgICAgICAgICAgZmlsZTogZmlsZVBhdGgsXG4gICAgICAgICAgICBsaW5lOiBtYXRjaC5saW5lLFxuICAgICAgICAgICAgY29sdW1uOiBtYXRjaC5jb2x1bW4sXG4gICAgICAgICAgICBjb2RlOiBtYXRjaC5jb2RlLFxuICAgICAgICAgICAgcmVtZWRpYXRpb246IHJ1bGUucmVtZWRpYXRpb24sXG4gICAgICAgICAgICBjb25maWRlbmNlOiB0aGlzLmNhbGN1bGF0ZUNvbmZpZGVuY2UobWF0Y2gsIHJ1bGUsIGZpbGVDb250ZXh0KVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEN1c3RvbSBjaGVjayBmdW5jdGlvblxuICAgICAgaWYgKHJ1bGUuY2hlY2spIHtcbiAgICAgICAgY29uc3QgY3VzdG9tRmluZGluZ3MgPSBydWxlLmNoZWNrKGNvbnRlbnQsIGZpbGVDb250ZXh0KTtcbiAgICAgICAgZmluZGluZ3MucHVzaCguLi5jdXN0b21GaW5kaW5ncy5tYXAoZiA9PiAoe1xuICAgICAgICAgIC4uLmYsXG4gICAgICAgICAgZmlsZTogZmlsZVBhdGhcbiAgICAgICAgfSkpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmluZGluZ3M7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBwYXR0ZXJuIG1hdGNoZXMgaW4gY29udGVudFxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kUGF0dGVybk1hdGNoZXMoXG4gICAgY29udGVudDogc3RyaW5nLCBcbiAgICBsaW5lczogc3RyaW5nW10sIFxuICAgIHJ1bGU6IFNlY3VyaXR5UnVsZVxuICApOiBBcnJheTx7bGluZTogbnVtYmVyOyBjb2x1bW46IG51bWJlcjsgY29kZTogc3RyaW5nOyBtZXNzYWdlOiBzdHJpbmd9PiB7XG4gICAgY29uc3QgbWF0Y2hlczogQXJyYXk8e2xpbmU6IG51bWJlcjsgY29sdW1uOiBudW1iZXI7IGNvZGU6IHN0cmluZzsgbWVzc2FnZTogc3RyaW5nfT4gPSBbXTtcbiAgICBcbiAgICBpZiAoIXJ1bGUucGF0dGVybikgcmV0dXJuIG1hdGNoZXM7XG5cbiAgICAvLyBSZXNldCByZWdleCBzdGF0ZVxuICAgIHJ1bGUucGF0dGVybi5sYXN0SW5kZXggPSAwO1xuICAgIFxuICAgIGxldCBtYXRjaDtcbiAgICB3aGlsZSAoKG1hdGNoID0gcnVsZS5wYXR0ZXJuLmV4ZWMoY29udGVudCkpICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBwb3NpdGlvbiA9IHRoaXMuZ2V0TGluZUFuZENvbHVtbihjb250ZW50LCBtYXRjaC5pbmRleCk7XG4gICAgICBjb25zdCBjb2RlID0gbGluZXNbcG9zaXRpb24ubGluZSAtIDFdPy50cmltKCkgfHwgJyc7XG4gICAgICBcbiAgICAgIG1hdGNoZXMucHVzaCh7XG4gICAgICAgIGxpbmU6IHBvc2l0aW9uLmxpbmUsXG4gICAgICAgIGNvbHVtbjogcG9zaXRpb24uY29sdW1uLFxuICAgICAgICBjb2RlOiBjb2RlLnN1YnN0cmluZygwLCAxMDApLCAvLyBMaW1pdCBjb2RlIHNuaXBwZXQgbGVuZ3RoXG4gICAgICAgIG1lc3NhZ2U6IHJ1bGUuZGVzY3JpcHRpb25cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBtYXRjaGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgc3RyaW5nIGluZGV4IHRvIGxpbmUgYW5kIGNvbHVtblxuICAgKi9cbiAgcHJpdmF0ZSBnZXRMaW5lQW5kQ29sdW1uKGNvbnRlbnQ6IHN0cmluZywgaW5kZXg6IG51bWJlcik6IHtsaW5lOiBudW1iZXI7IGNvbHVtbjogbnVtYmVyfSB7XG4gICAgY29uc3QgbGluZXMgPSBjb250ZW50LnN1YnN0cmluZygwLCBpbmRleCkuc3BsaXQoJ1xcbicpO1xuICAgIHJldHVybiB7XG4gICAgICBsaW5lOiBsaW5lcy5sZW5ndGgsXG4gICAgICBjb2x1bW46IGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdLmxlbmd0aCArIDFcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBjb25maWRlbmNlIGxldmVsIGZvciBhIGZpbmRpbmdcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlQ29uZmlkZW5jZShcbiAgICBtYXRjaDogYW55LCBcbiAgICBydWxlOiBTZWN1cml0eVJ1bGUsIFxuICAgIGNvbnRleHQ6IFNjYW5Db250ZXh0XG4gICk6ICdsb3cnIHwgJ21lZGl1bScgfCAnaGlnaCcge1xuICAgIC8vIEhpZ2ggY29uZmlkZW5jZSBmb3IgZXhhY3QgcGF0dGVybiBtYXRjaGVzXG4gICAgaWYgKHJ1bGUudGFncz8uaW5jbHVkZXMoJ2hpZ2gtY29uZmlkZW5jZScpKSB7XG4gICAgICByZXR1cm4gJ2hpZ2gnO1xuICAgIH1cblxuICAgIC8vIExvdyBjb25maWRlbmNlIGluIHRlc3QgZmlsZXNcbiAgICBpZiAoY29udGV4dC5pc1Rlc3QpIHtcbiAgICAgIHJldHVybiAnbG93JztcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgY29tbW9uIGZhbHNlIHBvc2l0aXZlIGluZGljYXRvcnNcbiAgICBjb25zdCBjb2RlID0gbWF0Y2guY29kZS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmIChjb2RlLmluY2x1ZGVzKCdleGFtcGxlJykgfHwgY29kZS5pbmNsdWRlcygndGVzdCcpIHx8IGNvZGUuaW5jbHVkZXMoJ2RlbW8nKSkge1xuICAgICAgcmV0dXJuICdsb3cnO1xuICAgIH1cblxuICAgIHJldHVybiAnbWVkaXVtJztcbiAgfVxuXG4gIGlzRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuZW5hYmxlZDtcbiAgfVxufSJdfQ==