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.

129 lines 20.9 kB
/** * Security Monitor for DollhouseMCP * * Centralized security event logging and monitoring system * for tracking and alerting on security-related events. */ import { logger } from '../utils/logger.js'; import { EvictingQueue } from '../utils/EvictingQueue.js'; import { EventDeduplicator } from '../utils/EventDeduplicator.js'; /** Deduplication window: suppress identical events within this period */ const DEDUP_WINDOW_MS = 60_000; /** Maximum dedup cache entries before LRU eviction */ const DEDUP_MAX_SIZE = 500; export class SecurityMonitor { static eventCount = 0; static events = new EvictingQueue(1000); static logListener; static dedup = new EventDeduplicator(DEDUP_WINDOW_MS, DEDUP_MAX_SIZE); static addLogListener(fn) { this.logListener = fn; return () => { this.logListener = undefined; }; } /** * Logs a security event, suppressing repeated identical events within the dedup window. */ static logSecurityEvent(event) { // Deduplicate: same type + source + details within 60s window = suppress if (this.dedup.shouldSuppress(`${event.type}\0${event.source}\0${event.details}`)) { return; } const logEntry = { ...event, timestamp: new Date().toISOString(), id: `SEC-${Date.now()}-${++this.eventCount}`, }; // Bounded FIFO eviction — EvictingQueue handles capacity this.events.push(logEntry); this.logListener?.(logEntry); // In MCP servers, we cannot write to stderr/stdout as it breaks the JSON-RPC protocol // Security events are stored in memory and can be retrieved via API // Only send critical alerts via the proper channel if (event.severity === 'CRITICAL') { this.sendSecurityAlert(logEntry); } } /** * Sends security alerts for critical events */ static sendSecurityAlert(event) { // In a production environment, this would integrate with: // - Slack webhooks // - Email alerts // - PagerDuty // - Security Information and Event Management (SIEM) systems // Log critical security alerts with structured data // DO NOT use console.error in MCP servers as it breaks the JSON-RPC protocol logger.error('[CRITICAL SECURITY ALERT]', { type: event.type, details: event.details, timestamp: event.timestamp, id: event.id }); // If in production mode with proper config, send actual alerts if (process.env.DOLLHOUSE_SECURITY_ALERTS === 'true') { // TODO: Implement actual alert mechanisms } } /** * Gets recent security events for analysis */ static getRecentEvents(count = 100) { return this.events.toArray().slice(-count); } /** * Gets events by severity */ static getEventsBySeverity(severity) { return this.events.toArray().filter(event => event.severity === severity); } /** * Gets events by type */ static getEventsByType(type) { return this.events.toArray().filter(event => event.type === type); } /** * Generates a security report */ static generateSecurityReport() { const eventsBySeverity = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0, }; const eventsByType = {}; for (const event of this.events.toArray()) { eventsBySeverity[event.severity]++; eventsByType[event.type] = (eventsByType[event.type] || 0) + 1; } return { totalEvents: this.events.size, eventsBySeverity, eventsByType, recentCriticalEvents: this.getEventsBySeverity('CRITICAL').slice(-10), }; } /** * Clears old events (for memory management) */ static clearOldEvents(daysToKeep = 7) { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - daysToKeep); const cutoffTimestamp = cutoffDate.toISOString(); const remaining = this.events.toArray().filter(event => event.timestamp >= cutoffTimestamp); this.events.reset([...remaining]); } /** * TESTING ONLY: Clears all events and resets counter * Should only be called in test cleanup (afterEach/afterAll) * to prevent test pollution from accumulated security events */ static clearAllEventsForTesting() { this.events.clear(); this.eventCount = 0; this.dedup.clear(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJpdHlNb25pdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7R0FLRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUE2RGxFLHlFQUF5RTtBQUN6RSxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUM7QUFFL0Isc0RBQXNEO0FBQ3RELE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQztBQUUzQixNQUFNLE9BQU8sZUFBZTtJQUNsQixNQUFNLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztJQUN0QixNQUFNLENBQUMsTUFBTSxHQUFHLElBQUksYUFBYSxDQUFtQixJQUFJLENBQUMsQ0FBQztJQUMxRCxNQUFNLENBQUMsV0FBVyxDQUFxQztJQUN2RCxNQUFNLENBQVUsS0FBSyxHQUFHLElBQUksaUJBQWlCLENBQUMsZUFBZSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBRXZGLE1BQU0sQ0FBQyxjQUFjLENBQUMsRUFBcUM7UUFDekQsSUFBSSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7UUFDdEIsT0FBTyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsS0FBb0I7UUFDMUMseUVBQXlFO1FBQ3pFLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxLQUFLLEtBQUssQ0FBQyxNQUFNLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FB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LFlBQVk7WUFDWixvQkFBb0IsRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsVUFBVSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ3RFLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsY0FBYyxDQUFDLGFBQXFCLENBQUM7UUFDMUMsTUFBTSxVQUFVLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUM5QixVQUFVLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxVQUFVLENBQUMsQ0FBQztRQUN0RCxNQUFNLGVBQWUsR0FBRyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFakQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQzVDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFNBQVMsSUFBSSxlQUFlLENBQzVDLENBQUM7UUFDRixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyx3QkFBd0I7UUFDN0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNwQixJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlY3VyaXR5IE1vbml0b3IgZm9yIERvbGxob3VzZU1DUFxuICogXG4gKiBDZW50cmFsaXplZCBzZWN1cml0eSBldmVudCBsb2dnaW5nIGFuZCBtb25pdG9yaW5nIHN5c3RlbVxuICogZm9yIHRyYWNraW5nIGFuZCBhbGVydGluZyBvbiBzZWN1cml0eS1yZWxhdGVkIGV2ZW50cy5cbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRXZpY3RpbmdRdWV1ZSB9IGZyb20gJy4uL3V0aWxzL0V2aWN0aW5nUXVldWUuanMnO1xuaW1wb3J0IHsgRXZlbnREZWR1cGxpY2F0b3IgfSBmcm9tICcuLi91dGlscy9FdmVudERlZHVwbGljYXRvci5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VjdXJpdHlFdmVudCB7XG4gIHR5cGU6ICdDT05URU5UX0lOSkVDVElPTl9BVFRFTVBUJyB8ICdZQU1MX0lOSkVDVElPTl9BVFRFTVBUJyB8ICdQQVRIX1RSQVZFUlNBTF9BVFRFTVBUJyB8XG4gICAgICAgICdUT0tFTl9WQUxJREFUSU9OX0ZBSUxVUkUnIHwgJ1VQREFURV9TRUNVUklUWV9WSU9MQVRJT04nIHwgJ1JBVEVfTElNSVRfRVhDRUVERUQnIHxcbiAgICAgICAgJ1lBTUxfUEFSU0lOR19XQVJOSU5HJyB8ICdZQU1MX1BBUlNFX1NVQ0NFU1MnIHwgJ1RPS0VOX1ZBTElEQVRJT05fU1VDQ0VTUycgfFxuICAgICAgICAnUEFUSF9WQUxJREFUSU9OX1NVQ0NFU1MnIHwgJ1JBVEVfTElNSVRfV0FSTklORycgfCAnVE9LRU5fQ0FDSEVfQ0xFQVJFRCcgfFxuICAgICAgICAnWUFNTF9VTklDT0RFX0FUVEFDSycgfCAnVU5JQ09ERV9ESVJFQ1RJT05fT1ZFUlJJREUnIHwgJ1VOSUNPREVfTUlYRURfU0NSSVBUJyB8XG4gICAgICAgICdVTklDT0RFX1ZBTElEQVRJT05fRVJST1InIHwgJ0NPTlRFTlRfU0laRV9FWENFRURFRCcgfCAnSU5DTFVERV9ERVBUSF9FWENFRURFRCcgfFxuICAgICAgICAnVEVNUExBVEVfUkVOREVSRUQnIHwgJ1RFTVBMQVRFX0lOQ0xVREUnIHwgJ1RFTVBMQVRFX0xPQURFRCcgfCAnVEVNUExBVEVfU0FWRUQnIHxcbiAgICAgICAgJ1RFTVBMQVRFX0RFTEVURUQnIHwgJ01FTU9SWV9DUkVBVEVEJyB8ICdNRU1PUllfQURERUQnIHwgJ01FTU9SWV9TRUFSQ0hFRCcgfFxuICAgICAgICAnU0VOU0lUSVZFX01FTU9SWV9ERUxFVEVEJyB8ICdSRVRFTlRJT05fUE9MSUNZX0VORk9SQ0VEJyB8ICdNRU1PUllfQ0xFQVJFRCcgfFxuICAgICAgICAnTUVNT1JZX0xPQURFRCcgfCAnTUVNT1JZX1NBVkVEJyB8ICdNRU1PUllfREVMRVRFRCcgfCAnTUVNT1JZX0xPQURfRkFJTEVEJyB8XG4gICAgICAgICdNRU1PUllfU0FWRV9GQUlMRUQnIHwgJ01FTU9SWV9MSVNUX0lURU1fRkFJTEVEJyB8ICdNRU1PUllfSU1QT1JUX0ZBSUxFRCcgfFxuICAgICAgICAnTUVNT1JZX0RFU0VSSUFMSVpFX0ZBSUxFRCcgfCAnTUVNT1JZX0lOVEVHUklUWV9WSU9MQVRJT04nIHwgJ01FTU9SWV9VTklDT0RFX1ZBTElEQVRJT05fRkFJTEVEJyB8XG4gICAgICAgICdNRU1PUllfRFVQTElDQVRFX0RFVEVDVEVEJyB8ICdTRUVEX01FTU9SWV9JTlNUQUxMRUQnIHwgJ1NFRURfTUVNT1JZX0lOU1RBTExBVElPTl9GQUlMRUQnIHxcbiAgICAgICAgJ0VMRU1FTlRfQ1JFQVRFRCcgfCAnRUxFTUVOVF9MT0FERUQnIHwgJ0VMRU1FTlRfRURJVEVEJyB8ICdFTEVNRU5UX0FDVElWQVRFRCcgfCAnRUxFTUVOVF9ERUFDVElWQVRFRCcgfFxuICAgICAgICAnRUxFTUVOVF9WQUxJREFURUQnIHwgJ0VMRU1FTlRfREVMRVRFRCcgfFxuICAgICAgICAnQUdFTlRfQUNUSVZBVEVEJyB8ICdBR0VOVF9BQ1RJVkFUSU9OX0ZBSUxFRCcgfCAnQUdFTlRfQUNUSVZBVElPTl9ST0xMQkFDSycgfFxuICAgICAgICAnQUdFTlRfREVBQ1RJVkFURUQnIHwgJ0FHRU5UX0VYRUNVVEVEJyB8XG4gICAgICAgICdDT05GSUdfVVBEQVRFRCcgfCAnSURFTlRJVFlfQ0hBTkdFRCcgfFxuICAgICAgICAnT1BFUkFUSU9OX0NPTVBMRVRFRCcgfCAnT1BFUkFUSU9OX0ZBSUxFRCcgfCAnQkFUQ0hfQ09NUExFVEVEJyB8ICdCQVRDSF9SRUpFQ1RFRCcgfFxuICAgICAgICAnQ09ORklSTUFUSU9OX1JFQ09SREVEJyB8ICdHQVRFS0VFUEVSX0RFQ0lTSU9OJyB8XG4gICAgICAgICdBVVRIX0ZMT1dfSU5JVElBVEVEJyB8XG4gICAgICAgICdBR0VOVF9ERUNJU0lPTicgfFxuICAgICAgICAnUlVMRV9FTkdJTkVfQ09ORklHX1VQREFURScgfCAnUlVMRV9FTkdJTkVfQ09ORklHX1ZBTElEQVRJT05fRVJST1InIHxcbiAgICAgICAgJ0dPQUxfVEVNUExBVEVfQVBQTElFRCcgfCAnR09BTF9URU1QTEFURV9WQUxJREFUSU9OJyB8XG4gICAgICAgICdFTlNFTUJMRV9DSVJDVUxBUl9ERVBFTkRFTkNZJyB8ICdFTlNFTUJMRV9SRVNPVVJDRV9MSU1JVF9FWENFRURFRCcgfFxuICAgICAgICAnRU5TRU1CTEVfQUNUSVZBVElPTl9USU1FT1VUJyB8ICdFTlNFTUJMRV9BQ1RJVkFUSU9OX0ZBSUxFRCcgfCAnRU5TRU1CTEVfU1VTUElDSU9VU19DT05ESVRJT04nIHxcbiAgICAgICAgJ0VOU0VNQkxFX0NPTkRJVElPTl9FVkFMVUFUSU9OX0ZBSUxFRCcgfFxuICAgICAgICAnRU5TRU1CTEVfTkVTVEVEX0RFUFRIX0VYQ0VFREVEJyB8ICdFTlNFTUJMRV9DT05URVhUX1NJWkVfRVhDRUVERUQnIHxcbiAgICAgICAgJ0VOU0VNQkxFX0NPTlRFWFRfVkFMVUVfVE9PX0xBUkdFJyB8ICdFTlNFTUJMRV9TQVZFRCcgfCAnRU5TRU1CTEVfSU1QT1JURUQnIHwgJ0VOU0VNQkxFX0RFTEVURUQnIHxcbiAgICAgICAgJ1BPUlRGT0xJT19JTklUSUFMSVpBVElPTicgfCAnUE9SVEZPTElPX1BPUFVMQVRFRCcgfCAnRklMRV9DT1BJRUQnIHwgJ0RJUkVDVE9SWV9NSUdSQVRJT04nIHxcbiAgICAgICAgJ1BPUlRGT0xJT19DQUNIRV9JTlZBTElEQVRJT04nIHwgJ1BPUlRGT0xJT19GRVRDSF9TVUNDRVNTJyB8ICdURVNUX0RBVEFfQkxPQ0tFRCcgfFxuICAgICAgICAnVEVTVF9QQVRIX1NFQ1VSSVRZX1JJU0snIHwgJ1RFU1RfUFJPRFVDVElPTl9BQ0NFU1NfQkxPQ0tFRCcgfCAnVEVTVF9QQVRIX0lOVkFMSUQnIHxcbiAgICAgICAgJ1RFU1RfRU5WSVJPTk1FTlRfUFJPRFVDVElPTl9QQVRIJyB8ICdURVNUX0VOVklST05NRU5UX0RFUFJFQ0FURURfVkFSJyB8ICdUT09MX0NBQ0hFX0lOVkFMSURBVEVEJyB8XG4gICAgICAgICdGSUxFX1JFQUQnIHwgJ0ZJTEVfV1JJVFRFTicgfCAnRklMRV9ERUxFVEVEJyB8XG4gICAgICAgICdEQU5HRVJfWk9ORV9UUklHR0VSRUQnIHwgJ0RBTkdFUl9aT05FX09QRVJBVElPTicgfFxuICAgICAgICAnQVVUT05PTVlfREVOSUVEJyB8ICdBVVRPTk9NWV9QQVVTRUQnIHwgJ1NBRkVUWV9FVkFMVUFUSU9OX0ZBSUxVUkUnIHxcbiAgICAgICAgJ1ZFUklGSUNBVElPTl9BVFRFTVBURUQnIHwgJ1ZFUklGSUNBVElPTl9TVUNDRUVERUQnIHxcbiAgICAgICAgJ1ZFUklGSUNBVElPTl9GQUlMRUQnIHwgJ1ZFUklGSUNBVElPTl9FWFBJUkVEJyB8XG4gICAgICAgICdBR0VOVF9BVVRPX0NPTlRJTlVFRCcgfCAnQUdFTlRfU1RFUF9SRVRSSUVEJyB8XG4gICAgICAgICdBR0VOVF9BVVRPX1JFU1RBUlRFRCcgfCAnQUdFTlRfUkVTSUxJRU5DRV9MSU1JVF9SRUFDSEVEJyB8XG4gICAgICAgICdQRVJNSVNTSU9OX1BST01QVF9ERU5JRUQnIHxcbiAgICAgICAgJ0NMSV9BUFBST1ZBTF9SRVFVRVNURUQnIHwgJ0NMSV9BUFBST1ZBTF9HUkFOVEVEJyB8ICdDTElfQVBQUk9WQUxfQ09OU1VNRUQnIHxcbiAgICAgICAgJ1RPVFBfRU5ST0xMRUQnIHwgJ1RPVFBfRElTQUJMRUQnIHwgJ1RPVFBfQkFDS1VQX0NPREVfQ09OU1VNRUQnIHwgJ1RPVFBfVkVSSUZJQ0FUSU9OX0ZBSUxFRCcgfFxuICAgICAgICAnQ09OU09MRV9UT0tFTl9ST1RBVEVEJztcbiAgc2V2ZXJpdHk6ICdMT1cnIHwgJ01FRElVTScgfCAnSElHSCcgfCAnQ1JJVElDQUwnO1xuICBzb3VyY2U6IHN0cmluZztcbiAgZGV0YWlsczogc3RyaW5nO1xuICB1c2VyQWdlbnQ/OiBzdHJpbmc7XG4gIGlwPzogc3RyaW5nO1xuICBhZGRpdGlvbmFsRGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgYW55Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZWN1cml0eUxvZ0VudHJ5IGV4dGVuZHMgU2VjdXJpdHlFdmVudCB7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuICBpZDogc3RyaW5nO1xufVxuXG4vKiogRGVkdXBsaWNhdGlvbiB3aW5kb3c6IHN1cHByZXNzIGlkZW50aWNhbCBldmVudHMgd2l0aGluIHRoaXMgcGVyaW9kICovXG5jb25zdCBERURVUF9XSU5ET1dfTVMgPSA2MF8wMDA7XG5cbi8qKiBNYXhpbXVtIGRlZHVwIGNhY2hlIGVudHJpZXMgYmVmb3JlIExSVSBldmljdGlvbiAqL1xuY29uc3QgREVEVVBfTUFYX1NJWkUgPSA1MDA7XG5cbmV4cG9ydCBjbGFzcyBTZWN1cml0eU1vbml0b3Ige1xuICBwcml2YXRlIHN0YXRpYyBldmVudENvdW50ID0gMDtcbiAgcHJpdmF0ZSBzdGF0aWMgZXZlbnRzID0gbmV3IEV2aWN0aW5nUXVldWU8U2VjdXJpdHlMb2dFbnRyeT4oMTAwMCk7XG4gIHByaXZhdGUgc3RhdGljIGxvZ0xpc3RlbmVyPzogKGVudHJ5OiBTZWN1cml0eUxvZ0VudHJ5KSA9PiB2b2lkO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBkZWR1cCA9IG5ldyBFdmVudERlZHVwbGljYXRvcihERURVUF9XSU5ET1dfTVMsIERFRFVQX01BWF9TSVpFKTtcblxuICBzdGF0aWMgYWRkTG9nTGlzdGVuZXIoZm46IChlbnRyeTogU2VjdXJpdHlMb2dFbnRyeSkgPT4gdm9pZCk6ICgpID0+IHZvaWQge1xuICAgIHRoaXMubG9nTGlzdGVuZXIgPSBmbjtcbiAgICByZXR1cm4gKCkgPT4geyB0aGlzLmxvZ0xpc3RlbmVyID0gdW5kZWZpbmVkOyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIExvZ3MgYSBzZWN1cml0eSBldmVudCwgc3VwcHJlc3NpbmcgcmVwZWF0ZWQgaWRlbnRpY2FsIGV2ZW50cyB3aXRoaW4gdGhlIGRlZHVwIHdpbmRvdy5cbiAgICovXG4gIHN0YXRpYyBsb2dTZWN1cml0eUV2ZW50KGV2ZW50OiBTZWN1cml0eUV2ZW50KTogdm9pZCB7XG4gICAgLy8gRGVkdXBsaWNhdGU6IHNhbWUgdHlwZSArIHNvdXJjZSArIGRldGFpbHMgd2l0aGluIDYwcyB3aW5kb3cgPSBzdXBwcmVzc1xuICAgIGlmICh0aGlzLmRlZHVwLnNob3VsZFN1cHByZXNzKGAke2V2ZW50LnR5cGV9XFwwJHtldmVudC5zb3VyY2V9XFwwJHtldmVudC5kZXRhaWxzfWApKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgbG9nRW50cnk6IFNlY3VyaXR5TG9nRW50cnkgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgaWQ6IGBTRUMtJHtEYXRlLm5vdygpfS0keysrdGhpcy5ldmVudENvdW50fWAsXG4gICAgfTtcblxuICAgIC8vIEJvdW5kZWQgRklGTyBldmljdGlvbiDigJQgRXZpY3RpbmdRdWV1ZSBoYW5kbGVzIGNhcGFjaXR5XG4gICAgdGhpcy5ldmVudHMucHVzaChsb2dFbnRyeSk7XG4gICAgdGhpcy5sb2dMaXN0ZW5lcj8uKGxvZ0VudHJ5KTtcblxuICAgIC8vIEluIE1DUCBzZXJ2ZXJzLCB3ZSBjYW5ub3Qgd3JpdGUgdG8gc3RkZXJyL3N0ZG91dCBhcyBpdCBicmVha3MgdGhlIEpTT04tUlBDIHByb3RvY29sXG4gICAgLy8gU2VjdXJpdHkgZXZlbnRzIGFyZSBzdG9yZWQgaW4gbWVtb3J5IGFuZCBjYW4gYmUgcmV0cmlldmVkIHZpYSBBUElcbiAgICAvLyBPbmx5IHNlbmQgY3JpdGljYWwgYWxlcnRzIHZpYSB0aGUgcHJvcGVyIGNoYW5uZWxcblxuICAgIGlmIChldmVudC5zZXZlcml0eSA9PT0gJ0NSSVRJQ0FMJykge1xuICAgICAgdGhpcy5zZW5kU2VjdXJpdHlBbGVydChsb2dFbnRyeSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIHNlY3VyaXR5IGFsZXJ0cyBmb3IgY3JpdGljYWwgZXZlbnRzXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBzZW5kU2VjdXJpdHlBbGVydChldmVudDogU2VjdXJpdHlMb2dFbnRyeSk6IHZvaWQge1xuICAgIC8vIEluIGEgcHJvZHVjdGlvbiBlbnZpcm9ubWVudCwgdGhpcyB3b3VsZCBpbnRlZ3JhdGUgd2l0aDpcbiAgICAvLyAtIFNsYWNrIHdlYmhvb2tzXG4gICAgLy8gLSBFbWFpbCBhbGVydHNcbiAgICAvLyAtIFBhZ2VyRHV0eVxuICAgIC8vIC0gU2VjdXJpdHkgSW5mb3JtYXRpb24gYW5kIEV2ZW50IE1hbmFnZW1lbnQgKFNJRU0pIHN5c3RlbXNcbiAgICBcbiAgICAvLyBMb2cgY3JpdGljYWwgc2VjdXJpdHkgYWxlcnRzIHdpdGggc3RydWN0dXJlZCBkYXRhXG4gICAgLy8gRE8gTk9UIHVzZSBjb25zb2xlLmVycm9yIGluIE1DUCBzZXJ2ZXJzIGFzIGl0IGJyZWFrcyB0aGUgSlNPTi1SUEMgcHJvdG9jb2xcbiAgICBsb2dnZXIuZXJyb3IoJ1tDUklUSUNBTCBTRUNVUklUWSBBTEVSVF0nLCB7XG4gICAgICB0eXBlOiBldmVudC50eXBlLFxuICAgICAgZGV0YWlsczogZXZlbnQuZGV0YWlscyxcbiAgICAgIHRpbWVzdGFtcDogZXZlbnQudGltZXN0YW1wLFxuICAgICAgaWQ6IGV2ZW50LmlkXG4gICAgfSk7XG4gICAgXG4gICAgLy8gSWYgaW4gcHJvZHVjdGlvbiBtb2RlIHdpdGggcHJvcGVyIGNvbmZpZywgc2VuZCBhY3R1YWwgYWxlcnRzXG4gICAgaWYgKHByb2Nlc3MuZW52LkRPTExIT1VTRV9TRUNVUklUWV9BTEVSVFMgPT09ICd0cnVlJykge1xuICAgICAgLy8gVE9ETzogSW1wbGVtZW50IGFjdHVhbCBhbGVydCBtZWNoYW5pc21zXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgcmVjZW50IHNlY3VyaXR5IGV2ZW50cyBmb3IgYW5hbHlzaXNcbiAgICovXG4gIHN0YXRpYyBnZXRSZWNlbnRFdmVudHMoY291bnQ6IG51bWJlciA9IDEwMCk6IFNlY3VyaXR5TG9nRW50cnlbXSB7XG4gICAgcmV0dXJuIHRoaXMuZXZlbnRzLnRvQXJyYXkoKS5zbGljZSgtY291bnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgZXZlbnRzIGJ5IHNldmVyaXR5XG4gICAqL1xuICBzdGF0aWMgZ2V0RXZlbnRzQnlTZXZlcml0eShzZXZlcml0eTogU2VjdXJpdHlFdmVudFsnc2V2ZXJpdHknXSk6IFNlY3VyaXR5TG9nRW50cnlbXSB7XG4gICAgcmV0dXJuIHRoaXMuZXZlbnRzLnRvQXJyYXkoKS5maWx0ZXIoZXZlbnQgPT4gZXZlbnQuc2V2ZXJpdHkgPT09IHNldmVyaXR5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGV2ZW50cyBieSB0eXBlXG4gICAqL1xuICBzdGF0aWMgZ2V0RXZlbnRzQnlUeXBlKHR5cGU6IFNlY3VyaXR5RXZlbnRbJ3R5cGUnXSk6IFNlY3VyaXR5TG9nRW50cnlbXSB7XG4gICAgcmV0dXJuIHRoaXMuZXZlbnRzLnRvQXJyYXkoKS5maWx0ZXIoZXZlbnQgPT4gZXZlbnQudHlwZSA9PT0gdHlwZSk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGEgc2VjdXJpdHkgcmVwb3J0XG4gICAqL1xuICBzdGF0aWMgZ2VuZXJhdGVTZWN1cml0eVJlcG9ydCgpOiB7XG4gICAgdG90YWxFdmVudHM6IG51bWJlcjtcbiAgICBldmVudHNCeVNldmVyaXR5OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xuICAgIGV2ZW50c0J5VHlwZTogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgICByZWNlbnRDcml0aWNhbEV2ZW50czogU2VjdXJpdHlMb2dFbnRyeVtdO1xuICB9IHtcbiAgICBjb25zdCBldmVudHNCeVNldmVyaXR5OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge1xuICAgICAgQ1JJVElDQUw6IDAsXG4gICAgICBISUdIOiAwLFxuICAgICAgTUVESVVNOiAwLFxuICAgICAgTE9XOiAwLFxuICAgIH07XG5cbiAgICBjb25zdCBldmVudHNCeVR5cGU6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcblxuICAgIGZvciAoY29uc3QgZXZlbnQgb2YgdGhpcy5ldmVudHMudG9BcnJheSgpKSB7XG4gICAgICBldmVudHNCeVNldmVyaXR5W2V2ZW50LnNldmVyaXR5XSsrO1xuICAgICAgZXZlbnRzQnlUeXBlW2V2ZW50LnR5cGVdID0gKGV2ZW50c0J5VHlwZVtldmVudC50eXBlXSB8fCAwKSArIDE7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsRXZlbnRzOiB0aGlzLmV2ZW50cy5zaXplLFxuICAgICAgZXZlbnRzQnlTZXZlcml0eSxcbiAgICAgIGV2ZW50c0J5VHlwZSxcbiAgICAgIHJlY2VudENyaXRpY2FsRXZlbnRzOiB0aGlzLmdldEV2ZW50c0J5U2V2ZXJpdHkoJ0NSSVRJQ0FMJykuc2xpY2UoLTEwKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyBvbGQgZXZlbnRzIChmb3IgbWVtb3J5IG1hbmFnZW1lbnQpXG4gICAqL1xuICBzdGF0aWMgY2xlYXJPbGRFdmVudHMoZGF5c1RvS2VlcDogbnVtYmVyID0gNyk6IHZvaWQge1xuICAgIGNvbnN0IGN1dG9mZkRhdGUgPSBuZXcgRGF0ZSgpO1xuICAgIGN1dG9mZkRhdGUuc2V0RGF0ZShjdXRvZmZEYXRlLmdldERhdGUoKSAtIGRheXNUb0tlZXApO1xuICAgIGNvbnN0IGN1dG9mZlRpbWVzdGFtcCA9IGN1dG9mZkRhdGUudG9JU09TdHJpbmcoKTtcblxuICAgIGNvbnN0IHJlbWFpbmluZyA9IHRoaXMuZXZlbnRzLnRvQXJyYXkoKS5maWx0ZXIoXG4gICAgICBldmVudCA9PiBldmVudC50aW1lc3RhbXAgPj0gY3V0b2ZmVGltZXN0YW1wXG4gICAgKTtcbiAgICB0aGlzLmV2ZW50cy5yZXNldChbLi4ucmVtYWluaW5nXSk7XG4gIH1cblxuICAvKipcbiAgICogVEVTVElORyBPTkxZOiBDbGVhcnMgYWxsIGV2ZW50cyBhbmQgcmVzZXRzIGNvdW50ZXJcbiAgICogU2hvdWxkIG9ubHkgYmUgY2FsbGVkIGluIHRlc3QgY2xlYW51cCAoYWZ0ZXJFYWNoL2FmdGVyQWxsKVxuICAgKiB0byBwcmV2ZW50IHRlc3QgcG9sbHV0aW9uIGZyb20gYWNjdW11bGF0ZWQgc2VjdXJpdHkgZXZlbnRzXG4gICAqL1xuICBzdGF0aWMgY2xlYXJBbGxFdmVudHNGb3JUZXN0aW5nKCk6IHZvaWQge1xuICAgIHRoaXMuZXZlbnRzLmNsZWFyKCk7XG4gICAgdGhpcy5ldmVudENvdW50ID0gMDtcbiAgICB0aGlzLmRlZHVwLmNsZWFyKCk7XG4gIH1cbn1cbiJdfQ==