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.

190 lines • 24.8 kB
/** * IdentityHandler - Manages user identity and attribution * * Handles user identity management for persona attribution including: * - Setting user identity (username and optional email) * - Retrieving current identity status * - Clearing identity to return to anonymous mode * - Providing attribution for new personas * * Identity state now flows through PersonaManager for DI integration. */ import { validateUsername, sanitizeInput } from '../security/InputValidator.js'; import { VALIDATION_PATTERNS } from '../security/constants.js'; import { SecureErrorHandler } from '../security/errorHandler.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; export class IdentityHandler { personaManager; initService; indicatorService; constructor(personaManager, initService, indicatorService) { this.personaManager = personaManager; this.initService = initService; this.indicatorService = indicatorService; } async ensureInitialized() { await this.initService.ensureInitialized(); } withIndicator(message) { const indicator = this.indicatorService.getPersonaIndicator(); return `${indicator}${message}`; } /** * Set user identity for attribution * @param username - Username to set (alphanumeric, hyphens, underscores, dots) * @param email - Optional email address */ async setUserIdentity(username, email) { await this.ensureInitialized(); try { if (!username || username.trim().length === 0) { return { content: [ { type: 'text', text: this.withIndicator('āŒ Username cannot be empty'), }, ], }; } const validatedUsername = validateUsername(username); let validatedEmail; if (email) { const sanitizedEmail = sanitizeInput(email, 100); if (!VALIDATION_PATTERNS.SAFE_EMAIL.test(sanitizedEmail)) { throw new Error('Invalid email format'); } validatedEmail = sanitizedEmail; } this.personaManager.setUserIdentity(validatedUsername, validatedEmail); const { username: currentUsername, email: currentEmail } = this.personaManager.getUserIdentity(); // FIX: DMCP-SEC-006 - Add security audit logging for identity changes SecurityMonitor.logSecurityEvent({ type: 'IDENTITY_CHANGED', severity: 'LOW', source: 'IdentityHandler.setUserIdentity', details: `User identity set: ${currentUsername}`, additionalData: { username: currentUsername, emailProvided: !!currentEmail } }); return { content: [ { type: 'text', text: this.withIndicator(`āœ… **User Identity Set**\n\n` + `šŸ‘¤ **Username:** ${currentUsername}\n` + `${currentEmail ? `šŸ“§ **Email:** ${currentEmail}\n` : ''}` + `\nšŸŽÆ **Next Steps:**\n` + `• New personas you create will be attributed to "${currentUsername}"\n` + `• Set environment variable \`DOLLHOUSE_USER=${currentUsername}\` to persist this setting\n` + `${currentEmail ? `• Set environment variable \`DOLLHOUSE_EMAIL=${currentEmail}\` for contact info\n` : ''}` + `• Use \`clear_user_identity\` to return to anonymous mode`), }, ], }; } catch (error) { const sanitized = SecureErrorHandler.sanitizeError(error); return { content: [ { type: 'text', text: this.withIndicator('āŒ **Validation Error**\n\n') + `${sanitized.message}\n\n` + `Please provide a valid username (alphanumeric characters, hyphens, underscores, dots only).`, }, ], }; } } /** * Get current user identity status * Shows username, email (if set), and attribution status */ async getUserIdentity() { await this.ensureInitialized(); const { username: currentUsername, email } = this.personaManager.getUserIdentity(); if (!currentUsername) { return { content: [ { type: 'text', text: this.withIndicator(`šŸ‘¤ **User Identity: Anonymous**\n\n` + `šŸ”’ **Status:** Anonymous mode\n` + `šŸ“ **Attribution:** Personas will use anonymous IDs\n\n` + `**To set your identity:**\n` + `• Use: \`set_user_identity "your-username"\`\n` + `• Or set environment variable: \`DOLLHOUSE_USER=your-username\``), }, ], }; } return { content: [ { type: 'text', text: this.withIndicator(`šŸ‘¤ **User Identity: ${currentUsername}**\n\n` + `āœ… **Status:** Authenticated\n` + `šŸ‘¤ **Username:** ${currentUsername}\n` + `${email ? `šŸ“§ **Email:** ${email}\n` : ''}` + `šŸ“ **Attribution:** New personas will be credited to "${currentUsername}"\n\n` + `**Environment Variables:**\n` + `• \`DOLLHOUSE_USER=${currentUsername}\`\n` + `${email ? `• \`DOLLHOUSE_EMAIL=${email}\`\n` : ''}` + `\n**Management:**\n` + `• Use \`clear_user_identity\` to return to anonymous mode\n` + `• Use \`set_user_identity "new-username"\` to change username`), }, ], }; } /** * Clear user identity and return to anonymous mode */ async clearUserIdentity() { await this.ensureInitialized(); const { username: currentUsername } = this.personaManager.getUserIdentity(); const wasSet = currentUsername !== null; const previousUser = currentUsername; this.personaManager.clearUserIdentity(); // FIX: DMCP-SEC-006 - Add security audit logging for identity clearing if (wasSet) { SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_DELETED', severity: 'LOW', source: 'IdentityHandler.clearUserIdentity', details: `User identity cleared: previous=${previousUser}`, additionalData: { previousUsername: previousUser } }); } return { content: [ { type: 'text', text: wasSet ? this.withIndicator(`āœ… **User Identity Cleared**\n\n` + `šŸ‘¤ **Previous:** ${previousUser}\n` + `šŸ”’ **Current:** Anonymous mode\n\n` + `šŸ“ **Effect:** New personas will use anonymous IDs\n\n` + `āš ļø **Note:** This only affects the current session.\n` + `To persist this change, unset the \`DOLLHOUSE_USER\` environment variable.`) : this.withIndicator(`ā„¹ļø **Already in Anonymous Mode**\n\n` + `šŸ‘¤ No user identity was set.\n\n` + `Use \`set_user_identity "username"\` to set your identity.`), }, ], }; } /** * Get current user for attribution purposes * Returns username if set, otherwise PersonaManager's anonymous ID */ getCurrentUserForAttribution() { return this.personaManager.getCurrentUserForAttribution(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSWRlbnRpdHlIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hhbmRsZXJzL0lkZW50aXR5SGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztHQVVHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGFBQWEsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2hGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBSWpFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVqRSxNQUFNLE9BQU8sZUFBZTtJQUVQO0lBQ0E7SUFDQTtJQUhuQixZQUNtQixjQUE4QixFQUM5QixXQUFrQyxFQUNsQyxnQkFBeUM7UUFGekMsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLGdCQUFXLEdBQVgsV0FBVyxDQUF1QjtRQUNsQyxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQXlCO0lBQ3pELENBQUM7SUFFSSxLQUFLLENBQUMsaUJBQWlCO1FBQzdCLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQzdDLENBQUM7SUFFTyxhQUFhLENBQUMsT0FBZTtRQUNuQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUM5RCxPQUFPLEdBQUcsU0FBUyxHQUFHLE9BQU8sRUFBRSxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGVBQWUsQ0FBQyxRQUFnQixFQUFFLEtBQWM7UUFDcEQsTUFBTSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUUvQixJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEtBQUssQ0FB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O2dCQUN2QixRQUFRLEVBQUUsS0FBSztnQkFDZixNQUFNLEVBQUUsbUNBQW1DO2dCQUMzQyxPQUFPLEVBQUUsbUNBQW1DLFlBQVksRUFBRTtnQkFDMUQsY0FBYyxFQUFFO29CQUNkLGdCQUFnQixFQUFFLFlBQVk7aUJBQy9CO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU87WUFDTCxPQUFPLEVBQUU7Z0JBQ1A7b0JBQ0UsSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxNQUFNO3dCQUNWLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUNoQixpQ0FBaUM7NEJBQy9CLG9CQUFvQixZQUFZLElBQUk7NEJBQ3BDLG9DQUFvQzs0QkFDcEMsd0RBQXdEOzRCQUN4RCx1REFBdUQ7NEJBQ3ZELDRFQUE0RSxDQUMvRTt3QkFDSCxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FDaEIsc0NBQXNDOzRCQUNwQyxrQ0FBa0M7NEJBQ2xDLDREQUE0RCxDQUMvRDtpQkFDTjthQUNGO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSSw0QkFBNEI7UUFDakMsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLDRCQUE0QixFQUFFLENBQUM7SUFDNUQsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBJZGVudGl0eUhhbmRsZXIgLSBNYW5hZ2VzIHVzZXIgaWRlbnRpdHkgYW5kIGF0dHJpYnV0aW9uXG4gKlxuICogSGFuZGxlcyB1c2VyIGlkZW50aXR5IG1hbmFnZW1lbnQgZm9yIHBlcnNvbmEgYXR0cmlidXRpb24gaW5jbHVkaW5nOlxuICogLSBTZXR0aW5nIHVzZXIgaWRlbnRpdHkgKHVzZXJuYW1lIGFuZCBvcHRpb25hbCBlbWFpbClcbiAqIC0gUmV0cmlldmluZyBjdXJyZW50IGlkZW50aXR5IHN0YXR1c1xuICogLSBDbGVhcmluZyBpZGVudGl0eSB0byByZXR1cm4gdG8gYW5vbnltb3VzIG1vZGVcbiAqIC0gUHJvdmlkaW5nIGF0dHJpYnV0aW9uIGZvciBuZXcgcGVyc29uYXNcbiAqXG4gKiBJZGVudGl0eSBzdGF0ZSBub3cgZmxvd3MgdGhyb3VnaCBQZXJzb25hTWFuYWdlciBmb3IgREkgaW50ZWdyYXRpb24uXG4gKi9cblxuaW1wb3J0IHsgdmFsaWRhdGVVc2VybmFtZSwgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFZBTElEQVRJT05fUEFUVEVSTlMgfSBmcm9tICcuLi9zZWN1cml0eS9jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgU2VjdXJlRXJyb3JIYW5kbGVyIH0gZnJvbSAnLi4vc2VjdXJpdHkvZXJyb3JIYW5kbGVyLmpzJztcbmltcG9ydCB7IFBlcnNvbmFNYW5hZ2VyIH0gZnJvbSAnLi4vcGVyc29uYS9QZXJzb25hTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBJbml0aWFsaXphdGlvblNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9Jbml0aWFsaXphdGlvblNlcnZpY2UuanMnO1xuaW1wb3J0IHsgUGVyc29uYUluZGljYXRvclNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9QZXJzb25hSW5kaWNhdG9yU2VydmljZS5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuXG5leHBvcnQgY2xhc3MgSWRlbnRpdHlIYW5kbGVyIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBwZXJzb25hTWFuYWdlcjogUGVyc29uYU1hbmFnZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBpbml0U2VydmljZTogSW5pdGlhbGl6YXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgaW5kaWNhdG9yU2VydmljZTogUGVyc29uYUluZGljYXRvclNlcnZpY2VcbiAgKSB7fVxuXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlSW5pdGlhbGl6ZWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5pbml0U2VydmljZS5lbnN1cmVJbml0aWFsaXplZCgpO1xuICB9XG5cbiAgcHJpdmF0ZSB3aXRoSW5kaWNhdG9yKG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgaW5kaWNhdG9yID0gdGhpcy5pbmRpY2F0b3JTZXJ2aWNlLmdldFBlcnNvbmFJbmRpY2F0b3IoKTtcbiAgICByZXR1cm4gYCR7aW5kaWNhdG9yfSR7bWVzc2FnZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB1c2VyIGlkZW50aXR5IGZvciBhdHRyaWJ1dGlvblxuICAgKiBAcGFyYW0gdXNlcm5hbWUgLSBVc2VybmFtZSB0byBzZXQgKGFscGhhbnVtZXJpYywgaHlwaGVucywgdW5kZXJzY29yZXMsIGRvdHMpXG4gICAqIEBwYXJhbSBlbWFpbCAtIE9wdGlvbmFsIGVtYWlsIGFkZHJlc3NcbiAgICovXG4gIGFzeW5jIHNldFVzZXJJZGVudGl0eSh1c2VybmFtZTogc3RyaW5nLCBlbWFpbD86IHN0cmluZykge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlSW5pdGlhbGl6ZWQoKTtcblxuICAgIHRyeSB7XG4gICAgICBpZiAoIXVzZXJuYW1lIHx8IHVzZXJuYW1lLnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgdGV4dDogdGhpcy53aXRoSW5kaWNhdG9yKCfinYwgVXNlcm5hbWUgY2Fubm90IGJlIGVtcHR5JyksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHZhbGlkYXRlZFVzZXJuYW1lID0gdmFsaWRhdGVVc2VybmFtZSh1c2VybmFtZSk7XG5cbiAgICAgIGxldCB2YWxpZGF0ZWRFbWFpbDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKGVtYWlsKSB7XG4gICAgICAgIGNvbnN0IHNhbml0aXplZEVtYWlsID0gc2FuaXRpemVJbnB1dChlbWFpbCwgMTAwKTtcbiAgICAgICAgaWYgKCFWQUxJREFUSU9OX1BBVFRFUk5TLlNBRkVfRU1BSUwudGVzdChzYW5pdGl6ZWRFbWFpbCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZW1haWwgZm9ybWF0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFsaWRhdGVkRW1haWwgPSBzYW5pdGl6ZWRFbWFpbDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5wZXJzb25hTWFuYWdlci5zZXRVc2VySWRlbnRpdHkodmFsaWRhdGVkVXNlcm5hbWUsIHZhbGlkYXRlZEVtYWlsKTtcbiAgICAgIGNvbnN0IHsgdXNlcm5hbWU6IGN1cnJlbnRVc2VybmFtZSwgZW1haWw6IGN1cnJlbnRFbWFpbCB9ID0gdGhpcy5wZXJzb25hTWFuYWdlci5nZXRVc2VySWRlbnRpdHkoKTtcblxuICAgICAgLy8gRklYOiBETUNQLVNFQy0wMDYgLSBBZGQgc2VjdXJpdHkgYXVkaXQgbG9nZ2luZyBmb3IgaWRlbnRpdHkgY2hhbmdlc1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnSURFTlRJVFlfQ0hBTkdFRCcsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiAnSWRlbnRpdHlIYW5kbGVyLnNldFVzZXJJZGVudGl0eScsXG4gICAgICAgIGRldGFpbHM6IGBVc2VyIGlkZW50aXR5IHNldDogJHtjdXJyZW50VXNlcm5hbWV9YCxcbiAgICAgICAgYWRkaXRpb25hbERhdGE6IHtcbiAgICAgICAgICB1c2VybmFtZTogY3VycmVudFVzZXJuYW1lLFxuICAgICAgICAgIGVtYWlsUHJvdmlkZWQ6ICEhY3VycmVudEVtYWlsXG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgdGV4dDogdGhpcy53aXRoSW5kaWNhdG9yKFxuICAgICAgICAgICAgICBg4pyFICoqVXNlciBJZGVudGl0eSBTZXQqKlxcblxcbmAgK1xuICAgICAgICAgICAgICAgIGDwn5GkICoqVXNlcm5hbWU6KiogJHtjdXJyZW50VXNlcm5hbWV9XFxuYCArXG4gICAgICAgICAgICAgICAgYCR7Y3VycmVudEVtYWlsID8gYPCfk6cgKipFbWFpbDoqKiAke2N1cnJlbnRFbWFpbH1cXG5gIDogJyd9YCArXG4gICAgICAgICAgICAgICAgYFxcbvCfjq8gKipOZXh0IFN0ZXBzOioqXFxuYCArXG4gICAgICAgICAgICAgICAgYOKAoiBOZXcgcGVyc29uYXMgeW91IGNyZWF0ZSB3aWxsIGJlIGF0dHJpYnV0ZWQgdG8gXCIke2N1cnJlbnRVc2VybmFtZX1cIlxcbmAgK1xuICAgICAgICAgICAgICAgIGDigKIgU2V0IGVudmlyb25tZW50IHZhcmlhYmxlIFxcYERPTExIT1VTRV9VU0VSPSR7Y3VycmVudFVzZXJuYW1lfVxcYCB0byBwZXJzaXN0IHRoaXMgc2V0dGluZ1xcbmAgK1xuICAgICAgICAgICAgICAgIGAke2N1cnJlbnRFbWFpbCA/IGDigKIgU2V0IGVudmlyb25tZW50IHZhcmlhYmxlIFxcYERPTExIT1VTRV9FTUFJTD0ke2N1cnJlbnRFbWFpbH1cXGAgZm9yIGNvbnRhY3QgaW5mb1xcbmAgOiAnJ31gICtcbiAgICAgICAgICAgICAgICBg4oCiIFVzZSBcXGBjbGVhcl91c2VyX2lkZW50aXR5XFxgIHRvIHJldHVybiB0byBhbm9ueW1vdXMgbW9kZWBcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IHNhbml0aXplZCA9IFNlY3VyZUVycm9ySGFuZGxlci5zYW5pdGl6ZUVycm9yKGVycm9yKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICB0ZXh0OlxuICAgICAgICAgICAgICB0aGlzLndpdGhJbmRpY2F0b3IoJ+KdjCAqKlZhbGlkYXRpb24gRXJyb3IqKlxcblxcbicpICtcbiAgICAgICAgICAgICAgYCR7c2FuaXRpemVkLm1lc3NhZ2V9XFxuXFxuYCArXG4gICAgICAgICAgICAgIGBQbGVhc2UgcHJvdmlkZSBhIHZhbGlkIHVzZXJuYW1lIChhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgaHlwaGVucywgdW5kZXJzY29yZXMsIGRvdHMgb25seSkuYCxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgdXNlciBpZGVudGl0eSBzdGF0dXNcbiAgICogU2hvd3MgdXNlcm5hbWUsIGVtYWlsIChpZiBzZXQpLCBhbmQgYXR0cmlidXRpb24gc3RhdHVzXG4gICAqL1xuICBhc3luYyBnZXRVc2VySWRlbnRpdHkoKSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVJbml0aWFsaXplZCgpO1xuXG4gICAgY29uc3QgeyB1c2VybmFtZTogY3VycmVudFVzZXJuYW1lLCBlbWFpbCB9ID0gdGhpcy5wZXJzb25hTWFuYWdlci5nZXRVc2VySWRlbnRpdHkoKTtcblxuICAgIGlmICghY3VycmVudFVzZXJuYW1lKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgdGV4dDogdGhpcy53aXRoSW5kaWNhdG9yKFxuICAgICAgICAgICAgICBg8J+RpCAqKlVzZXIgSWRlbnRpdHk6IEFub255bW91cyoqXFxuXFxuYCArXG4gICAgICAgICAgICAgICAgYPCflJIgKipTdGF0dXM6KiogQW5vbnltb3VzIG1vZGVcXG5gICtcbiAgICAgICAgICAgICAgICBg8J+TnSAqKkF0dHJpYnV0aW9uOioqIFBlcnNvbmFzIHdpbGwgdXNlIGFub255bW91cyBJRHNcXG5cXG5gICtcbiAgICAgICAgICAgICAgICBgKipUbyBzZXQgeW91ciBpZGVudGl0eToqKlxcbmAgK1xuICAgICAgICAgICAgICAgIGDigKIgVXNlOiBcXGBzZXRfdXNlcl9pZGVudGl0eSBcInlvdXItdXNlcm5hbWVcIlxcYFxcbmAgK1xuICAgICAgICAgICAgICAgIGDigKIgT3Igc2V0IGVudmlyb25tZW50IHZhcmlhYmxlOiBcXGBET0xMSE9VU0VfVVNFUj15b3VyLXVzZXJuYW1lXFxgYFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW1xuICAgICAgICB7XG4gICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgIHRleHQ6IHRoaXMud2l0aEluZGljYXRvcihcbiAgICAgICAgICAgIGDwn5GkICoqVXNlciBJZGVudGl0eTogJHtjdXJyZW50VXNlcm5hbWV9KipcXG5cXG5gICtcbiAgICAgICAgICAgICAgYOKchSAqKlN0YXR1czoqKiBBdXRoZW50aWNhdGVkXFxuYCArXG4gICAgICAgICAgICAgIGDwn5GkICoqVXNlcm5hbWU6KiogJHtjdXJyZW50VXNlcm5hbWV9XFxuYCArXG4gICAgICAgICAgICAgIGAke2VtYWlsID8gYPCfk6cgKipFbWFpbDoqKiAke2VtYWlsfVxcbmAgOiAnJ31gICtcbiAgICAgICAgICAgICAgYPCfk50gKipBdHRyaWJ1dGlvbjoqKiBOZXcgcGVyc29uYXMgd2lsbCBiZSBjcmVkaXRlZCB0byBcIiR7Y3VycmVudFVzZXJuYW1lfVwiXFxuXFxuYCArXG4gICAgICAgICAgICAgIGAqKkVudmlyb25tZW50IFZhcmlhYmxlczoqKlxcbmAgK1xuICAgICAgICAgICAgICBg4oCiIFxcYERPTExIT1VTRV9VU0VSPSR7Y3VycmVudFVzZXJuYW1lfVxcYFxcbmAgK1xuICAgICAgICAgICAgICBgJHtlbWFpbCA/IGDigKIgXFxgRE9MTEhPVVNFX0VNQUlMPSR7ZW1haWx9XFxgXFxuYCA6ICcnfWAgK1xuICAgICAgICAgICAgICBgXFxuKipNYW5hZ2VtZW50OioqXFxuYCArXG4gICAgICAgICAgICAgIGDigKIgVXNlIFxcYGNsZWFyX3VzZXJfaWRlbnRpdHlcXGAgdG8gcmV0dXJuIHRvIGFub255bW91cyBtb2RlXFxuYCArXG4gICAgICAgICAgICAgIGDigKIgVXNlIFxcYHNldF91c2VyX2lkZW50aXR5IFwibmV3LXVzZXJuYW1lXCJcXGAgdG8gY2hhbmdlIHVzZXJuYW1lYFxuICAgICAgICAgICksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdXNlciBpZGVudGl0eSBhbmQgcmV0dXJuIHRvIGFub255bW91cyBtb2RlXG4gICAqL1xuICBhc3luYyBjbGVhclVzZXJJZGVudGl0eSgpIHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZUluaXRpYWxpemVkKCk7XG5cbiAgICBjb25zdCB7IHVzZXJuYW1lOiBjdXJyZW50VXNlcm5hbWUgfSA9IHRoaXMucGVyc29uYU1hbmFnZXIuZ2V0VXNlcklkZW50aXR5KCk7XG4gICAgY29uc3Qgd2FzU2V0ID0gY3VycmVudFVzZXJuYW1lICE9PSBudWxsO1xuICAgIGNvbnN0IHByZXZpb3VzVXNlciA9IGN1cnJlbnRVc2VybmFtZTtcblxuICAgIHRoaXMucGVyc29uYU1hbmFnZXIuY2xlYXJVc2VySWRlbnRpdHkoKTtcblxuICAgIC8vIEZJWDogRE1DUC1TRUMtMDA2IC0gQWRkIHNlY3VyaXR5IGF1ZGl0IGxvZ2dpbmcgZm9yIGlkZW50aXR5IGNsZWFyaW5nXG4gICAgaWYgKHdhc1NldCkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnRUxFTUVOVF9ERUxFVEVEJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6ICdJZGVudGl0eUhhbmRsZXIuY2xlYXJVc2VySWRlbnRpdHknLFxuICAgICAgICBkZXRhaWxzOiBgVXNlciBpZGVudGl0eSBjbGVhcmVkOiBwcmV2aW91cz0ke3ByZXZpb3VzVXNlcn1gLFxuICAgICAgICBhZGRpdGlvbmFsRGF0YToge1xuICAgICAgICAgIHByZXZpb3VzVXNlcm5hbWU6IHByZXZpb3VzVXNlclxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW1xuICAgICAgICB7XG4gICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgIHRleHQ6IHdhc1NldFxuICAgICAgICAgICAgPyB0aGlzLndpdGhJbmRpY2F0b3IoXG4gICAgICAgICAgICAgICAgYOKchSAqKlVzZXIgSWRlbnRpdHkgQ2xlYXJlZCoqXFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBg8J+RpCAqKlByZXZpb3VzOioqICR7cHJldmlvdXNVc2VyfVxcbmAgK1xuICAgICAgICAgICAgICAgICAgYPCflJIgKipDdXJyZW50OioqIEFub255bW91cyBtb2RlXFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBg8J+TnSAqKkVmZmVjdDoqKiBOZXcgcGVyc29uYXMgd2lsbCB1c2UgYW5vbnltb3VzIElEc1xcblxcbmAgK1xuICAgICAgICAgICAgICAgICAgYOKaoO+4jyAqKk5vdGU6KiogVGhpcyBvbmx5IGFmZmVjdHMgdGhlIGN1cnJlbnQgc2Vzc2lvbi5cXG5gICtcbiAgICAgICAgICAgICAgICAgIGBUbyBwZXJzaXN0IHRoaXMgY2hhbmdlLCB1bnNldCB0aGUgXFxgRE9MTEhPVVNFX1VTRVJcXGAgZW52aXJvbm1lbnQgdmFyaWFibGUuYFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICA6IHRoaXMud2l0aEluZGljYXRvcihcbiAgICAgICAgICAgICAgICBg4oS577iPICoqQWxyZWFkeSBpbiBBbm9ueW1vdXMgTW9kZSoqXFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBg8J+RpCBObyB1c2VyIGlkZW50aXR5IHdhcyBzZXQuXFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBgVXNlIFxcYHNldF91c2VyX2lkZW50aXR5IFwidXNlcm5hbWVcIlxcYCB0byBzZXQgeW91ciBpZGVudGl0eS5gXG4gICAgICAgICAgICAgICksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgdXNlciBmb3IgYXR0cmlidXRpb24gcHVycG9zZXNcbiAgICogUmV0dXJucyB1c2VybmFtZSBpZiBzZXQsIG90aGVyd2lzZSBQZXJzb25hTWFuYWdlcidzIGFub255bW91cyBJRFxuICAgKi9cbiAgcHVibGljIGdldEN1cnJlbnRVc2VyRm9yQXR0cmlidXRpb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wZXJzb25hTWFuYWdlci5nZXRDdXJyZW50VXNlckZvckF0dHJpYnV0aW9uKCk7XG4gIH1cbn1cbiJdfQ==