UNPKG

mage-validator

Version:

Validation utility for MAGE user commands & topics (TypeScript)

201 lines 23.5 kB
"use strict"; function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); const classTransformer = require("class-transformer"); const classValidator = require("class-validator"); const classes_1 = require("./classes"); const errors_1 = require("./errors"); const deepIterator = require('deep-iterator').default; const functionArguments = require('function-arguments'); // Expose everything from class-validator and class-transformer __export(require("class-transformer")); __export(require("class-validator")); /** * wrap the class' static create method * * @param target * @param key * @param childrenType * @param type */ function wrapCreate(target, key, childrenType, validateFunction, mapType) { const { create } = target; target.create = async (state, index, data) => { const instance = await create.call(target, state, index, data); const map = mapType ? new mapType() : {}; if (!instance[key]) { return instance; } for (const [subkey, value] of Object.entries(instance[key])) { map[subkey] = Object.assign(new childrenType(), value); } instance[key] = map; return instance; }; const { validate } = target.prototype; target.prototype.validate = async function (errorMessage, code) { await validate.call(this, errorMessage, code); let errors = []; if (!this[key]) { return; } for (const [subkey, value] of Object.entries(this[key])) { errors = errors.concat(await classValidator.validate(value)); if (!validateFunction) { continue; } try { validateFunction(subkey, value); } catch (error) { error.message = `Validation error on ${key}.${subkey}: ${error.message}`; const validationError = new classValidator.ValidationError(); validationError.target = target; validationError.property = key; validationError.value = value; validationError.constraints = { mapOf: error.message }; errors.push(Object.assign(validationError, error)); } } if (errors.length > 0) { this.raiseValidationError(errors, errorMessage, code); } }; } /** * * @param type */ function MapOf(type, validateFunction) { return (target, key) => { if (!key) { target.isMapOf = { type, validateFunction }; } else { wrapCreate(target.constructor, key, type, validateFunction); } }; } exports.MapOf = MapOf; /** * Wrap @Type from class-transformer * * @param type The type to configure */ function Type(type) { if (type.isMapOf) { const { type: childrenType, validateFunction } = type.isMapOf; return (target, key) => wrapCreate(target.constructor, key, childrenType, validateFunction, type); } if (type.prototype) { return classTransformer.Type(/* istanbul ignore next */ () => type); } return classTransformer.Type(type); } exports.Type = Type; /** * Validate ValidatedObjects and throw an error if the data is invalid. * * @param message * @param code * @param state * @param parsedData * @param receivedData */ async function validateObject(message, code, state, parsedData, receivedData) { const errors = await classValidator.validate(parsedData); if (errors.length > 0) { throw new errors_1.ValidationError(message, code, { actorId: state.actorId, userCommand: state.description, receivedData, parsedData }, errors); } return parsedData; } /** * Validate the output of an `execute` call of an user command. * * @param value */ async function validateOutput(state, value) { const type = typeof value; if (type !== 'object') { return; } if (!Array.isArray(value)) { return validateObject('Invalid user command return value', 'server', state, value); } for (const val of value) { await validateOutput(state, val); } } /** * @Acl decorator * * Protect the user command with the given ACL and defined type validation */ function Acl(...acl) { return function (UserCommand, key) { if (key !== 'execute') { throw errors_1.crash('@validate only works for usercommand.execute functions', { method: key, userCommand: UserCommand }); } const execute = UserCommand.execute; const parameterNames = functionArguments(execute); const types = Reflect.getMetadata('design:paramtypes', UserCommand, key); if (!types) { throw errors_1.crash('Reflect.getMetadata returned null.\ Did you set experimentalDecorators and emitDecoratorMetadata to true in your tsconfig.json ?', { method: key, userCommand: UserCommand }); } // We extract the state information, since we won't need it parameterNames.shift(); types.shift(); // We attach additional information to the UserCommand class UserCommand.acl = acl; UserCommand.params = parameterNames; return { value: async (state, ...args) => { // Map user command's parameters const userCommandData = {}; args.forEach((arg, pos) => { const parameterName = parameterNames[pos]; userCommandData[parameterName] = arg; }); // Cast data into a user command instance const userCommand = classTransformer.plainToClass(UserCommand, userCommandData); for (const { value } of deepIterator(userCommand)) { if (value instanceof classes_1.ValidatedTopic) { value.setState(state); const index = value.index || {}; await value.setIndex(index); delete value.index; } } // Validate all parameters at once await validateObject('Invalid user command input', 'invalidInput', state, userCommand, userCommandData); // Map casted parameters into an array of arguments const castedArgs = args.map((_arg, pos) => { const parameterName = parameterNames[pos]; return userCommand[parameterName]; }); // Execute the actual user command const output = await execute(state, ...castedArgs); await validateOutput(state, output); return output; } }; }; } exports.Acl = Acl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVjb3JhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kZWNvcmF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQ0Esc0RBQXFEO0FBQ3JELGtEQUFpRDtBQUVqRCx1Q0FBMEM7QUFDMUMscUNBQWlEO0FBRWpELE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxPQUFPLENBQUE7QUFDckQsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQTtBQVl2RCwrREFBK0Q7QUFDL0QsdUNBQWlDO0FBQ2pDLHFDQUErQjtBQUUvQjs7Ozs7OztHQU9HO0FBQ0gsb0JBQW9CLE1BQVcsRUFBRSxHQUFXLEVBQUUsWUFBaUIsRUFBRSxnQkFBbUMsRUFBRSxPQUFhO0lBQ2pILE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFFekIsTUFBTSxDQUFDLE1BQU0sR0FBRyxLQUFLLEVBQ25CLEtBQXVCLEVBQ3ZCLEtBQXFDLEVBQ3JDLElBQVUsRUFDVixFQUFFO1FBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzlELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1FBRXhDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDbEIsT0FBTyxRQUFRLENBQUE7U0FDaEI7UUFFRCxLQUFLLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRTtZQUMzRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVksRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFBO1NBQ3ZEO1FBRUQsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQTtRQUVuQixPQUFPLFFBQVEsQ0FBQTtJQUNqQixDQUFDLENBQUE7SUFFRCxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQTtJQUVyQyxNQUFNLENBQUMsU0FBUyxDQUFDLFFBQVEsR0FBRyxLQUFLLFdBQVcsWUFBcUIsRUFBRSxJQUFhO1FBQzlFLE1BQU0sUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzdDLElBQUksTUFBTSxHQUFVLEVBQUUsQ0FBQTtRQUV0QixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ2QsT0FBTTtTQUNQO1FBRUQsS0FBSyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUU7WUFDdkQsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxjQUFjLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7WUFFNUQsSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dCQUNyQixTQUFRO2FBQ1Q7WUFFRCxJQUFJO2dCQUNGLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQTthQUNoQztZQUFDLE9BQU8sS0FBSyxFQUFFO2dCQUNkLEtBQUssQ0FBQyxPQUFPLEdBQUcsdUJBQXVCLEdBQUcsSUFBSSxNQUFNLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFBO2dCQUV4RSxNQUFNLGVBQWUsR0FBRyxJQUFJLGNBQWMsQ0FBQyxlQUFlLEVBQUUsQ0FBQTtnQkFDNUQsZUFBZSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUE7Z0JBQy9CLGVBQWUsQ0FBQyxRQUFRLEdBQUcsR0FBRyxDQUFBO2dCQUM5QixlQUFlLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtnQkFDN0IsZUFBZSxDQUFDLFdBQVcsR0FBRztvQkFDNUIsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPO2lCQUNyQixDQUFBO2dCQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQTthQUNuRDtTQUNGO1FBRUQsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUNyQixJQUFJLENBQUMsb0JBQW9CLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxJQUFJLENBQUMsQ0FBQTtTQUN0RDtJQUNILENBQUMsQ0FBQTtBQUNILENBQUM7QUFFRDs7O0dBR0c7QUFDSCxlQUFzQixJQUFTLEVBQUUsZ0JBQW1DO0lBQ2xFLE9BQU8sQ0FBQyxNQUFXLEVBQUUsR0FBWSxFQUFFLEVBQUU7UUFDbkMsSUFBSSxDQUFDLEdBQUcsRUFBRTtZQUNSLE1BQU0sQ0FBQyxPQUFPLEdBQUcsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQTtTQUM1QzthQUFNO1lBQ0wsVUFBVSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsQ0FBQyxDQUFBO1NBQzVEO0lBQ0gsQ0FBQyxDQUFBO0FBQ0gsQ0FBQztBQVJELHNCQVFDO0FBRUQ7Ozs7R0FJRztBQUNILGNBQXFCLElBQVM7SUFDNUIsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO1FBQ2hCLE1BQU0sRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQTtRQUM3RCxPQUFPLENBQUMsTUFBVyxFQUFFLEdBQVcsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQTtLQUMvRztJQUVELElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRTtRQUNsQixPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtLQUNwRTtJQUVELE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0FBQ3BDLENBQUM7QUFYRCxvQkFXQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsS0FBSyx5QkFBeUIsT0FBZSxFQUFFLElBQVksRUFBRSxLQUFVLEVBQUUsVUFBZSxFQUFFLFlBQWtCO0lBQzFHLE1BQU0sTUFBTSxHQUFHLE1BQU0sY0FBYyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUN4RCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQ3JCLE1BQU0sSUFBSSx3QkFBZSxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUU7WUFDdkMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1lBQ3RCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztZQUM5QixZQUFZO1lBQ1osVUFBVTtTQUNYLEVBQUUsTUFBTSxDQUFDLENBQUE7S0FDWDtJQUVELE9BQU8sVUFBVSxDQUFBO0FBQ25CLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsS0FBSyx5QkFBeUIsS0FBdUIsRUFBRSxLQUFVO0lBQy9ELE1BQU0sSUFBSSxHQUFHLE9BQU8sS0FBSyxDQUFBO0lBRXpCLElBQUksSUFBSSxLQUFLLFFBQVEsRUFBRTtRQUNyQixPQUFNO0tBQ1A7SUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUN6QixPQUFPLGNBQWMsQ0FBQyxtQ0FBbUMsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFBO0tBQ25GO0lBRUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQUU7UUFDdkIsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFBO0tBQ2pDO0FBQ0gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxhQUFvQixHQUFHLEdBQWE7SUFDbEMsT0FBTyxVQUFVLFdBQWdCLEVBQUUsR0FBVztRQUM1QyxJQUFJLEdBQUcsS0FBSyxTQUFTLEVBQUU7WUFDckIsTUFBTSxjQUFLLENBQUMsd0RBQXdELEVBQUU7Z0JBQ3BFLE1BQU0sRUFBRSxHQUFHO2dCQUNYLFdBQVcsRUFBRSxXQUFXO2FBQ3pCLENBQUMsQ0FBQTtTQUNIO1FBRUQsTUFBTSxPQUFPLEdBQXNCLFdBQVcsQ0FBQyxPQUFPLENBQUE7UUFDdEQsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDakQsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFFeEUsSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNSLE1BQU0sY0FBSyxDQUFDO3FHQUNpRixFQUFFO2dCQUMzRixNQUFNLEVBQUUsR0FBRztnQkFDWCxXQUFXLEVBQUUsV0FBVzthQUMzQixDQUFDLENBQUE7U0FDTDtRQUVELDJEQUEyRDtRQUMzRCxjQUFjLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDdEIsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBRWIsNERBQTREO1FBQzVELFdBQVcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFBO1FBQ3JCLFdBQVcsQ0FBQyxNQUFNLEdBQUcsY0FBYyxDQUFBO1FBRW5DLE9BQU87WUFDTCxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQXVCLEVBQUUsR0FBRyxJQUFXLEVBQUUsRUFBRTtnQkFDdkQsZ0NBQWdDO2dCQUNoQyxNQUFNLGVBQWUsR0FBMkIsRUFBRSxDQUFBO2dCQUNsRCxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO29CQUN4QixNQUFNLGFBQWEsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUE7b0JBQ3pDLGVBQWUsQ0FBQyxhQUFhLENBQUMsR0FBRyxHQUFHLENBQUE7Z0JBQ3RDLENBQUMsQ0FBQyxDQUFBO2dCQUVGLHlDQUF5QztnQkFDekMsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxlQUFlLENBQUMsQ0FBQTtnQkFDL0UsS0FBSyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksWUFBWSxDQUFDLFdBQVcsQ0FBQyxFQUFFO29CQUNqRCxJQUFJLEtBQUssWUFBWSx3QkFBYyxFQUFFO3dCQUNuQyxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFBO3dCQUVyQixNQUFNLEtBQUssR0FBVSxLQUFNLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQTt3QkFFdkMsTUFBTSxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFBO3dCQUMzQixPQUFjLEtBQU0sQ0FBQyxLQUFLLENBQUE7cUJBQzNCO2lCQUNGO2dCQUVELGtDQUFrQztnQkFDbEMsTUFBTSxjQUFjLENBQUMsNEJBQTRCLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsZUFBZSxDQUFDLENBQUE7Z0JBRXZHLG1EQUFtRDtnQkFDbkQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsRUFBRTtvQkFDeEMsTUFBTSxhQUFhLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFBO29CQUN6QyxPQUFjLFdBQVksQ0FBQyxhQUFhLENBQUMsQ0FBQTtnQkFDM0MsQ0FBQyxDQUFDLENBQUE7Z0JBRUYsa0NBQWtDO2dCQUNsQyxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxVQUFVLENBQUMsQ0FBQTtnQkFFbEQsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFBO2dCQUVuQyxPQUFPLE1BQWEsQ0FBQTtZQUN0QixDQUFDO1NBQ0YsQ0FBQTtJQUNILENBQUMsQ0FBQTtBQUNILENBQUM7QUFyRUQsa0JBcUVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgbWFnZSBmcm9tICdtYWdlJ1xuaW1wb3J0ICogYXMgY2xhc3NUcmFuc2Zvcm1lciBmcm9tICdjbGFzcy10cmFuc2Zvcm1lcidcbmltcG9ydCAqIGFzIGNsYXNzVmFsaWRhdG9yIGZyb20gJ2NsYXNzLXZhbGlkYXRvcidcblxuaW1wb3J0IHsgVmFsaWRhdGVkVG9waWMgfSBmcm9tICcuL2NsYXNzZXMnXG5pbXBvcnQgeyBjcmFzaCwgVmFsaWRhdGlvbkVycm9yIH0gZnJvbSAnLi9lcnJvcnMnXG5cbmNvbnN0IGRlZXBJdGVyYXRvciA9IHJlcXVpcmUoJ2RlZXAtaXRlcmF0b3InKS5kZWZhdWx0XG5jb25zdCBmdW5jdGlvbkFyZ3VtZW50cyA9IHJlcXVpcmUoJ2Z1bmN0aW9uLWFyZ3VtZW50cycpXG5cbi8qKlxuICogdXNlcmNvbW1hbmQuZXhlY3V0ZSBmdW5jdGlvbiBzaWduYXR1cmVcbiAqL1xudHlwZSBJRXhlY3V0ZUZ1bmN0aW9uID0gPFQ+KHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLCAuLi5hcmdzOiBhbnlbXSkgPT4gUHJvbWlzZTxUPlxuXG4vKipcbiAqIFZhbGlkYXRlIGZ1bmN0aW9uIHR5cGUgKGN1cnJlbnRseSB1c2VkIGZvciBNYXBPZilcbiAqL1xuZXhwb3J0IHR5cGUgVmFsaWRhdGVGdW5jdGlvbiA9IChrZXk6IHN0cmluZywgdmFsdWU6IGFueSkgPT4gdm9pZFxuXG4vLyBFeHBvc2UgZXZlcnl0aGluZyBmcm9tIGNsYXNzLXZhbGlkYXRvciBhbmQgY2xhc3MtdHJhbnNmb3JtZXJcbmV4cG9ydCAqIGZyb20gJ2NsYXNzLXRyYW5zZm9ybWVyJ1xuZXhwb3J0ICogZnJvbSAnY2xhc3MtdmFsaWRhdG9yJ1xuXG4vKipcbiAqIHdyYXAgdGhlIGNsYXNzJyBzdGF0aWMgY3JlYXRlIG1ldGhvZFxuICpcbiAqIEBwYXJhbSB0YXJnZXRcbiAqIEBwYXJhbSBrZXlcbiAqIEBwYXJhbSBjaGlsZHJlblR5cGVcbiAqIEBwYXJhbSB0eXBlXG4gKi9cbmZ1bmN0aW9uIHdyYXBDcmVhdGUodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBjaGlsZHJlblR5cGU6IGFueSwgdmFsaWRhdGVGdW5jdGlvbj86IFZhbGlkYXRlRnVuY3Rpb24sIG1hcFR5cGU/OiBhbnkpIHtcbiAgY29uc3QgeyBjcmVhdGUgfSA9IHRhcmdldFxuXG4gIHRhcmdldC5jcmVhdGUgPSBhc3luYyAoXG4gICAgc3RhdGU6IG1hZ2UuY29yZS5JU3RhdGUsXG4gICAgaW5kZXg6IG1hZ2UuYXJjaGl2aXN0LklBcmNoaXZpc3RJbmRleCxcbiAgICBkYXRhPzogYW55XG4gICkgPT4ge1xuICAgIGNvbnN0IGluc3RhbmNlID0gYXdhaXQgY3JlYXRlLmNhbGwodGFyZ2V0LCBzdGF0ZSwgaW5kZXgsIGRhdGEpXG4gICAgY29uc3QgbWFwID0gbWFwVHlwZSA/IG5ldyBtYXBUeXBlKCkgOiB7fVxuXG4gICAgaWYgKCFpbnN0YW5jZVtrZXldKSB7XG4gICAgICByZXR1cm4gaW5zdGFuY2VcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtzdWJrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhpbnN0YW5jZVtrZXldKSkge1xuICAgICAgbWFwW3N1YmtleV0gPSBPYmplY3QuYXNzaWduKG5ldyBjaGlsZHJlblR5cGUoKSwgdmFsdWUpXG4gICAgfVxuXG4gICAgaW5zdGFuY2Vba2V5XSA9IG1hcFxuXG4gICAgcmV0dXJuIGluc3RhbmNlXG4gIH1cblxuICBjb25zdCB7IHZhbGlkYXRlIH0gPSB0YXJnZXQucHJvdG90eXBlXG5cbiAgdGFyZ2V0LnByb3RvdHlwZS52YWxpZGF0ZSA9IGFzeW5jIGZ1bmN0aW9uIChlcnJvck1lc3NhZ2U/OiBzdHJpbmcsIGNvZGU/OiBzdHJpbmcpIHtcbiAgICBhd2FpdCB2YWxpZGF0ZS5jYWxsKHRoaXMsIGVycm9yTWVzc2FnZSwgY29kZSlcbiAgICBsZXQgZXJyb3JzOiBhbnlbXSA9IFtdXG5cbiAgICBpZiAoIXRoaXNba2V5XSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbc3Via2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModGhpc1trZXldKSkge1xuICAgICAgZXJyb3JzID0gZXJyb3JzLmNvbmNhdChhd2FpdCBjbGFzc1ZhbGlkYXRvci52YWxpZGF0ZSh2YWx1ZSkpXG5cbiAgICAgIGlmICghdmFsaWRhdGVGdW5jdGlvbikge1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICB0cnkge1xuICAgICAgICB2YWxpZGF0ZUZ1bmN0aW9uKHN1YmtleSwgdmFsdWUpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBlcnJvci5tZXNzYWdlID0gYFZhbGlkYXRpb24gZXJyb3Igb24gJHtrZXl9LiR7c3Via2V5fTogJHtlcnJvci5tZXNzYWdlfWBcblxuICAgICAgICBjb25zdCB2YWxpZGF0aW9uRXJyb3IgPSBuZXcgY2xhc3NWYWxpZGF0b3IuVmFsaWRhdGlvbkVycm9yKClcbiAgICAgICAgdmFsaWRhdGlvbkVycm9yLnRhcmdldCA9IHRhcmdldFxuICAgICAgICB2YWxpZGF0aW9uRXJyb3IucHJvcGVydHkgPSBrZXlcbiAgICAgICAgdmFsaWRhdGlvbkVycm9yLnZhbHVlID0gdmFsdWVcbiAgICAgICAgdmFsaWRhdGlvbkVycm9yLmNvbnN0cmFpbnRzID0ge1xuICAgICAgICAgIG1hcE9mOiBlcnJvci5tZXNzYWdlXG4gICAgICAgIH1cblxuICAgICAgICBlcnJvcnMucHVzaChPYmplY3QuYXNzaWduKHZhbGlkYXRpb25FcnJvciwgZXJyb3IpKVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5yYWlzZVZhbGlkYXRpb25FcnJvcihlcnJvcnMsIGVycm9yTWVzc2FnZSwgY29kZSlcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKlxuICogQHBhcmFtIHR5cGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE1hcE9mKHR5cGU6IGFueSwgdmFsaWRhdGVGdW5jdGlvbj86IFZhbGlkYXRlRnVuY3Rpb24pIHtcbiAgcmV0dXJuICh0YXJnZXQ6IGFueSwga2V5Pzogc3RyaW5nKSA9PiB7XG4gICAgaWYgKCFrZXkpIHtcbiAgICAgIHRhcmdldC5pc01hcE9mID0geyB0eXBlLCB2YWxpZGF0ZUZ1bmN0aW9uIH1cbiAgICB9IGVsc2Uge1xuICAgICAgd3JhcENyZWF0ZSh0YXJnZXQuY29uc3RydWN0b3IsIGtleSwgdHlwZSwgdmFsaWRhdGVGdW5jdGlvbilcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBXcmFwIEBUeXBlIGZyb20gY2xhc3MtdHJhbnNmb3JtZXJcbiAqXG4gKiBAcGFyYW0gdHlwZSBUaGUgdHlwZSB0byBjb25maWd1cmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFR5cGUodHlwZTogYW55KSB7XG4gIGlmICh0eXBlLmlzTWFwT2YpIHtcbiAgICBjb25zdCB7IHR5cGU6IGNoaWxkcmVuVHlwZSwgdmFsaWRhdGVGdW5jdGlvbiB9ID0gdHlwZS5pc01hcE9mXG4gICAgcmV0dXJuICh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcpID0+IHdyYXBDcmVhdGUodGFyZ2V0LmNvbnN0cnVjdG9yLCBrZXksIGNoaWxkcmVuVHlwZSwgdmFsaWRhdGVGdW5jdGlvbiwgdHlwZSlcbiAgfVxuXG4gIGlmICh0eXBlLnByb3RvdHlwZSkge1xuICAgIHJldHVybiBjbGFzc1RyYW5zZm9ybWVyLlR5cGUoLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi8gKCkgPT4gdHlwZSlcbiAgfVxuXG4gIHJldHVybiBjbGFzc1RyYW5zZm9ybWVyLlR5cGUodHlwZSlcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBWYWxpZGF0ZWRPYmplY3RzIGFuZCB0aHJvdyBhbiBlcnJvciBpZiB0aGUgZGF0YSBpcyBpbnZhbGlkLlxuICpcbiAqIEBwYXJhbSBtZXNzYWdlXG4gKiBAcGFyYW0gY29kZVxuICogQHBhcmFtIHN0YXRlXG4gKiBAcGFyYW0gcGFyc2VkRGF0YVxuICogQHBhcmFtIHJlY2VpdmVkRGF0YVxuICovXG5hc3luYyBmdW5jdGlvbiB2YWxpZGF0ZU9iamVjdChtZXNzYWdlOiBzdHJpbmcsIGNvZGU6IHN0cmluZywgc3RhdGU6IGFueSwgcGFyc2VkRGF0YTogYW55LCByZWNlaXZlZERhdGE/OiBhbnkpIHtcbiAgY29uc3QgZXJyb3JzID0gYXdhaXQgY2xhc3NWYWxpZGF0b3IudmFsaWRhdGUocGFyc2VkRGF0YSlcbiAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihtZXNzYWdlLCBjb2RlLCB7XG4gICAgICBhY3RvcklkOiBzdGF0ZS5hY3RvcklkLFxuICAgICAgdXNlckNvbW1hbmQ6IHN0YXRlLmRlc2NyaXB0aW9uLFxuICAgICAgcmVjZWl2ZWREYXRhLFxuICAgICAgcGFyc2VkRGF0YVxuICAgIH0sIGVycm9ycylcbiAgfVxuXG4gIHJldHVybiBwYXJzZWREYXRhXG59XG5cbi8qKlxuICogVmFsaWRhdGUgdGhlIG91dHB1dCBvZiBhbiBgZXhlY3V0ZWAgY2FsbCBvZiBhbiB1c2VyIGNvbW1hbmQuXG4gKlxuICogQHBhcmFtIHZhbHVlXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHZhbGlkYXRlT3V0cHV0KHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLCB2YWx1ZTogYW55KSB7XG4gIGNvbnN0IHR5cGUgPSB0eXBlb2YgdmFsdWVcblxuICBpZiAodHlwZSAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm5cbiAgfVxuXG4gIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICByZXR1cm4gdmFsaWRhdGVPYmplY3QoJ0ludmFsaWQgdXNlciBjb21tYW5kIHJldHVybiB2YWx1ZScsICdzZXJ2ZXInLCBzdGF0ZSwgdmFsdWUpXG4gIH1cblxuICBmb3IgKGNvbnN0IHZhbCBvZiB2YWx1ZSkge1xuICAgIGF3YWl0IHZhbGlkYXRlT3V0cHV0KHN0YXRlLCB2YWwpXG4gIH1cbn1cblxuLyoqXG4gKiBAQWNsIGRlY29yYXRvclxuICpcbiAqIFByb3RlY3QgdGhlIHVzZXIgY29tbWFuZCB3aXRoIHRoZSBnaXZlbiBBQ0wgYW5kIGRlZmluZWQgdHlwZSB2YWxpZGF0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBBY2woLi4uYWNsOiBzdHJpbmdbXSkge1xuICByZXR1cm4gZnVuY3Rpb24gKFVzZXJDb21tYW5kOiBhbnksIGtleTogc3RyaW5nKSB7XG4gICAgaWYgKGtleSAhPT0gJ2V4ZWN1dGUnKSB7XG4gICAgICB0aHJvdyBjcmFzaCgnQHZhbGlkYXRlIG9ubHkgd29ya3MgZm9yIHVzZXJjb21tYW5kLmV4ZWN1dGUgZnVuY3Rpb25zJywge1xuICAgICAgICBtZXRob2Q6IGtleSxcbiAgICAgICAgdXNlckNvbW1hbmQ6IFVzZXJDb21tYW5kXG4gICAgICB9KVxuICAgIH1cblxuICAgIGNvbnN0IGV4ZWN1dGUgPSA8SUV4ZWN1dGVGdW5jdGlvbj4gVXNlckNvbW1hbmQuZXhlY3V0ZVxuICAgIGNvbnN0IHBhcmFtZXRlck5hbWVzID0gZnVuY3Rpb25Bcmd1bWVudHMoZXhlY3V0ZSlcbiAgICBjb25zdCB0eXBlcyA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoJ2Rlc2lnbjpwYXJhbXR5cGVzJywgVXNlckNvbW1hbmQsIGtleSlcblxuICAgIGlmICghdHlwZXMpIHtcbiAgICAgICAgdGhyb3cgY3Jhc2goJ1JlZmxlY3QuZ2V0TWV0YWRhdGEgcmV0dXJuZWQgbnVsbC5cXFxuICAgICAgICBEaWQgeW91IHNldCBleHBlcmltZW50YWxEZWNvcmF0b3JzIGFuZCBlbWl0RGVjb3JhdG9yTWV0YWRhdGEgdG8gdHJ1ZSBpbiB5b3VyIHRzY29uZmlnLmpzb24gPycsIHtcbiAgICAgICAgICAgIG1ldGhvZDoga2V5LFxuICAgICAgICAgICAgdXNlckNvbW1hbmQ6IFVzZXJDb21tYW5kXG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8gV2UgZXh0cmFjdCB0aGUgc3RhdGUgaW5mb3JtYXRpb24sIHNpbmNlIHdlIHdvbid0IG5lZWQgaXRcbiAgICBwYXJhbWV0ZXJOYW1lcy5zaGlmdCgpXG4gICAgdHlwZXMuc2hpZnQoKVxuXG4gICAgLy8gV2UgYXR0YWNoIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gdG8gdGhlIFVzZXJDb21tYW5kIGNsYXNzXG4gICAgVXNlckNvbW1hbmQuYWNsID0gYWNsXG4gICAgVXNlckNvbW1hbmQucGFyYW1zID0gcGFyYW1ldGVyTmFtZXNcblxuICAgIHJldHVybiB7XG4gICAgICB2YWx1ZTogYXN5bmMgKHN0YXRlOiBtYWdlLmNvcmUuSVN0YXRlLCAuLi5hcmdzOiBhbnlbXSkgPT4ge1xuICAgICAgICAvLyBNYXAgdXNlciBjb21tYW5kJ3MgcGFyYW1ldGVyc1xuICAgICAgICBjb25zdCB1c2VyQ29tbWFuZERhdGE6IHsgW2tleTogc3RyaW5nXTogYW55IH0gPSB7fVxuICAgICAgICBhcmdzLmZvckVhY2goKGFyZywgcG9zKSA9PiB7XG4gICAgICAgICAgY29uc3QgcGFyYW1ldGVyTmFtZSA9IHBhcmFtZXRlck5hbWVzW3Bvc11cbiAgICAgICAgICB1c2VyQ29tbWFuZERhdGFbcGFyYW1ldGVyTmFtZV0gPSBhcmdcbiAgICAgICAgfSlcblxuICAgICAgICAvLyBDYXN0IGRhdGEgaW50byBhIHVzZXIgY29tbWFuZCBpbnN0YW5jZVxuICAgICAgICBjb25zdCB1c2VyQ29tbWFuZCA9IGNsYXNzVHJhbnNmb3JtZXIucGxhaW5Ub0NsYXNzKFVzZXJDb21tYW5kLCB1c2VyQ29tbWFuZERhdGEpXG4gICAgICAgIGZvciAoY29uc3QgeyB2YWx1ZSB9IG9mIGRlZXBJdGVyYXRvcih1c2VyQ29tbWFuZCkpIHtcbiAgICAgICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBWYWxpZGF0ZWRUb3BpYykge1xuICAgICAgICAgICAgdmFsdWUuc2V0U3RhdGUoc3RhdGUpXG5cbiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gKDxhbnk+IHZhbHVlKS5pbmRleCB8fCB7fVxuXG4gICAgICAgICAgICBhd2FpdCB2YWx1ZS5zZXRJbmRleChpbmRleClcbiAgICAgICAgICAgIGRlbGV0ZSAoPGFueT4gdmFsdWUpLmluZGV4XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gVmFsaWRhdGUgYWxsIHBhcmFtZXRlcnMgYXQgb25jZVxuICAgICAgICBhd2FpdCB2YWxpZGF0ZU9iamVjdCgnSW52YWxpZCB1c2VyIGNvbW1hbmQgaW5wdXQnLCAnaW52YWxpZElucHV0Jywgc3RhdGUsIHVzZXJDb21tYW5kLCB1c2VyQ29tbWFuZERhdGEpXG5cbiAgICAgICAgLy8gTWFwIGNhc3RlZCBwYXJhbWV0ZXJzIGludG8gYW4gYXJyYXkgb2YgYXJndW1lbnRzXG4gICAgICAgIGNvbnN0IGNhc3RlZEFyZ3MgPSBhcmdzLm1hcCgoX2FyZywgcG9zKSA9PiB7XG4gICAgICAgICAgY29uc3QgcGFyYW1ldGVyTmFtZSA9IHBhcmFtZXRlck5hbWVzW3Bvc11cbiAgICAgICAgICByZXR1cm4gKDxhbnk+IHVzZXJDb21tYW5kKVtwYXJhbWV0ZXJOYW1lXVxuICAgICAgICB9KVxuXG4gICAgICAgIC8vIEV4ZWN1dGUgdGhlIGFjdHVhbCB1c2VyIGNvbW1hbmRcbiAgICAgICAgY29uc3Qgb3V0cHV0ID0gYXdhaXQgZXhlY3V0ZShzdGF0ZSwgLi4uY2FzdGVkQXJncylcblxuICAgICAgICBhd2FpdCB2YWxpZGF0ZU91dHB1dChzdGF0ZSwgb3V0cHV0KVxuXG4gICAgICAgIHJldHVybiBvdXRwdXQgYXMgYW55XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=