@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.
117 lines • 14.7 kB
JavaScript
/**
* Permission Guard
*
* Layer 3 (actual security enforcement) in the defense-in-depth model:
* - Layer 1: MCP tool annotations (UX hints to clients)
* - Layer 2: CRUD endpoint naming (signals intent)
* - Layer 3: This guard (actual enforcement)
*
* Validates that operations are called via the correct CRUD endpoint
* based on their permission requirements.
*/
import { getRoute } from './OperationRouter.js';
import { SecurityMonitor } from '../../security/securityMonitor.js';
export class PermissionGuard {
/**
* Permission flags for each CRUDE endpoint.
* These define the security characteristics of each endpoint.
*/
static ENDPOINT_PERMISSIONS = {
CREATE: { readOnly: false, destructive: false },
READ: { readOnly: true, destructive: false },
UPDATE: { readOnly: false, destructive: true },
DELETE: { readOnly: false, destructive: true },
EXECUTE: { readOnly: false, destructive: true }, // Potentially destructive - agents can perform any action
};
/**
* Validates that an operation is being called via the correct endpoint.
* Throws an error if the operation doesn't exist or is called via wrong endpoint.
*
* @param operation - The operation being called (e.g., 'create_element')
* @param calledEndpoint - The endpoint it was called through (e.g., 'CREATE')
* @throws Error if operation unknown or endpoint mismatch
*
* @example
* ```typescript
* // Valid call - operation matches endpoint
* PermissionGuard.validate('create_element', 'CREATE'); // OK
*
* // Invalid call - operation called via wrong endpoint
* PermissionGuard.validate('create_element', 'READ'); // Throws: Security violation
*
* // Unknown operation
* PermissionGuard.validate('unknown_op', 'READ'); // Throws: Unknown operation
* ```
*/
static validate(operation, calledEndpoint) {
const route = getRoute(operation);
if (!route) {
SecurityMonitor.logSecurityEvent({
type: 'UPDATE_SECURITY_VIOLATION',
severity: 'MEDIUM',
source: 'PermissionGuard.validate',
details: `Unknown operation: "${operation}"`,
additionalData: { operation, calledEndpoint }
});
throw new Error(`Unknown operation: "${operation}". See tool descriptions for available operations on each endpoint.`);
}
if (route.endpoint !== calledEndpoint) {
// Log security violation attempt
SecurityMonitor.logSecurityEvent({
type: 'UPDATE_SECURITY_VIOLATION',
severity: 'HIGH',
source: 'PermissionGuard.validate',
details: `Security violation: Operation "${operation}" called via wrong endpoint`,
additionalData: {
operation,
expectedEndpoint: route.endpoint,
actualEndpoint: calledEndpoint,
permissionReason: this.getPermissionReason(route.endpoint)
}
});
throw new Error(`Security violation: Operation "${operation}" must be called via mcp_aql_${route.endpoint.toLowerCase()} endpoint, ` +
`not mcp_aql_${calledEndpoint.toLowerCase()}. ` +
`This operation is classified as ${route.endpoint} due to its ${this.getPermissionReason(route.endpoint)}.`);
}
}
/**
* Gets the permission flags for an endpoint.
*
* @param endpoint - The CRUD endpoint to get permissions for
* @returns The permission flags for the endpoint
*
* @example
* ```typescript
* const perms = PermissionGuard.getPermissions('READ');
* // { readOnly: true, destructive: false }
*
* const deletePerms = PermissionGuard.getPermissions('DELETE');
* // { readOnly: false, destructive: true }
* ```
*/
static getPermissions(endpoint) {
return this.ENDPOINT_PERMISSIONS[endpoint];
}
/**
* Returns a human-readable reason for the permission classification.
* Uses exhaustive switch to ensure all endpoints are handled at compile time.
*
* @param endpoint - The CRUD endpoint to get the reason for
* @returns A description of why the endpoint has its permission classification
*/
static getPermissionReason(endpoint) {
switch (endpoint) {
case 'CREATE': return 'additive, non-destructive nature';
case 'READ': return 'read-only, safe nature';
case 'UPDATE': return 'data modification capabilities';
case 'DELETE': return 'destructive potential';
case 'EXECUTE': return 'runtime execution lifecycle (stateful, non-idempotent)';
default: {
// Exhaustive check - TypeScript will error if a case is missing
const _exhaustive = endpoint;
return _exhaustive;
}
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVybWlzc2lvbkd1YXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2hhbmRsZXJzL21jcC1hcWwvUGVybWlzc2lvbkd1YXJkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQWdCLFFBQVEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQU9wRSxNQUFNLE9BQU8sZUFBZTtJQUMxQjs7O09BR0c7SUFDSyxNQUFNLENBQVUsb0JBQW9CLEdBQThDO1FBQ3hGLE1BQU0sRUFBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRTtRQUNoRCxJQUFJLEVBQUssRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFHLFdBQVcsRUFBRSxLQUFLLEVBQUU7UUFDaEQsTUFBTSxFQUFHLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFO1FBQy9DLE1BQU0sRUFBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRTtRQUMvQyxPQUFPLEVBQUUsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsRUFBRywwREFBMEQ7S0FDN0csQ0FBQztJQUVGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BbUJHO0lBQ0gsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFpQixFQUFFLGNBQTRCO1FBQzdELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVsQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxlQUFlLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLElBQUksRUFBRSwyQkFBMkI7Z0JBQ2pDLFFBQVEsRUFBRSxRQUFRO2dCQUNsQixNQUFNLEVBQUUsMEJBQTBCO2dCQUNsQyxPQUFPLEVBQUUsdUJBQXVCLFNBQVMsR0FBRztnQkFDNUMsY0FBYyxFQUFFLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRTthQUM5QyxDQUFDLENBQUM7WUFDSCxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixTQUFTLHFFQUFxRSxDQUFDLENBQUM7UUFDekgsQ0FBQztRQUVELElBQUksS0FBSyxDQUFDLFFBQVEsS0FBSyxjQUFjLEVBQUUsQ0FBQztZQUN0QyxpQ0FBaUM7WUFDakMsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsMkJBQTJCO2dCQUNqQyxRQUFRLEVBQUUsTUFBTTtnQkFDaEIsTUFBTSxFQUFFLDBCQUEwQjtnQkFDbEMsT0FBTyxFQUFFLGtDQUFrQyxTQUFTLDZCQUE2QjtnQkFDakYsY0FBYyxFQUFFO29CQUNkLFNBQVM7b0JBQ1QsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLFFBQVE7b0JBQ2hDLGNBQWMsRUFBRSxjQUFjO29CQUM5QixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQztpQkFDM0Q7YUFDRixDQUFDLENBQUM7WUFDSCxNQUFNLElBQUksS0FBSyxDQUNiLGtDQUFrQyxTQUFTLGdDQUFnQyxLQUFLLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxhQUFhO2dCQUNwSCxlQUFlLGNBQWMsQ0FBQyxXQUFXLEVBQUUsSUFBSTtnQkFDL0MsbUNBQW1DLEtBQUssQ0FBQyxRQUFRLGVBQWUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUM1RyxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBc0I7UUFDMUMsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFzQjtRQUN2RCxRQUFRLFFBQVEsRUFBRSxDQUFDO1lBQ2pCLEtBQUssUUFBUSxDQUFDLENBQUMsT0FBTyxrQ0FBa0MsQ0FBQztZQUN6RCxLQUFLLE1BQU0sQ0FBQyxDQUFDLE9BQU8sd0JBQXdCLENBQUM7WUFDN0MsS0FBSyxRQUFRLENBQUMsQ0FBQyxPQUFPLGdDQUFnQyxDQUFDO1lBQ3ZELEtBQUssUUFBUSxDQUFDLENBQUMsT0FBTyx1QkFBdUIsQ0FBQztZQUM5QyxLQUFLLFNBQVMsQ0FBQyxDQUFDLE9BQU8sd0RBQXdELENBQUM7WUFDaEYsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDUixnRUFBZ0U7Z0JBQ2hFLE1BQU0sV0FBVyxHQUFVLFFBQVEsQ0FBQztnQkFDcEMsT0FBTyxXQUFXLENBQUM7WUFDckIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQZXJtaXNzaW9uIEd1YXJkXG4gKlxuICogTGF5ZXIgMyAoYWN0dWFsIHNlY3VyaXR5IGVuZm9yY2VtZW50KSBpbiB0aGUgZGVmZW5zZS1pbi1kZXB0aCBtb2RlbDpcbiAqIC0gTGF5ZXIgMTogTUNQIHRvb2wgYW5ub3RhdGlvbnMgKFVYIGhpbnRzIHRvIGNsaWVudHMpXG4gKiAtIExheWVyIDI6IENSVUQgZW5kcG9pbnQgbmFtaW5nIChzaWduYWxzIGludGVudClcbiAqIC0gTGF5ZXIgMzogVGhpcyBndWFyZCAoYWN0dWFsIGVuZm9yY2VtZW50KVxuICpcbiAqIFZhbGlkYXRlcyB0aGF0IG9wZXJhdGlvbnMgYXJlIGNhbGxlZCB2aWEgdGhlIGNvcnJlY3QgQ1JVRCBlbmRwb2ludFxuICogYmFzZWQgb24gdGhlaXIgcGVybWlzc2lvbiByZXF1aXJlbWVudHMuXG4gKi9cblxuaW1wb3J0IHsgQ1JVREVuZHBvaW50LCBnZXRSb3V0ZSB9IGZyb20gJy4vT3BlcmF0aW9uUm91dGVyLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW5kcG9pbnRQZXJtaXNzaW9ucyB7XG4gIHJlYWRPbmx5OiBib29sZWFuO1xuICBkZXN0cnVjdGl2ZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIFBlcm1pc3Npb25HdWFyZCB7XG4gIC8qKlxuICAgKiBQZXJtaXNzaW9uIGZsYWdzIGZvciBlYWNoIENSVURFIGVuZHBvaW50LlxuICAgKiBUaGVzZSBkZWZpbmUgdGhlIHNlY3VyaXR5IGNoYXJhY3RlcmlzdGljcyBvZiBlYWNoIGVuZHBvaW50LlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgRU5EUE9JTlRfUEVSTUlTU0lPTlM6IFJlY29yZDxDUlVERW5kcG9pbnQsIEVuZHBvaW50UGVybWlzc2lvbnM+ID0ge1xuICAgIENSRUFURTogIHsgcmVhZE9ubHk6IGZhbHNlLCBkZXN0cnVjdGl2ZTogZmFsc2UgfSxcbiAgICBSRUFEOiAgICB7IHJlYWRPbmx5OiB0cnVlLCAgZGVzdHJ1Y3RpdmU6IGZhbHNlIH0sXG4gICAgVVBEQVRFOiAgeyByZWFkT25seTogZmFsc2UsIGRlc3RydWN0aXZlOiB0cnVlIH0sXG4gICAgREVMRVRFOiAgeyByZWFkT25seTogZmFsc2UsIGRlc3RydWN0aXZlOiB0cnVlIH0sXG4gICAgRVhFQ1VURTogeyByZWFkT25seTogZmFsc2UsIGRlc3RydWN0aXZlOiB0cnVlIH0sICAvLyBQb3RlbnRpYWxseSBkZXN0cnVjdGl2ZSAtIGFnZW50cyBjYW4gcGVyZm9ybSBhbnkgYWN0aW9uXG4gIH07XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGF0IGFuIG9wZXJhdGlvbiBpcyBiZWluZyBjYWxsZWQgdmlhIHRoZSBjb3JyZWN0IGVuZHBvaW50LlxuICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG9wZXJhdGlvbiBkb2Vzbid0IGV4aXN0IG9yIGlzIGNhbGxlZCB2aWEgd3JvbmcgZW5kcG9pbnQuXG4gICAqXG4gICAqIEBwYXJhbSBvcGVyYXRpb24gLSBUaGUgb3BlcmF0aW9uIGJlaW5nIGNhbGxlZCAoZS5nLiwgJ2NyZWF0ZV9lbGVtZW50JylcbiAgICogQHBhcmFtIGNhbGxlZEVuZHBvaW50IC0gVGhlIGVuZHBvaW50IGl0IHdhcyBjYWxsZWQgdGhyb3VnaCAoZS5nLiwgJ0NSRUFURScpXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgb3BlcmF0aW9uIHVua25vd24gb3IgZW5kcG9pbnQgbWlzbWF0Y2hcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBWYWxpZCBjYWxsIC0gb3BlcmF0aW9uIG1hdGNoZXMgZW5kcG9pbnRcbiAgICogUGVybWlzc2lvbkd1YXJkLnZhbGlkYXRlKCdjcmVhdGVfZWxlbWVudCcsICdDUkVBVEUnKTsgLy8gT0tcbiAgICpcbiAgICogLy8gSW52YWxpZCBjYWxsIC0gb3BlcmF0aW9uIGNhbGxlZCB2aWEgd3JvbmcgZW5kcG9pbnRcbiAgICogUGVybWlzc2lvbkd1YXJkLnZhbGlkYXRlKCdjcmVhdGVfZWxlbWVudCcsICdSRUFEJyk7IC8vIFRocm93czogU2VjdXJpdHkgdmlvbGF0aW9uXG4gICAqXG4gICAqIC8vIFVua25vd24gb3BlcmF0aW9uXG4gICAqIFBlcm1pc3Npb25HdWFyZC52YWxpZGF0ZSgndW5rbm93bl9vcCcsICdSRUFEJyk7IC8vIFRocm93czogVW5rbm93biBvcGVyYXRpb25cbiAgICogYGBgXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGUob3BlcmF0aW9uOiBzdHJpbmcsIGNhbGxlZEVuZHBvaW50OiBDUlVERW5kcG9pbnQpOiB2b2lkIHtcbiAgICBjb25zdCByb3V0ZSA9IGdldFJvdXRlKG9wZXJhdGlvbik7XG5cbiAgICBpZiAoIXJvdXRlKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdVUERBVEVfU0VDVVJJVFlfVklPTEFUSU9OJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICBzb3VyY2U6ICdQZXJtaXNzaW9uR3VhcmQudmFsaWRhdGUnLFxuICAgICAgICBkZXRhaWxzOiBgVW5rbm93biBvcGVyYXRpb246IFwiJHtvcGVyYXRpb259XCJgLFxuICAgICAgICBhZGRpdGlvbmFsRGF0YTogeyBvcGVyYXRpb24sIGNhbGxlZEVuZHBvaW50IH1cbiAgICAgIH0pO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9wZXJhdGlvbjogXCIke29wZXJhdGlvbn1cIi4gU2VlIHRvb2wgZGVzY3JpcHRpb25zIGZvciBhdmFpbGFibGUgb3BlcmF0aW9ucyBvbiBlYWNoIGVuZHBvaW50LmApO1xuICAgIH1cblxuICAgIGlmIChyb3V0ZS5lbmRwb2ludCAhPT0gY2FsbGVkRW5kcG9pbnQpIHtcbiAgICAgIC8vIExvZyBzZWN1cml0eSB2aW9sYXRpb24gYXR0ZW1wdFxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnVVBEQVRFX1NFQ1VSSVRZX1ZJT0xBVElPTicsXG4gICAgICAgIHNldmVyaXR5OiAnSElHSCcsXG4gICAgICAgIHNvdXJjZTogJ1Blcm1pc3Npb25HdWFyZC52YWxpZGF0ZScsXG4gICAgICAgIGRldGFpbHM6IGBTZWN1cml0eSB2aW9sYXRpb246IE9wZXJhdGlvbiBcIiR7b3BlcmF0aW9ufVwiIGNhbGxlZCB2aWEgd3JvbmcgZW5kcG9pbnRgLFxuICAgICAgICBhZGRpdGlvbmFsRGF0YToge1xuICAgICAgICAgIG9wZXJhdGlvbixcbiAgICAgICAgICBleHBlY3RlZEVuZHBvaW50OiByb3V0ZS5lbmRwb2ludCxcbiAgICAgICAgICBhY3R1YWxFbmRwb2ludDogY2FsbGVkRW5kcG9pbnQsXG4gICAgICAgICAgcGVybWlzc2lvblJlYXNvbjogdGhpcy5nZXRQZXJtaXNzaW9uUmVhc29uKHJvdXRlLmVuZHBvaW50KVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFNlY3VyaXR5IHZpb2xhdGlvbjogT3BlcmF0aW9uIFwiJHtvcGVyYXRpb259XCIgbXVzdCBiZSBjYWxsZWQgdmlhIG1jcF9hcWxfJHtyb3V0ZS5lbmRwb2ludC50b0xvd2VyQ2FzZSgpfSBlbmRwb2ludCwgYCArXG4gICAgICAgIGBub3QgbWNwX2FxbF8ke2NhbGxlZEVuZHBvaW50LnRvTG93ZXJDYXNlKCl9LiBgICtcbiAgICAgICAgYFRoaXMgb3BlcmF0aW9uIGlzIGNsYXNzaWZpZWQgYXMgJHtyb3V0ZS5lbmRwb2ludH0gZHVlIHRvIGl0cyAke3RoaXMuZ2V0UGVybWlzc2lvblJlYXNvbihyb3V0ZS5lbmRwb2ludCl9LmBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIHBlcm1pc3Npb24gZmxhZ3MgZm9yIGFuIGVuZHBvaW50LlxuICAgKlxuICAgKiBAcGFyYW0gZW5kcG9pbnQgLSBUaGUgQ1JVRCBlbmRwb2ludCB0byBnZXQgcGVybWlzc2lvbnMgZm9yXG4gICAqIEByZXR1cm5zIFRoZSBwZXJtaXNzaW9uIGZsYWdzIGZvciB0aGUgZW5kcG9pbnRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBwZXJtcyA9IFBlcm1pc3Npb25HdWFyZC5nZXRQZXJtaXNzaW9ucygnUkVBRCcpO1xuICAgKiAvLyB7IHJlYWRPbmx5OiB0cnVlLCBkZXN0cnVjdGl2ZTogZmFsc2UgfVxuICAgKlxuICAgKiBjb25zdCBkZWxldGVQZXJtcyA9IFBlcm1pc3Npb25HdWFyZC5nZXRQZXJtaXNzaW9ucygnREVMRVRFJyk7XG4gICAqIC8vIHsgcmVhZE9ubHk6IGZhbHNlLCBkZXN0cnVjdGl2ZTogdHJ1ZSB9XG4gICAqIGBgYFxuICAgKi9cbiAgc3RhdGljIGdldFBlcm1pc3Npb25zKGVuZHBvaW50OiBDUlVERW5kcG9pbnQpOiBFbmRwb2ludFBlcm1pc3Npb25zIHtcbiAgICByZXR1cm4gdGhpcy5FTkRQT0lOVF9QRVJNSVNTSU9OU1tlbmRwb2ludF07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGh1bWFuLXJlYWRhYmxlIHJlYXNvbiBmb3IgdGhlIHBlcm1pc3Npb24gY2xhc3NpZmljYXRpb24uXG4gICAqIFVzZXMgZXhoYXVzdGl2ZSBzd2l0Y2ggdG8gZW5zdXJlIGFsbCBlbmRwb2ludHMgYXJlIGhhbmRsZWQgYXQgY29tcGlsZSB0aW1lLlxuICAgKlxuICAgKiBAcGFyYW0gZW5kcG9pbnQgLSBUaGUgQ1JVRCBlbmRwb2ludCB0byBnZXQgdGhlIHJlYXNvbiBmb3JcbiAgICogQHJldHVybnMgQSBkZXNjcmlwdGlvbiBvZiB3aHkgdGhlIGVuZHBvaW50IGhhcyBpdHMgcGVybWlzc2lvbiBjbGFzc2lmaWNhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0UGVybWlzc2lvblJlYXNvbihlbmRwb2ludDogQ1JVREVuZHBvaW50KTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKGVuZHBvaW50KSB7XG4gICAgICBjYXNlICdDUkVBVEUnOiByZXR1cm4gJ2FkZGl0aXZlLCBub24tZGVzdHJ1Y3RpdmUgbmF0dXJlJztcbiAgICAgIGNhc2UgJ1JFQUQnOiByZXR1cm4gJ3JlYWQtb25seSwgc2FmZSBuYXR1cmUnO1xuICAgICAgY2FzZSAnVVBEQVRFJzogcmV0dXJuICdkYXRhIG1vZGlmaWNhdGlvbiBjYXBhYmlsaXRpZXMnO1xuICAgICAgY2FzZSAnREVMRVRFJzogcmV0dXJuICdkZXN0cnVjdGl2ZSBwb3RlbnRpYWwnO1xuICAgICAgY2FzZSAnRVhFQ1VURSc6IHJldHVybiAncnVudGltZSBleGVjdXRpb24gbGlmZWN5Y2xlIChzdGF0ZWZ1bCwgbm9uLWlkZW1wb3RlbnQpJztcbiAgICAgIGRlZmF1bHQ6IHtcbiAgICAgICAgLy8gRXhoYXVzdGl2ZSBjaGVjayAtIFR5cGVTY3JpcHQgd2lsbCBlcnJvciBpZiBhIGNhc2UgaXMgbWlzc2luZ1xuICAgICAgICBjb25zdCBfZXhoYXVzdGl2ZTogbmV2ZXIgPSBlbmRwb2ludDtcbiAgICAgICAgcmV0dXJuIF9leGhhdXN0aXZlO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19