@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.
186 lines • 24.4 kB
JavaScript
/**
* VerificationNotifier - Non-blocking OS dialog for verification codes (Issue #522)
*
* Spawns native OS dialogs to display verification codes directly to the human.
* The code is NEVER returned to the LLM via MCP tool responses.
*
* Why a separate service instead of reusing DisplayService?
* - DisplayService uses execSync (blocking). We need non-blocking spawn so
* the MCP response returns immediately.
* - DI-injectable for testability (integration tests run headless, can mock/spy).
* - Clean separation: DisplayService owns cross-platform dialog mechanics,
* VerificationNotifier owns the "fire-and-forget, never block the server" concern.
*
* @since v1.1.0
*/
import { spawn, execSync } from 'child_process';
import { platform } from 'os';
import { SecurityMonitor } from '../security/securityMonitor.js';
export class VerificationNotifier {
/**
* Display the verification code via a native OS dialog.
*
* - Uses child_process.spawn with detached + unref for true fire-and-forget
* - Never throws (catches all errors internally)
* - Never logs the code itself
*/
showCode(code, reason) {
let currentPlatform = 'unknown';
try {
currentPlatform = platform();
const title = 'DollhouseMCP Verification Required';
// The message shown to the human in the dialog
const message = `${reason}\n\nVerification Code: ${code}\n\nType this code in your chat to proceed.`;
if (currentPlatform === 'darwin') {
this.spawnMacOS(title, message);
}
else if (currentPlatform === 'linux') {
this.spawnLinux(title, message);
}
else if (currentPlatform === 'win32') {
this.spawnWindows(title, message);
}
else {
// SECURITY: Never log the code on unsupported platforms
SecurityMonitor.logSecurityEvent({
type: 'DANGER_ZONE_TRIGGERED',
severity: 'MEDIUM',
source: 'VerificationNotifier.showCode',
details: `Unsupported platform for verification dialog: ${currentPlatform}`,
additionalData: { platform: currentPlatform },
});
}
}
catch {
// SECURITY: Never log the code in error paths
SecurityMonitor.logSecurityEvent({
type: 'DANGER_ZONE_TRIGGERED',
severity: 'MEDIUM',
source: 'VerificationNotifier.showCode',
details: 'Failed to spawn verification dialog',
additionalData: { platform: currentPlatform },
});
}
}
isAvailable() {
try {
const currentPlatform = platform();
if (currentPlatform === 'darwin') {
return true; // macOS always has osascript
}
else if (currentPlatform === 'linux') {
return this.hasLinuxDialogTool();
}
else if (currentPlatform === 'win32') {
return true; // Windows always has PowerShell
}
return false;
}
catch {
return false;
}
}
// ---- Platform-specific spawners ----
spawnMacOS(title, message) {
// Escape for AppleScript: backslashes, then double quotes. Newlines are
// replaced with AppleScript `return` character concatenation so they render
// as real line breaks in the dialog instead of literal "\n" text.
const escapedTitle = title.replaceAll('\\', String.raw `\\`).replaceAll('"', String.raw `\"`).replaceAll(/[\n\r]/g, ' ');
const escapedMessage = message.replaceAll('\\', String.raw `\\`).replaceAll('"', String.raw `\"`);
// Split on newlines and join with AppleScript return concatenation
const messageParts = escapedMessage.split(/\r?\n/).map(part => `"${part}"`).join(' & return & ');
const script = `display dialog (${messageParts}) with title "${escapedTitle}" with icon caution buttons {"OK"} default button "OK"`;
// NOSONAR - Intentional: OS dialog via AppleScript, input escaped with escapeShellArg
const child = spawn('osascript', ['-e', script], {
detached: true,
stdio: 'ignore',
});
child.unref();
}
spawnLinux(title, message) {
const realMessage = message;
try {
execSync('which zenity', { stdio: 'pipe' }); // NOSONAR - Tool detection, no user input
const child = spawn('zenity', [
'--info',
`--title=${title}`,
`--text=${realMessage}`,
'--no-wrap',
], {
detached: true,
stdio: 'ignore',
});
child.unref();
return;
}
catch { /* zenity not found */ }
try {
execSync('which kdialog', { stdio: 'pipe' }); // NOSONAR - Tool detection, no user input
const child = spawn('kdialog', [
'--msgbox', realMessage,
'--title', title,
], {
detached: true,
stdio: 'ignore',
});
child.unref();
return;
}
catch { /* kdialog not found */ }
try {
execSync('which xmessage', { stdio: 'pipe' }); // NOSONAR - Tool detection, no user input
const child = spawn('xmessage', [
'-center', `${title}\n\n${realMessage}`,
], {
detached: true,
stdio: 'ignore',
});
child.unref();
return;
}
catch { /* xmessage not found */ }
// No dialog tool available
SecurityMonitor.logSecurityEvent({
type: 'DANGER_ZONE_TRIGGERED',
severity: 'MEDIUM',
source: 'VerificationNotifier.spawnLinux',
details: 'No GUI dialog tool available on Linux (tried zenity, kdialog, xmessage)',
additionalData: { platform: 'linux', dialogToolsTried: ['zenity', 'kdialog', 'xmessage'] },
});
}
spawnWindows(title, message) {
// Convert real newlines to PowerShell backtick-n for MessageBox rendering
const realMessage = message.replaceAll('\n', '`n');
const escapedMessage = realMessage.replaceAll("'", "''");
const escapedTitle = title.replaceAll("'", "''");
const script = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${escapedMessage}', '${escapedTitle}', 'OK', 'Warning')`;
// SECURITY: Use -EncodedCommand for safe execution (Base64 encoding prevents injection)
// NOSONAR - Intentional: OS dialog via PowerShell, input Base64-encoded
const encodedScript = Buffer.from(script, 'utf16le').toString('base64');
const child = spawn('powershell', ['-EncodedCommand', encodedScript], {
detached: true,
stdio: 'ignore',
});
child.unref();
}
hasLinuxDialogTool() {
// NOSONAR - All execSync calls below are tool detection with no user input
try {
execSync('which zenity', { stdio: 'pipe' });
return true;
}
catch { /* not found */ }
try {
execSync('which kdialog', { stdio: 'pipe' });
return true;
}
catch { /* not found */ }
try {
execSync('which xmessage', { stdio: 'pipe' });
return true;
}
catch { /* not found */ }
return false;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmVyaWZpY2F0aW9uTm90aWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvVmVyaWZpY2F0aW9uTm90aWZpZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzlCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQWFqRSxNQUFNLE9BQU8sb0JBQW9CO0lBQy9COzs7Ozs7T0FNRztJQUNILFFBQVEsQ0FBQyxJQUFZLEVBQUUsTUFBYztRQUNuQyxJQUFJLGVBQWUsR0FBRyxTQUFTLENBQUM7UUFDaEMsSUFBSSxDQUFDO1lBQ0gsZUFBZSxHQUFHLFFBQVEsRUFBRSxDQUFDO1lBQzdCLE1BQU0sS0FBSyxHQUFHLG9DQUFvQyxDQUFDO1lBQ25ELCtDQUErQztZQUMvQyxNQUFNLE9BQU8sR0FBRyxHQUFHLE1BQU0sMEJBQTBCLElBQUksNkNBQTZDLENBQUM7WUFFckcsSUFBSSxlQUFlLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2xDLENBQUM7aUJBQU0sSUFBSSxlQUFlLEtBQUssT0FBTyxFQUFFLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2xDLENBQUM7aUJBQU0sSUFBSSxlQUFlLEtBQUssT0FBTyxFQUFFLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ3BDLENBQUM7aUJBQU0sQ0FBQztnQkFDTix3REFBd0Q7Z0JBQ3hELGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFD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TyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsTUFBTSxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDO1lBQ0gsUUFBUSxDQUFDLGVBQWUsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzdDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQztZQUNILFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzlDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzNCLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBWZXJpZmljYXRpb25Ob3RpZmllciAtIE5vbi1ibG9ja2luZyBPUyBkaWFsb2cgZm9yIHZlcmlmaWNhdGlvbiBjb2RlcyAoSXNzdWUgIzUyMilcbiAqXG4gKiBTcGF3bnMgbmF0aXZlIE9TIGRpYWxvZ3MgdG8gZGlzcGxheSB2ZXJpZmljYXRpb24gY29kZXMgZGlyZWN0bHkgdG8gdGhlIGh1bWFuLlxuICogVGhlIGNvZGUgaXMgTkVWRVIgcmV0dXJuZWQgdG8gdGhlIExMTSB2aWEgTUNQIHRvb2wgcmVzcG9uc2VzLlxuICpcbiAqIFdoeSBhIHNlcGFyYXRlIHNlcnZpY2UgaW5zdGVhZCBvZiByZXVzaW5nIERpc3BsYXlTZXJ2aWNlP1xuICogLSBEaXNwbGF5U2VydmljZSB1c2VzIGV4ZWNTeW5jIChibG9ja2luZykuIFdlIG5lZWQgbm9uLWJsb2NraW5nIHNwYXduIHNvXG4gKiAgIHRoZSBNQ1AgcmVzcG9uc2UgcmV0dXJucyBpbW1lZGlhdGVseS5cbiAqIC0gREktaW5qZWN0YWJsZSBmb3IgdGVzdGFiaWxpdHkgKGludGVncmF0aW9uIHRlc3RzIHJ1biBoZWFkbGVzcywgY2FuIG1vY2svc3B5KS5cbiAqIC0gQ2xlYW4gc2VwYXJhdGlvbjogRGlzcGxheVNlcnZpY2Ugb3ducyBjcm9zcy1wbGF0Zm9ybSBkaWFsb2cgbWVjaGFuaWNzLFxuICogICBWZXJpZmljYXRpb25Ob3RpZmllciBvd25zIHRoZSBcImZpcmUtYW5kLWZvcmdldCwgbmV2ZXIgYmxvY2sgdGhlIHNlcnZlclwiIGNvbmNlcm4uXG4gKlxuICogQHNpbmNlIHYxLjEuMFxuICovXG5cbmltcG9ydCB7IHNwYXduLCBleGVjU3luYyB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgcGxhdGZvcm0gfSBmcm9tICdvcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuXG4vKipcbiAqIEludGVyZmFjZSBmb3IgdmVyaWZpY2F0aW9uIGNvZGUgZGlzcGxheS5cbiAqIEltcGxlbWVudGF0aW9ucyBtdXN0IE5FVkVSIHJldHVybiBvciBsb2cgdGhlIGNvZGUgaXRzZWxmLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElWZXJpZmljYXRpb25Ob3RpZmllciB7XG4gIC8qKiBGaXJlLWFuZC1mb3JnZXQ6IHNob3cgdGhlIGNvZGUgaW4gYW4gT1MgZGlhbG9nLiBOZXZlciB0aHJvd3MuICovXG4gIHNob3dDb2RlKGNvZGU6IHN0cmluZywgcmVhc29uOiBzdHJpbmcpOiB2b2lkO1xuICAvKiogV2hldGhlciB0aGUgY3VycmVudCBwbGF0Zm9ybSBzdXBwb3J0cyBPUyBkaWFsb2dzLiAqL1xuICBpc0F2YWlsYWJsZSgpOiBib29sZWFuO1xufVxuXG5leHBvcnQgY2xhc3MgVmVyaWZpY2F0aW9uTm90aWZpZXIgaW1wbGVtZW50cyBJVmVyaWZpY2F0aW9uTm90aWZpZXIge1xuICAvKipcbiAgICogRGlzcGxheSB0aGUgdmVyaWZpY2F0aW9uIGNvZGUgdmlhIGEgbmF0aXZlIE9TIGRpYWxvZy5cbiAgICpcbiAgICogLSBVc2VzIGNoaWxkX3Byb2Nlc3Muc3Bhd24gd2l0aCBkZXRhY2hlZCArIHVucmVmIGZvciB0cnVlIGZpcmUtYW5kLWZvcmdldFxuICAgKiAtIE5ldmVyIHRocm93cyAoY2F0Y2hlcyBhbGwgZXJyb3JzIGludGVybmFsbHkpXG4gICAqIC0gTmV2ZXIgbG9ncyB0aGUgY29kZSBpdHNlbGZcbiAgICovXG4gIHNob3dDb2RlKGNvZGU6IHN0cmluZywgcmVhc29uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsZXQgY3VycmVudFBsYXRmb3JtID0gJ3Vua25vd24nO1xuICAgIHRyeSB7XG4gICAgICBjdXJyZW50UGxhdGZvcm0gPSBwbGF0Zm9ybSgpO1xuICAgICAgY29uc3QgdGl0bGUgPSAnRG9sbGhvdXNlTUNQIFZlcmlmaWNhdGlvbiBSZXF1aXJlZCc7XG4gICAgICAvLyBUaGUgbWVzc2FnZSBzaG93biB0byB0aGUgaHVtYW4gaW4gdGhlIGRpYWxvZ1xuICAgICAgY29uc3QgbWVzc2FnZSA9IGAke3JlYXNvbn1cXG5cXG5WZXJpZmljYXRpb24gQ29kZTogJHtjb2RlfVxcblxcblR5cGUgdGhpcyBjb2RlIGluIHlvdXIgY2hhdCB0byBwcm9jZWVkLmA7XG5cbiAgICAgIGlmIChjdXJyZW50UGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgICAgIHRoaXMuc3Bhd25NYWNPUyh0aXRsZSwgbWVzc2FnZSk7XG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRQbGF0Zm9ybSA9PT0gJ2xpbnV4Jykge1xuICAgICAgICB0aGlzLnNwYXduTGludXgodGl0bGUsIG1lc3NhZ2UpO1xuICAgICAgfSBlbHNlIGlmIChjdXJyZW50UGxhdGZvcm0gPT09ICd3aW4zMicpIHtcbiAgICAgICAgdGhpcy5zcGF3bldpbmRvd3ModGl0bGUsIG1lc3NhZ2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gU0VDVVJJVFk6IE5ldmVyIGxvZyB0aGUgY29kZSBvbiB1bnN1cHBvcnRlZCBwbGF0Zm9ybXNcbiAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgIHR5cGU6ICdEQU5HRVJfWk9ORV9UUklHR0VSRUQnLFxuICAgICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgICBzb3VyY2U6ICdWZXJpZmljYXRpb25Ob3RpZmllci5zaG93Q29kZScsXG4gICAgICAgICAgZGV0YWlsczogYFVuc3VwcG9ydGVkIHBsYXRmb3JtIGZvciB2ZXJpZmljYXRpb24gZGlhbG9nOiAke2N1cnJlbnRQbGF0Zm9ybX1gLFxuICAgICAgICAgIGFkZGl0aW9uYWxEYXRhOiB7IHBsYXRmb3JtOiBjdXJyZW50UGxhdGZvcm0gfSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBTRUNVUklUWTogTmV2ZXIgbG9nIHRoZSBjb2RlIGluIGVycm9yIHBhdGhzXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdEQU5HRVJfWk9ORV9UUklHR0VSRUQnLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ1ZlcmlmaWNhdGlvbk5vdGlmaWVyLnNob3dDb2RlJyxcbiAgICAgICAgZGV0YWlsczogJ0ZhaWxlZCB0byBzcGF3biB2ZXJpZmljYXRpb24gZGlhbG9nJyxcbiAgICAgICAgYWRkaXRpb25hbERhdGE6IHsgcGxhdGZvcm06IGN1cnJlbnRQbGF0Zm9ybSB9LFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaXNBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGN1cnJlbnRQbGF0Zm9ybSA9IHBsYXRmb3JtKCk7XG5cbiAgICAgIGlmIChjdXJyZW50UGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgICAgIHJldHVybiB0cnVlOyAvLyBtYWNPUyBhbHdheXMgaGFzIG9zYXNjcmlwdFxuICAgICAgfSBlbHNlIGlmIChjdXJyZW50UGxhdGZvcm0gPT09ICdsaW51eCcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaGFzTGludXhEaWFsb2dUb29sKCk7XG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRQbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gV2luZG93cyBhbHdheXMgaGFzIFBvd2VyU2hlbGxcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8vIC0tLS0gUGxhdGZvcm0tc3BlY2lmaWMgc3Bhd25lcnMgLS0tLVxuXG4gIHByaXZhdGUgc3Bhd25NYWNPUyh0aXRsZTogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyBFc2NhcGUgZm9yIEFwcGxlU2NyaXB0OiBiYWNrc2xhc2hlcywgdGhlbiBkb3VibGUgcXVvdGVzLiBOZXdsaW5lcyBhcmVcbiAgICAvLyByZXBsYWNlZCB3aXRoIEFwcGxlU2NyaXB0IGByZXR1cm5gIGNoYXJhY3RlciBjb25jYXRlbmF0aW9uIHNvIHRoZXkgcmVuZGVyXG4gICAgLy8gYXMgcmVhbCBsaW5lIGJyZWFrcyBpbiB0aGUgZGlhbG9nIGluc3RlYWQgb2YgbGl0ZXJhbCBcIlxcblwiIHRleHQuXG4gICAgY29uc3QgZXNjYXBlZFRpdGxlID0gdGl0bGUucmVwbGFjZUFsbCgnXFxcXCcsIFN0cmluZy5yYXdgXFxcXGApLnJlcGxhY2VBbGwoJ1wiJywgU3RyaW5nLnJhd2BcXFwiYCkucmVwbGFjZUFsbCgvW1xcblxccl0vZywgJyAnKTtcbiAgICBjb25zdCBlc2NhcGVkTWVzc2FnZSA9IG1lc3NhZ2UucmVwbGFjZUFsbCgnXFxcXCcsIFN0cmluZy5yYXdgXFxcXGApLnJlcGxhY2VBbGwoJ1wiJywgU3RyaW5nLnJhd2BcXFwiYCk7XG4gICAgLy8gU3BsaXQgb24gbmV3bGluZXMgYW5kIGpvaW4gd2l0aCBBcHBsZVNjcmlwdCByZXR1cm4gY29uY2F0ZW5hdGlvblxuICAgIGNvbnN0IG1lc3NhZ2VQYXJ0cyA9IGVzY2FwZWRNZXNzYWdlLnNwbGl0KC9cXHI/XFxuLykubWFwKHBhcnQgPT4gYFwiJHtwYXJ0fVwiYCkuam9pbignICYgcmV0dXJuICYgJyk7XG5cbiAgICBjb25zdCBzY3JpcHQgPSBgZGlzcGxheSBkaWFsb2cgKCR7bWVzc2FnZVBhcnRzfSkgd2l0aCB0aXRsZSBcIiR7ZXNjYXBlZFRpdGxlfVwiIHdpdGggaWNvbiBjYXV0aW9uIGJ1dHRvbnMge1wiT0tcIn0gZGVmYXVsdCBidXR0b24gXCJPS1wiYDtcblxuICAgIC8vIE5PU09OQVIgLSBJbnRlbnRpb25hbDogT1MgZGlhbG9nIHZpYSBBcHBsZVNjcmlwdCwgaW5wdXQgZXNjYXBlZCB3aXRoIGVzY2FwZVNoZWxsQXJnXG4gICAgY29uc3QgY2hpbGQgPSBzcGF3bignb3Nhc2NyaXB0JywgWyctZScsIHNjcmlwdF0sIHtcbiAgICAgIGRldGFjaGVkOiB0cnVlLFxuICAgICAgc3RkaW86ICdpZ25vcmUnLFxuICAgIH0pO1xuICAgIGNoaWxkLnVucmVmKCk7XG4gIH1cblxuICBwcml2YXRlIHNwYXduTGludXgodGl0bGU6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcmVhbE1lc3NhZ2UgPSBtZXNzYWdlO1xuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKCd3aGljaCB6ZW5pdHknLCB7IHN0ZGlvOiAncGlwZScgfSk7IC8vIE5PU09OQVIgLSBUb29sIGRldGVjdGlvbiwgbm8gdXNlciBpbnB1dFxuICAgICAgY29uc3QgY2hpbGQgPSBzcGF3bignemVuaXR5JywgW1xuICAgICAgICAnLS1pbmZvJyxcbiAgICAgICAgYC0tdGl0bGU9JHt0aXRsZX1gLFxuICAgICAgICBgLS10ZXh0PSR7cmVhbE1lc3NhZ2V9YCxcbiAgICAgICAgJy0tbm8td3JhcCcsXG4gICAgICBdLCB7XG4gICAgICAgIGRldGFjaGVkOiB0cnVlLFxuICAgICAgICBzdGRpbzogJ2lnbm9yZScsXG4gICAgICB9KTtcbiAgICAgIGNoaWxkLnVucmVmKCk7XG4gICAgICByZXR1cm47XG4gICAgfSBjYXRjaCB7IC8qIHplbml0eSBub3QgZm91bmQgKi8gfVxuXG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKCd3aGljaCBrZGlhbG9nJywgeyBzdGRpbzogJ3BpcGUnIH0pOyAvLyBOT1NPTkFSIC0gVG9vbCBkZXRlY3Rpb24sIG5vIHVzZXIgaW5wdXRcbiAgICAgIGNvbnN0IGNoaWxkID0gc3Bhd24oJ2tkaWFsb2cnLCBbXG4gICAgICAgICctLW1zZ2JveCcsIHJlYWxNZXNzYWdlLFxuICAgICAgICAnLS10aXRsZScsIHRpdGxlLFxuICAgICAgXSwge1xuICAgICAgICBkZXRhY2hlZDogdHJ1ZSxcbiAgICAgICAgc3RkaW86ICdpZ25vcmUnLFxuICAgICAgfSk7XG4gICAgICBjaGlsZC51bnJlZigpO1xuICAgICAgcmV0dXJuO1xuICAgIH0gY2F0Y2ggeyAvKiBrZGlhbG9nIG5vdCBmb3VuZCAqLyB9XG5cbiAgICB0cnkge1xuICAgICAgZXhlY1N5bmMoJ3doaWNoIHhtZXNzYWdlJywgeyBzdGRpbzogJ3BpcGUnIH0pOyAvLyBOT1NPTkFSIC0gVG9vbCBkZXRlY3Rpb24sIG5vIHVzZXIgaW5wdXRcbiAgICAgIGNvbnN0IGNoaWxkID0gc3Bhd24oJ3htZXNzYWdlJywgW1xuICAgICAgICAnLWNlbnRlcicsIGAke3RpdGxlfVxcblxcbiR7cmVhbE1lc3NhZ2V9YCxcbiAgICAgIF0sIHtcbiAgICAgICAgZGV0YWNoZWQ6IHRydWUsXG4gICAgICAgIHN0ZGlvOiAnaWdub3JlJyxcbiAgICAgIH0pO1xuICAgICAgY2hpbGQudW5yZWYoKTtcbiAgICAgIHJldHVybjtcbiAgICB9IGNhdGNoIHsgLyogeG1lc3NhZ2Ugbm90IGZvdW5kICovIH1cblxuICAgIC8vIE5vIGRpYWxvZyB0b29sIGF2YWlsYWJsZVxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdEQU5HRVJfWk9ORV9UUklHR0VSRUQnLFxuICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgc291cmNlOiAnVmVyaWZpY2F0aW9uTm90aWZpZXIuc3Bhd25MaW51eCcsXG4gICAgICBkZXRhaWxzOiAnTm8gR1VJIGRpYWxvZyB0b29sIGF2YWlsYWJsZSBvbiBMaW51eCAodHJpZWQgemVuaXR5LCBrZGlhbG9nLCB4bWVzc2FnZSknLFxuICAgICAgYWRkaXRpb25hbERhdGE6IHsgcGxhdGZvcm06ICdsaW51eCcsIGRpYWxvZ1Rvb2xzVHJpZWQ6IFsnemVuaXR5JywgJ2tkaWFsb2cnLCAneG1lc3NhZ2UnXSB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzcGF3bldpbmRvd3ModGl0bGU6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gQ29udmVydCByZWFsIG5ld2xpbmVzIHRvIFBvd2VyU2hlbGwgYmFja3RpY2stbiBmb3IgTWVzc2FnZUJveCByZW5kZXJpbmdcbiAgICBjb25zdCByZWFsTWVzc2FnZSA9IG1lc3NhZ2UucmVwbGFjZUFsbCgnXFxuJywgJ2BuJyk7XG4gICAgY29uc3QgZXNjYXBlZE1lc3NhZ2UgPSByZWFsTWVzc2FnZS5yZXBsYWNlQWxsKFwiJ1wiLCBcIicnXCIpO1xuICAgIGNvbnN0IGVzY2FwZWRUaXRsZSA9IHRpdGxlLnJlcGxhY2VBbGwoXCInXCIsIFwiJydcIik7XG5cbiAgICBjb25zdCBzY3JpcHQgPSBgQWRkLVR5cGUgLUFzc2VtYmx5TmFtZSBTeXN0ZW0uV2luZG93cy5Gb3JtczsgW1N5c3RlbS5XaW5kb3dzLkZvcm1zLk1lc3NhZ2VCb3hdOjpTaG93KCcke2VzY2FwZWRNZXNzYWdlfScsICcke2VzY2FwZWRUaXRsZX0nLCAnT0snLCAnV2FybmluZycpYDtcblxuICAgIC8vIFNFQ1VSSVRZOiBVc2UgLUVuY29kZWRDb21tYW5kIGZvciBzYWZlIGV4ZWN1dGlvbiAoQmFzZTY0IGVuY29kaW5nIHByZXZlbnRzIGluamVjdGlvbilcbiAgICAvLyBOT1NPTkFSIC0gSW50ZW50aW9uYWw6IE9TIGRpYWxvZyB2aWEgUG93ZXJTaGVsbCwgaW5wdXQgQmFzZTY0LWVuY29kZWRcbiAgICBjb25zdCBlbmNvZGVkU2NyaXB0ID0gQnVmZmVyLmZyb20oc2NyaXB0LCAndXRmMTZsZScpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICBjb25zdCBjaGlsZCA9IHNwYXduKCdwb3dlcnNoZWxsJywgWyctRW5jb2RlZENvbW1hbmQnLCBlbmNvZGVkU2NyaXB0XSwge1xuICAgICAgZGV0YWNoZWQ6IHRydWUsXG4gICAgICBzdGRpbzogJ2lnbm9yZScsXG4gICAgfSk7XG4gICAgY2hpbGQudW5yZWYoKTtcbiAgfVxuXG4gIHByaXZhdGUgaGFzTGludXhEaWFsb2dUb29sKCk6IGJvb2xlYW4ge1xuICAgIC8vIE5PU09OQVIgLSBBbGwgZXhlY1N5bmMgY2FsbHMgYmVsb3cgYXJlIHRvb2wgZGV0ZWN0aW9uIHdpdGggbm8gdXNlciBpbnB1dFxuICAgIHRyeSB7XG4gICAgICBleGVjU3luYygnd2hpY2ggemVuaXR5JywgeyBzdGRpbzogJ3BpcGUnIH0pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7IC8qIG5vdCBmb3VuZCAqLyB9XG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKCd3aGljaCBrZGlhbG9nJywgeyBzdGRpbzogJ3BpcGUnIH0pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7IC8qIG5vdCBmb3VuZCAqLyB9XG4gICAgdHJ5IHtcbiAgICAgIGV4ZWNTeW5jKCd3aGljaCB4bWVzc2FnZScsIHsgc3RkaW86ICdwaXBlJyB9KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggeyAvKiBub3QgZm91bmQgKi8gfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19