UNPKG

sops-secretsmanager-cdk

Version:

Safely load secrets from sops into secretsmanager using the CDK

408 lines 55.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.onEvent = void 0; const client_s3_1 = require("@aws-sdk/client-s3"); const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager"); const path = require("path"); const childProcess = require("child_process"); const util_1 = require("util"); const log = (message, extra = {}) => { console.log(JSON.stringify({ message, ...extra, })); }; const logError = (error, message, extra = {}) => { const stack = error.stack; // istanbul ignore next const stackLines = stack ? stack.split(/\n/) : []; console.error(JSON.stringify({ error: { name: error.name, message: error.message, stack: stackLines, }, message, ...extra, })); }; var MappingEncoding; (function (MappingEncoding) { MappingEncoding["String"] = "string"; MappingEncoding["Json"] = "json"; })(MappingEncoding || (MappingEncoding = {})); var RequestType; (function (RequestType) { RequestType["Create"] = "Create"; RequestType["Update"] = "Update"; RequestType["Delete"] = "Delete"; })(RequestType || (RequestType = {})); const normaliseBoolean = (value) => { if (typeof value === 'boolean') { return value; } return value === 'true'; }; const determineFileType = (s3Path, fileType, wholeFile) => { if (fileType) { return fileType; } if (wholeFile) { return 'json'; } const parts = s3Path.split('.'); const lastPart = parts.pop(); if (typeof lastPart === 'undefined') { throw new Error(`String '${s3Path}' split to have zero elements. This should not happen.`); } return lastPart; }; const isMapping = (obj) => { if (!hasKey('path', obj)) { return false; } if (!isArrayOfStrings(obj.path)) { return false; } // Is optional if (!hasKey('encoding', obj)) { return true; } const encoding = obj.encoding; if (!isString(encoding)) { return false; } try { toMappingEncodingOrError(encoding); } catch (_a) { return false; } return true; }; const isMappings = (obj) => { if (typeof obj !== 'object') { return false; } if (!obj) { return false; } for (const value of Object.values(obj)) { if (!isMapping(value)) { return false; } } return true; }; const toMappingsOrError = (obj, errorMessage) => { if (isMappings(obj)) { return obj; } throw new Error(errorMessage); }; const toMappingOrNullOrError = (obj, errorMessage) => { console.log('obj', obj); if (obj === null) { return null; } if (isMapping(obj)) { return obj; } throw new Error(errorMessage); }; const toMappingEncodingOrError = (mappingEncodingAsString) => { if (typeof mappingEncodingAsString === 'undefined') { return undefined; } switch (mappingEncodingAsString) { case 'string': return MappingEncoding.String; case 'json': return MappingEncoding.Json; } throw new Error(`Unknown mapping encoding: ${mappingEncodingAsString}`); }; const bytesToString = (byteArray) => { return new util_1.TextDecoder().decode(byteArray); }; const execPromise = async (args, input) => { return new Promise((res, rej) => { const proc = childProcess.spawn('sh', ['-c', 'cat', '-', '|', ...args], { stdio: 'pipe', shell: true }); proc.stdin.end(input); let stdout = ''; let stderr = ''; proc.stdout.on('data', (data) => { stdout += bytesToString(data); }); proc.stderr.on('data', (data) => { stderr += bytesToString(data); }); proc.on('close', (code) => { if (code > 0) { log(`Exec exited with code ${code}`, { stdout, stderr, }); rej(new Error(`Exec exited with code ${code}`)); } else { if (stderr) { log(`Exec exited cleanly, but stderr was not empty`, { stderr, }); } else { log('Exec exited cleanly'); } res(stdout); } }); }); }; const sopsDecode = async (fileContent, dataType, kmsKeyArn) => { log('Running sops command'); const sopsArgs = ['-d', '--input-type', dataType, '--output-type', 'json', ...(kmsKeyArn ? ['--kms', kmsKeyArn] : []), '/dev/stdin']; log('Sops command args', { sopsArgs }); let result; try { result = await execPromise([path.join(__dirname, 'sops'), ...sopsArgs], fileContent); } catch (_a) { result = '{}'; } log('Sops command result', { result }); const parsed = JSON.parse(result); log('Sops command result', { parsed }); return Promise.resolve(parsed); }; const isJsonData = (obj) => { return typeof obj === 'object'; }; const getJsonDataOrError = (obj, errorMessage) => { if (isJsonData(obj)) { return obj; } throw new Error(errorMessage); }; const resolveMappingPath = (data, path, encoding) => { if (typeof data !== 'object') { return undefined; } if (path.length > 1) { const [head, ...rest] = path; return resolveMappingPath(getJsonDataOrError(data[head], `Invalid json data when resolving mapping at: ${head}`), rest, encoding); } const value = data[path[0]]; if (typeof value === 'undefined') { return undefined; } switch (encoding) { case MappingEncoding.String: if (typeof value === 'object') { return undefined; } return String(value); case MappingEncoding.Json: return JSON.stringify(value); } throw new Error(`Unknown encoding ${encoding}`); }; const resolveMappings = (data, mappings) => { const mapped = {}; Object.entries(mappings).forEach((keyAndMapping) => { const [key, mapping] = keyAndMapping; const value = resolveMappingPath(getJsonDataOrError(data, 'Invalid json data'), mapping.path, toMappingEncodingOrError(mapping.encoding) || MappingEncoding.String); if (typeof value !== 'undefined') { mapped[key] = value; } }); return mapped; }; const setSecretString = async (secretString, secretArn) => { const secretsManager = new client_secrets_manager_1.SecretsManager({}); await secretsManager.putSecretValue({ SecretId: secretArn, SecretString: secretString, }); }; const handleCreate = async (event) => { const kmsKeyArn = event.ResourceProperties.KMSKeyArn; const s3BucketName = event.ResourceProperties.S3Bucket; const s3Path = event.ResourceProperties.S3Path; const mappings = toMappingsOrError(JSON.parse(event.ResourceProperties.Mappings), 'Unable to parse mappings to a valid shape'); const singleValueMapping = toMappingOrNullOrError(JSON.parse(event.ResourceProperties.SingleValueMapping), 'Unable to parse singleValueMapping to a valid shape'); const wholeFile = normaliseBoolean(event.ResourceProperties.WholeFile); const secretArn = event.ResourceProperties.SecretArn; // const sourceHash = event.ResourceProperties.SourceHash; const fileType = event.ResourceProperties.FileType; const s3 = new client_s3_1.S3({}); const getObjectParams = { Bucket: s3BucketName, Key: s3Path, }; log('Getting object from S3', { params: getObjectParams }); const obj = await s3.getObject(getObjectParams); const body = obj.Body; console.error(obj); if (typeof body === 'undefined') { throw new Error('Body of object from s3 is empty'); } log('Reading file'); const fileBody = await body.transformToString('utf-8'); log('Determining file type', { s3Path, fileType, wholeFile }); const fileTypeToUse = determineFileType(s3Path, fileType, wholeFile); log('Decoding with sops', { fileBody, fileTypeToUse, kmsKeyArn, }); const data = await sopsDecode(fileBody, fileTypeToUse, kmsKeyArn); log('Successfully decoded secret data with sops'); if (wholeFile) { log('Writing decoded data to secretsmanager as whole file', { secretArn }); const wholeFileData = data.data || ''; await setSecretString(wholeFileData, secretArn); } else if (singleValueMapping) { log('Mapping values from decoded data', { singleValueMapping }); const mappedValue = resolveMappings(data, { '': singleValueMapping })['']; await setSecretString(mappedValue, secretArn); } else { log('Mapping values from decoded data', { mappings }); const mappedValues = resolveMappings(data, mappings); log('Writing decoded data to secretsmanager as JSON file', { secretArn }); await setSecretString(JSON.stringify(mappedValues), secretArn); } log('Wrote data to secretsmanager'); return Promise.resolve({ PhysicalResourceId: `secretdata_${secretArn}`, Data: {}, }); }; const handleUpdate = async (event) => { const physicalResourceId = event.PhysicalResourceId; const response = await handleCreate(event); return Promise.resolve({ ...response, PhysicalResourceId: physicalResourceId, }); }; const handleDelete = async (event) => { return Promise.resolve({ PhysicalResourceId: event.PhysicalResourceId, Data: {}, }); }; const hasKey = (key, obj) => { return typeof obj === 'object' && !!obj && key in obj; }; const getTypedKeyOrError = (key, obj, errorMessageRoot, typeName, typeCheck) => { if (!hasKey(key, obj)) { throw new Error(`${errorMessageRoot}: no ${key} set`); } const value = obj[key]; if (!typeCheck(value)) { throw new Error(`${errorMessageRoot}: ${key} is not a ${typeName}`); } return value; }; const getTypedKeyOrUndefined = (key, obj, errorMessageRoot, typeName, typeCheck) => { if (!hasKey(key, obj)) { return undefined; } const value = obj[key]; if (!typeCheck(value)) { return undefined; } return value; }; const getUntypedKeyOrError = (key, obj, errorMessageRoot) => { if (!hasKey(key, obj)) { throw new Error(`${errorMessageRoot}: no ${key} set`); } return obj[key]; }; const isString = (a) => { return typeof a === 'string'; }; const isStringOrBoolean = (a) => { return typeof a === 'string' || typeof a === 'boolean'; }; const isArrayOfStrings = (obj) => { if (!Array.isArray(obj)) { return false; } for (const item of obj) { if (!isString(item)) { return false; } } return true; }; const getStringKeyOrError = (key, obj, errorMessageRoot) => { return getTypedKeyOrError(key, obj, errorMessageRoot, 'string', isString); }; const getStringOrBooleanKeyOrError = (key, obj, errorMessageRoot) => { return getTypedKeyOrError(key, obj, errorMessageRoot, '(string | boolean)', isStringOrBoolean); }; const getStringKeyOrUndefined = (key, obj, errorMessageRoot) => { return getTypedKeyOrUndefined(key, obj, errorMessageRoot, 'string', isString); }; const decodeResourceProperties = (resourceProperties) => { return { KMSKeyArn: getStringKeyOrUndefined('KMSKeyArn', resourceProperties, 'Invalid resourceProperties'), S3Bucket: getStringKeyOrError('S3Bucket', resourceProperties, 'Invalid resourceProperties'), S3Path: getStringKeyOrError('S3Path', resourceProperties, 'Invalid resourceProperties'), Mappings: getStringKeyOrError('Mappings', resourceProperties, 'Invalid resourceProperties'), SingleValueMapping: getStringKeyOrError('SingleValueMapping', resourceProperties, 'Invalid resourceProperties'), WholeFile: getStringOrBooleanKeyOrError('WholeFile', resourceProperties, 'Invalid resourceProperties'), SecretArn: getStringKeyOrError('SecretArn', resourceProperties, 'Invalid resourceProperties'), SourceHash: getStringKeyOrError('SourceHash', resourceProperties, 'Invalid resourceProperties'), FileType: getStringKeyOrUndefined('FileType', resourceProperties, 'Invalid resourceProperties'), }; }; const decodeEvent = (event) => { const requestType = getStringKeyOrError('RequestType', event, 'Invalid event'); switch (requestType) { case 'Create': return { RequestType: RequestType.Create, ResourceProperties: decodeResourceProperties(getUntypedKeyOrError('ResourceProperties', event, 'Invalid create event')), }; case 'Update': return { RequestType: RequestType.Update, PhysicalResourceId: getStringKeyOrError('PhysicalResourceId', event, 'Invalid update event'), ResourceProperties: decodeResourceProperties(getUntypedKeyOrError('ResourceProperties', event, 'Invalid update event')), }; case 'Delete': return { PhysicalResourceId: getStringKeyOrError('PhysicalResourceId', event, 'Invalid delete event'), RequestType: RequestType.Delete, }; } throw new Error(`Unknown event type: ${requestType}`); }; const handleEvent = async (inputEvent) => { log('Handling event', { event: inputEvent }); const event = decodeEvent(inputEvent); switch (event.RequestType) { case RequestType.Create: return handleCreate(event); case RequestType.Update: return handleUpdate(event); case RequestType.Delete: return handleDelete(event); } // istanbul ignore next throw new Error('Unknown event type. This should be unreachable.'); }; const onEvent = (inputEvent) => { return handleEvent(inputEvent).catch(err => { logError(err, 'Unhandled error, failing'); return Promise.reject(new Error('Failed')); }); }; exports.onEvent = onEvent; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxrREFBd0M7QUFDeEMsNEVBQWlFO0FBQ2pFLDZCQUE2QjtBQUM3Qiw4Q0FBOEM7QUFFOUMsK0JBQW1DO0FBRW5DLE1BQU0sR0FBRyxHQUFHLENBQUMsT0FBZSxFQUFFLFFBQWlDLEVBQUUsRUFBUSxFQUFFO0lBQ3ZFLE9BQU8sQ0FBQyxHQUFHLENBQ1AsSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUNYLE9BQU87UUFDUCxHQUFHLEtBQUs7S0FDWCxDQUFDLENBQ0wsQ0FBQztBQUNOLENBQUMsQ0FBQztBQUVGLE1BQU0sUUFBUSxHQUFHLENBQUMsS0FBWSxFQUFFLE9BQWUsRUFBRSxRQUFpQyxFQUFFLEVBQVEsRUFBRTtJQUMxRixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzFCLHVCQUF1QjtJQUN2QixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNsRCxPQUFPLENBQUMsS0FBSyxDQUNULElBQUksQ0FBQyxTQUFTLENBQUM7UUFDWCxLQUFLLEVBQUU7WUFDSCxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7WUFDaEIsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1lBQ3RCLEtBQUssRUFBRSxVQUFVO1NBQ3BCO1FBQ0QsT0FBTztRQUNQLEdBQUcsS0FBSztLQUNYLENBQUMsQ0FDTCxDQUFDO0FBQ04sQ0FBQyxDQUFDO0FBRUYsSUFBSyxlQUdKO0FBSEQsV0FBSyxlQUFlO0lBQ2hCLG9DQUFpQixDQUFBO0lBQ2pCLGdDQUFhLENBQUE7QUFDakIsQ0FBQyxFQUhJLGVBQWUsS0FBZixlQUFlLFFBR25CO0FBK0JELElBQUssV0FJSjtBQUpELFdBQUssV0FBVztJQUNaLGdDQUFpQixDQUFB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QUMsQ0FBQyxDQUFDO0lBQy9DLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDO0FBTFcsUUFBQSxPQUFPLFdBS2xCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUzMgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtczMnO1xuaW1wb3J0IHsgU2VjcmV0c01hbmFnZXIgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtc2VjcmV0cy1tYW5hZ2VyJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjaGlsZFByb2Nlc3MgZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5pbXBvcnQgeyBXcml0YWJsZSB9IGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgeyBUZXh0RGVjb2RlciB9IGZyb20gJ3V0aWwnO1xuXG5jb25zdCBsb2cgPSAobWVzc2FnZTogc3RyaW5nLCBleHRyYTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fSk6IHZvaWQgPT4ge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBtZXNzYWdlLFxuICAgICAgICAgICAgLi4uZXh0cmEsXG4gICAgICAgIH0pLFxuICAgICk7XG59O1xuXG5jb25zdCBsb2dFcnJvciA9IChlcnJvcjogRXJyb3IsIG1lc3NhZ2U6IHN0cmluZywgZXh0cmE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge30pOiB2b2lkID0+IHtcbiAgICBjb25zdCBzdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0XG4gICAgY29uc3Qgc3RhY2tMaW5lcyA9IHN0YWNrID8gc3RhY2suc3BsaXQoL1xcbi8pIDogW107XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBlcnJvci5uYW1lLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgc3RhY2s6IHN0YWNrTGluZXMsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICAgIC4uLmV4dHJhLFxuICAgICAgICB9KSxcbiAgICApO1xufTtcblxuZW51bSBNYXBwaW5nRW5jb2Rpbmcge1xuICAgIFN0cmluZyA9ICdzdHJpbmcnLFxuICAgIEpzb24gPSAnanNvbicsXG59XG5cbmludGVyZmFjZSBNYXBwaW5nIHtcbiAgICBwYXRoOiBBcnJheTxzdHJpbmc+O1xuICAgIGVuY29kaW5nPzogTWFwcGluZ0VuY29kaW5nO1xufVxuXG5pbnRlcmZhY2UgTWFwcGluZ3Mge1xuICAgIFtuYW1lOiBzdHJpbmddOiBNYXBwaW5nO1xufVxuXG50eXBlIE1hcHBlZFZhbHVlcyA9IHtcbiAgICBbbmFtZTogc3RyaW5nXTogc3RyaW5nO1xufTtcblxuaW50ZXJmYWNlIFNvcHNXaG9sZUZpbGVEYXRhIHtcbiAgICBkYXRhOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBSZXNvdXJjZVByb3BlcnRpZXMge1xuICAgIEtNU0tleUFybjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIFMzQnVja2V0OiBzdHJpbmc7XG4gICAgUzNQYXRoOiBzdHJpbmc7XG4gICAgTWFwcGluZ3M6IHN0cmluZzsgLy8ganNvbiBlbmNvZGVkIE1hcHBpbmdzO1xuICAgIFNpbmdsZVZhbHVlTWFwcGluZzogc3RyaW5nOyAvLyBqc29uIGVuY29kZWQgTWFwcGluZztcbiAgICBXaG9sZUZpbGU6IGJvb2xlYW4gfCBzdHJpbmc7XG4gICAgU2VjcmV0QXJuOiBzdHJpbmc7XG4gICAgU291cmNlSGFzaDogc3RyaW5nO1xuICAgIEZpbGVUeXBlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG59XG5cbmVudW0gUmVxdWVzdFR5cGUge1xuICAgIENyZWF0ZSA9ICdDcmVhdGUnLFxuICAgIFVwZGF0ZSA9ICdVcGRhdGUnLFxuICAgIERlbGV0ZSA9ICdEZWxldGUnLFxufVxuXG5pbnRlcmZhY2UgQ3JlYXRlT3JVcGRhdGVFdmVudCB7XG4gICAgUmVzb3VyY2VQcm9wZXJ0aWVzOiBSZXNvdXJjZVByb3BlcnRpZXM7XG4gICAgUmVxdWVzdFR5cGU6IFJlcXVlc3RUeXBlLkNyZWF0ZSB8IFJlcXVlc3RUeXBlLlVwZGF0ZTtcbn1cblxuaW50ZXJmYWNlIENyZWF0ZUV2ZW50IGV4dGVuZHMgQ3JlYXRlT3JVcGRhdGVFdmVudCB7XG4gICAgUmVxdWVzdFR5cGU6IFJlcXVlc3RUeXBlLkNyZWF0ZTtcbn1cblxuaW50ZXJmYWNlIFVwZGF0ZUV2ZW50IGV4dGVuZHMgQ3JlYXRlT3JVcGRhdGVFdmVudCB7XG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBzdHJpbmc7XG4gICAgUmVxdWVzdFR5cGU6IFJlcXVlc3RUeXBlLlVwZGF0ZTtcbn1cblxuaW50ZXJmYWNlIERlbGV0ZUV2ZW50IHtcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgICBSZXF1ZXN0VHlwZTogUmVxdWVzdFR5cGUuRGVsZXRlO1xufVxuXG4vLyBpbnRlcmZhY2UgUmVzcG9uc2VEYXRhIHt9XG5cbmludGVyZmFjZSBSZXNwb25zZSB7XG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBzdHJpbmc7XG4gICAgRGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbnR5cGUgRXZlbnQgPSBDcmVhdGVFdmVudCB8IFVwZGF0ZUV2ZW50IHwgRGVsZXRlRXZlbnQ7XG5cbmNvbnN0IG5vcm1hbGlzZUJvb2xlYW4gPSAodmFsdWU6IGJvb2xlYW4gfCBzdHJpbmcpOiBib29sZWFuID0+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWUgPT09ICd0cnVlJztcbn07XG5cbmNvbnN0IGRldGVybWluZUZpbGVUeXBlID0gKHMzUGF0aDogc3RyaW5nLCBmaWxlVHlwZTogc3RyaW5nIHwgdW5kZWZpbmVkLCB3aG9sZUZpbGU6IGJvb2xlYW4pOiBzdHJpbmcgPT4ge1xuICAgIGlmIChmaWxlVHlwZSkge1xuICAgICAgICByZXR1cm4gZmlsZVR5cGU7XG4gICAgfVxuXG4gICAgaWYgKHdob2xlRmlsZSkge1xuICAgICAgICByZXR1cm4gJ2pzb24nO1xuICAgIH1cblxuICAgIGNvbnN0IHBhcnRzID0gczNQYXRoLnNwbGl0KCcuJyk7XG4gICAgY29uc3QgbGFzdFBhcnQgPSBwYXJ0cy5wb3AoKTtcbiAgICBpZiAodHlwZW9mIGxhc3RQYXJ0ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFN0cmluZyAnJHtzM1BhdGh9JyBzcGxpdCB0byBoYXZlIHplcm8gZWxlbWVudHMuIFRoaXMgc2hvdWxkIG5vdCBoYXBwZW4uYCk7XG4gICAgfVxuICAgIHJldHVybiBsYXN0UGFydDtcbn07XG5cbmNvbnN0IGlzTWFwcGluZyA9IChvYmo6IHVua25vd24pOiBvYmogaXMgTWFwcGluZyA9PiB7XG4gICAgaWYgKCFoYXNLZXkoJ3BhdGgnLCBvYmopKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCFpc0FycmF5T2ZTdHJpbmdzKG9iai5wYXRoKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gSXMgb3B0aW9uYWxcbiAgICBpZiAoIWhhc0tleSgnZW5jb2RpbmcnLCBvYmopKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGVuY29kaW5nID0gb2JqLmVuY29kaW5nO1xuICAgIGlmICghaXNTdHJpbmcoZW5jb2RpbmcpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgdG9NYXBwaW5nRW5jb2RpbmdPckVycm9yKGVuY29kaW5nKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbmNvbnN0IGlzTWFwcGluZ3MgPSAob2JqOiB1bmtub3duKTogb2JqIGlzIE1hcHBpbmdzID0+IHtcbiAgICBpZiAodHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIW9iaikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGZvciAoY29uc3QgdmFsdWUgb2YgT2JqZWN0LnZhbHVlcyhvYmopKSB7XG4gICAgICAgIGlmICghaXNNYXBwaW5nKHZhbHVlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuXG5jb25zdCB0b01hcHBpbmdzT3JFcnJvciA9IChvYmo6IHVua25vd24sIGVycm9yTWVzc2FnZTogc3RyaW5nKTogTWFwcGluZ3MgPT4ge1xuICAgIGlmIChpc01hcHBpbmdzKG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7XG59O1xuXG5jb25zdCB0b01hcHBpbmdPck51bGxPckVycm9yID0gKG9iajogdW5rbm93biwgZXJyb3JNZXNzYWdlOiBzdHJpbmcpOiBNYXBwaW5nIHwgbnVsbCA9PiB7XG4gICAgY29uc29sZS5sb2coJ29iaicsIG9iaik7XG5cbiAgICBpZiAob2JqID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBpZiAoaXNNYXBwaW5nKG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7XG59O1xuXG5jb25zdCB0b01hcHBpbmdFbmNvZGluZ09yRXJyb3IgPSAobWFwcGluZ0VuY29kaW5nQXNTdHJpbmc6IHN0cmluZyB8IHVuZGVmaW5lZCk6IE1hcHBpbmdFbmNvZGluZyB8IHVuZGVmaW5lZCA9PiB7XG4gICAgaWYgKHR5cGVvZiBtYXBwaW5nRW5jb2RpbmdBc1N0cmluZyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc3dpdGNoIChtYXBwaW5nRW5jb2RpbmdBc1N0cmluZykge1xuICAgICAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgICAgICAgcmV0dXJuIE1hcHBpbmdFbmNvZGluZy5TdHJpbmc7XG4gICAgICAgIGNhc2UgJ2pzb24nOlxuICAgICAgICAgICAgcmV0dXJuIE1hcHBpbmdFbmNvZGluZy5Kc29uO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gbWFwcGluZyBlbmNvZGluZzogJHttYXBwaW5nRW5jb2RpbmdBc1N0cmluZ31gKTtcbn07XG5cbmNvbnN0IGJ5dGVzVG9TdHJpbmcgPSAoYnl0ZUFycmF5OiBVaW50OEFycmF5KTogc3RyaW5nID0+IHtcbiAgICByZXR1cm4gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGJ5dGVBcnJheSk7XG59O1xuXG5jb25zdCBleGVjUHJvbWlzZSA9IGFzeW5jIChhcmdzOiBBcnJheTxzdHJpbmc+LCBpbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlczogKHJlc3VsdDogc3RyaW5nKSA9PiB2b2lkLCByZWo6IChlcnJvcjogRXJyb3IpID0+IHZvaWQpOiB2b2lkID0+IHtcbiAgICAgICAgY29uc3QgcHJvYyA9IGNoaWxkUHJvY2Vzcy5zcGF3bignc2gnLCBbJy1jJywgJ2NhdCcsICctJywgJ3wnLCAuLi5hcmdzXSwgeyBzdGRpbzogJ3BpcGUnLCBzaGVsbDogdHJ1ZSB9KTtcbiAgICAgICAgKHByb2Muc3RkaW4gYXMgV3JpdGFibGUpLmVuZChpbnB1dCk7XG5cbiAgICAgICAgbGV0IHN0ZG91dCA9ICcnO1xuICAgICAgICBsZXQgc3RkZXJyID0gJyc7XG5cbiAgICAgICAgcHJvYy5zdGRvdXQub24oJ2RhdGEnLCAoZGF0YTogVWludDhBcnJheSkgPT4ge1xuICAgICAgICAgICAgc3Rkb3V0ICs9IGJ5dGVzVG9TdHJpbmcoZGF0YSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHByb2Muc3RkZXJyLm9uKCdkYXRhJywgKGRhdGE6IFVpbnQ4QXJyYXkpID0+IHtcbiAgICAgICAgICAgIHN0ZGVyciArPSBieXRlc1RvU3RyaW5nKGRhdGEpO1xuICAgICAgICB9KTtcblxuICAgICAgICBwcm9jLm9uKCdjbG9zZScsIChjb2RlOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgIGlmIChjb2RlID4gMCkge1xuICAgICAgICAgICAgICAgIGxvZyhgRXhlYyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX1gLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0ZG91dCxcbiAgICAgICAgICAgICAgICAgICAgc3RkZXJyLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJlaihuZXcgRXJyb3IoYEV4ZWMgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9YCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoc3RkZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZyhgRXhlYyBleGl0ZWQgY2xlYW5seSwgYnV0IHN0ZGVyciB3YXMgbm90IGVtcHR5YCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RkZXJyLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBsb2coJ0V4ZWMgZXhpdGVkIGNsZWFubHknKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVzKHN0ZG91dCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pO1xufTtcblxuY29uc3Qgc29wc0RlY29kZSA9IGFzeW5jIChmaWxlQ29udGVudDogc3RyaW5nLCBkYXRhVHlwZTogc3RyaW5nLCBrbXNLZXlBcm46IHN0cmluZyB8IHVuZGVmaW5lZCk6IFByb21pc2U8dW5rbm93bj4gPT4ge1xuICAgIGxvZygnUnVubmluZyBzb3BzIGNvbW1hbmQnKTtcbiAgICBjb25zdCBzb3BzQXJncyA9IFsnLWQnLCAnLS1pbnB1dC10eXBlJywgZGF0YVR5cGUsICctLW91dHB1dC10eXBlJywgJ2pzb24nLCAuLi4oa21zS2V5QXJuID8gWyctLWttcycsIGttc0tleUFybl0gOiBbXSksICcvZGV2L3N0ZGluJ107XG4gICAgbG9nKCdTb3BzIGNvbW1hbmQgYXJncycsIHsgc29wc0FyZ3MgfSk7XG4gICAgbGV0IHJlc3VsdDogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGV4ZWNQcm9taXNlKFtwYXRoLmpvaW4oX19kaXJuYW1lLCAnc29wcycpLCAuLi5zb3BzQXJnc10sIGZpbGVDb250ZW50KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgICAgcmVzdWx0ID0gJ3t9JztcbiAgICB9XG4gICAgbG9nKCdTb3BzIGNvbW1hbmQgcmVzdWx0JywgeyByZXN1bHQgfSk7XG4gICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShyZXN1bHQpO1xuICAgIGxvZygnU29wcyBjb21tYW5kIHJlc3VsdCcsIHsgcGFyc2VkIH0pO1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocGFyc2VkKTtcbn07XG5cbmludGVyZmFjZSBKc29uRGF0YSB7XG4gICAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuY29uc3QgaXNKc29uRGF0YSA9IChvYmo6IHVua25vd24pOiBvYmogaXMgSnNvbkRhdGEgPT4ge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnb2JqZWN0Jztcbn07XG5cbmNvbnN0IGdldEpzb25EYXRhT3JFcnJvciA9IChvYmo6IHVua25vd24sIGVycm9yTWVzc2FnZTogc3RyaW5nKTogSnNvbkRhdGEgPT4ge1xuICAgIGlmIChpc0pzb25EYXRhKG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7XG59O1xuXG5jb25zdCByZXNvbHZlTWFwcGluZ1BhdGggPSAoZGF0YTogSnNvbkRhdGEsIHBhdGg6IEFycmF5PHN0cmluZz4sIGVuY29kaW5nOiBNYXBwaW5nRW5jb2RpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQgPT4ge1xuICAgIGlmICh0eXBlb2YgZGF0YSAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBpZiAocGF0aC5sZW5ndGggPiAxKSB7XG4gICAgICAgIGNvbnN0IFtoZWFkLCAuLi5yZXN0XSA9IHBhdGg7XG4gICAgICAgIHJldHVybiByZXNvbHZlTWFwcGluZ1BhdGgoZ2V0SnNvbkRhdGFPckVycm9yKGRhdGFbaGVhZF0sIGBJbnZhbGlkIGpzb24gZGF0YSB3aGVuIHJlc29sdmluZyBtYXBwaW5nIGF0OiAke2hlYWR9YCksIHJlc3QsIGVuY29kaW5nKTtcbiAgICB9XG5cbiAgICBjb25zdCB2YWx1ZSA9IGRhdGFbcGF0aFswXV07XG5cbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgICAgY2FzZSBNYXBwaW5nRW5jb2RpbmcuU3RyaW5nOlxuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIFN0cmluZyh2YWx1ZSk7XG4gICAgICAgIGNhc2UgTWFwcGluZ0VuY29kaW5nLkpzb246XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBlbmNvZGluZyAke2VuY29kaW5nfWApO1xufTtcblxudHlwZSBLZXlBbmRNYXBwaW5nID0gW3N0cmluZywgTWFwcGluZ107XG5cbmNvbnN0IHJlc29sdmVNYXBwaW5ncyA9IChkYXRhOiB1bmtub3duLCBtYXBwaW5nczogTWFwcGluZ3MpOiBNYXBwZWRWYWx1ZXMgPT4ge1xuICAgIGNvbnN0IG1hcHBlZDogTWFwcGVkVmFsdWVzID0ge307XG4gICAgT2JqZWN0LmVudHJpZXMobWFwcGluZ3MpLmZvckVhY2goKGtleUFuZE1hcHBpbmc6IEtleUFuZE1hcHBpbmcpID0+IHtcbiAgICAgICAgY29uc3QgW2tleSwgbWFwcGluZ10gPSBrZXlBbmRNYXBwaW5nO1xuICAgICAgICBjb25zdCB2YWx1ZSA9IHJlc29sdmVNYXBwaW5nUGF0aChnZXRKc29uRGF0YU9yRXJyb3IoZGF0YSwgJ0ludmFsaWQganNvbiBkYXRhJyksIG1hcHBpbmcucGF0aCwgdG9NYXBwaW5nRW5jb2RpbmdPckVycm9yKG1hcHBpbmcuZW5jb2RpbmcpIHx8IE1hcHBpbmdFbmNvZGluZy5TdHJpbmcpO1xuICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgbWFwcGVkW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBtYXBwZWQ7XG59O1xuXG5jb25zdCBzZXRTZWNyZXRTdHJpbmcgPSBhc3luYyAoc2VjcmV0U3RyaW5nOiBzdHJpbmcsIHNlY3JldEFybjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgY29uc3Qgc2VjcmV0c01hbmFnZXIgPSBuZXcgU2VjcmV0c01hbmFnZXIoe30pO1xuICAgIGF3YWl0IHNlY3JldHNNYW5hZ2VyLnB1dFNlY3JldFZhbHVlKHtcbiAgICAgICAgU2VjcmV0SWQ6IHNlY3JldEFybixcbiAgICAgICAgU2VjcmV0U3RyaW5nOiBzZWNyZXRTdHJpbmcsXG4gICAgfSk7XG59O1xuXG5jb25zdCBoYW5kbGVDcmVhdGUgPSBhc3luYyAoZXZlbnQ6IENyZWF0ZU9yVXBkYXRlRXZlbnQpOiBQcm9taXNlPFJlc3BvbnNlPiA9PiB7XG4gICAgY29uc3Qga21zS2V5QXJuID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLktNU0tleUFybjtcbiAgICBjb25zdCBzM0J1Y2tldE5hbWUgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuUzNCdWNrZXQ7XG4gICAgY29uc3QgczNQYXRoID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLlMzUGF0aDtcbiAgICBjb25zdCBtYXBwaW5ncyA9IHRvTWFwcGluZ3NPckVycm9yKEpTT04ucGFyc2UoZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLk1hcHBpbmdzKSwgJ1VuYWJsZSB0byBwYXJzZSBtYXBwaW5ncyB0byBhIHZhbGlkIHNoYXBlJyk7XG4gICAgY29uc3Qgc2luZ2xlVmFsdWVNYXBwaW5nID0gdG9NYXBwaW5nT3JOdWxsT3JFcnJvcihKU09OLnBhcnNlKGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5TaW5nbGVWYWx1ZU1hcHBpbmcpLCAnVW5hYmxlIHRvIHBhcnNlIHNpbmdsZVZhbHVlTWFwcGluZyB0byBhIHZhbGlkIHNoYXBlJyk7XG4gICAgY29uc3Qgd2hvbGVGaWxlID0gbm9ybWFsaXNlQm9vbGVhbihldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuV2hvbGVGaWxlKTtcbiAgICBjb25zdCBzZWNyZXRBcm4gPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuU2VjcmV0QXJuO1xuICAgIC8vIGNvbnN0IHNvdXJjZUhhc2ggPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuU291cmNlSGFzaDtcbiAgICBjb25zdCBmaWxlVHlwZSA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5GaWxlVHlwZTtcblxuICAgIGNvbnN0IHMzID0gbmV3IFMzKHt9KTtcblxuICAgIGNvbnN0IGdldE9iamVjdFBhcmFtcyA9IHtcbiAgICAgICAgQnVja2V0OiBzM0J1Y2tldE5hbWUsXG4gICAgICAgIEtleTogczNQYXRoLFxuICAgIH07XG4gICAgbG9nKCdHZXR0aW5nIG9iamVjdCBmcm9tIFMzJywgeyBwYXJhbXM6IGdldE9iamVjdFBhcmFtcyB9KTtcbiAgICBjb25zdCBvYmogPSBhd2FpdCBzMy5nZXRPYmplY3QoZ2V0T2JqZWN0UGFyYW1zKTtcbiAgICBjb25zdCBib2R5ID0gb2JqLkJvZHk7XG5cbiAgICBjb25zb2xlLmVycm9yKG9iaik7XG5cbiAgICBpZiAodHlwZW9mIGJvZHkgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQm9keSBvZiBvYmplY3QgZnJvbSBzMyBpcyBlbXB0eScpO1xuICAgIH1cblxuICAgIGxvZygnUmVhZGluZyBmaWxlJyk7XG4gICAgY29uc3QgZmlsZUJvZHkgPSBhd2FpdCBib2R5LnRyYW5zZm9ybVRvU3RyaW5nKCd1dGYtOCcpO1xuICAgIGxvZygnRGV0ZXJtaW5pbmcgZmlsZSB0eXBlJywgeyBzM1BhdGgsIGZpbGVUeXBlLCB3aG9sZUZpbGUgfSk7XG4gICAgY29uc3QgZmlsZVR5cGVUb1VzZSA9IGRldGVybWluZUZpbGVUeXBlKHMzUGF0aCwgZmlsZVR5cGUsIHdob2xlRmlsZSk7XG4gICAgbG9nKCdEZWNvZGluZyB3aXRoIHNvcHMnLCB7XG4gICAgICAgIGZpbGVCb2R5LFxuICAgICAgICBmaWxlVHlwZVRvVXNlLFxuICAgICAgICBrbXNLZXlBcm4sXG4gICAgfSk7XG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHNvcHNEZWNvZGUoZmlsZUJvZHksIGZpbGVUeXBlVG9Vc2UsIGttc0tleUFybik7XG4gICAgbG9nKCdTdWNjZXNzZnVsbHkgZGVjb2RlZCBzZWNyZXQgZGF0YSB3aXRoIHNvcHMnKTtcblxuICAgIGlmICh3aG9sZUZpbGUpIHtcbiAgICAgICAgbG9nKCdXcml0aW5nIGRlY29kZWQgZGF0YSB0byBzZWNyZXRzbWFuYWdlciBhcyB3aG9sZSBmaWxlJywgeyBzZWNyZXRBcm4gfSk7XG4gICAgICAgIGNvbnN0IHdob2xlRmlsZURhdGEgPSAoZGF0YSBhcyBTb3BzV2hvbGVGaWxlRGF0YSkuZGF0YSB8fCAnJztcbiAgICAgICAgYXdhaXQgc2V0U2VjcmV0U3RyaW5nKHdob2xlRmlsZURhdGEsIHNlY3JldEFybik7XG4gICAgfSBlbHNlIGlmIChzaW5nbGVWYWx1ZU1hcHBpbmcpIHtcbiAgICAgICAgbG9nKCdNYXBwaW5nIHZhbHVlcyBmcm9tIGRlY29kZWQgZGF0YScsIHsgc2luZ2xlVmFsdWVNYXBwaW5nIH0pO1xuICAgICAgICBjb25zdCBtYXBwZWRWYWx1ZSA9IHJlc29sdmVNYXBwaW5ncyhkYXRhLCB7ICcnOiBzaW5nbGVWYWx1ZU1hcHBpbmcgfSlbJyddO1xuICAgICAgICBhd2FpdCBzZXRTZWNyZXRTdHJpbmcobWFwcGVkVmFsdWUsIHNlY3JldEFybik7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbG9nKCdNYXBwaW5nIHZhbHVlcyBmcm9tIGRlY29kZWQgZGF0YScsIHsgbWFwcGluZ3MgfSk7XG4gICAgICAgIGNvbnN0IG1hcHBlZFZhbHVlcyA9IHJlc29sdmVNYXBwaW5ncyhkYXRhLCBtYXBwaW5ncyk7XG4gICAgICAgIGxvZygnV3JpdGluZyBkZWNvZGVkIGRhdGEgdG8gc2VjcmV0c21hbmFnZXIgYXMgSlNPTiBmaWxlJywgeyBzZWNyZXRBcm4gfSk7XG4gICAgICAgIGF3YWl0IHNldFNlY3JldFN0cmluZyhKU09OLnN0cmluZ2lmeShtYXBwZWRWYWx1ZXMpLCBzZWNyZXRBcm4pO1xuICAgIH1cbiAgICBsb2coJ1dyb3RlIGRhdGEgdG8gc2VjcmV0c21hbmFnZXInKTtcblxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICBQaHlzaWNhbFJlc291cmNlSWQ6IGBzZWNyZXRkYXRhXyR7c2VjcmV0QXJufWAsXG4gICAgICAgIERhdGE6IHt9LFxuICAgIH0pO1xufTtcblxuY29uc3QgaGFuZGxlVXBkYXRlID0gYXN5bmMgKGV2ZW50OiBVcGRhdGVFdmVudCk6IFByb21pc2U8UmVzcG9uc2U+ID0+IHtcbiAgICBjb25zdCBwaHlzaWNhbFJlc291cmNlSWQgPSBldmVudC5QaHlzaWNhbFJlc291cmNlSWQ7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBoYW5kbGVDcmVhdGUoZXZlbnQpO1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAuLi5yZXNwb25zZSxcbiAgICAgICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gICAgfSk7XG59O1xuXG5jb25zdCBoYW5kbGVEZWxldGUgPSBhc3luYyAoZXZlbnQ6IERlbGV0ZUV2ZW50KTogUHJvbWlzZTxSZXNwb25zZT4gPT4ge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICBQaHlzaWNhbFJlc291cmNlSWQ6IGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCxcbiAgICAgICAgRGF0YToge30sXG4gICAgfSk7XG59O1xuXG5jb25zdCBoYXNLZXkgPSA8SyBleHRlbmRzIHN0cmluZz4oa2V5OiBLLCBvYmo6IHVua25vd24pOiBvYmogaXMgeyBbXyBpbiBLXTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfSA9PiB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT09ICdvYmplY3QnICYmICEhb2JqICYmIGtleSBpbiBvYmo7XG59O1xuXG5jb25zdCBnZXRUeXBlZEtleU9yRXJyb3IgPSA8QT4oa2V5OiBzdHJpbmcsIG9iajogdW5rbm93biwgZXJyb3JNZXNzYWdlUm9vdDogc3RyaW5nLCB0eXBlTmFtZTogc3RyaW5nLCB0eXBlQ2hlY2s6ICh2YWx1ZTogdW5rbm93bikgPT4gdmFsdWUgaXMgQSk6IEEgPT4ge1xuICAgIGlmICghaGFzS2V5KGtleSwgb2JqKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZXJyb3JNZXNzYWdlUm9vdH06IG5vICR7a2V5fSBzZXRgKTtcbiAgICB9XG4gICAgY29uc3QgdmFsdWUgPSBvYmpba2V5XTtcbiAgICBpZiAoIXR5cGVDaGVjayh2YWx1ZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2Vycm9yTWVzc2FnZVJvb3R9OiAke2tleX0gaXMgbm90IGEgJHt0eXBlTmFtZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xufTtcblxuY29uc3QgZ2V0VHlwZWRLZXlPclVuZGVmaW5lZCA9IDxBPihrZXk6IHN0cmluZywgb2JqOiB1bmtub3duLCBlcnJvck1lc3NhZ2VSb290OiBzdHJpbmcsIHR5cGVOYW1lOiBzdHJpbmcsIHR5cGVDaGVjazogKHZhbHVlOiB1bmtub3duKSA9PiB2YWx1ZSBpcyBBKTogQSB8IHVuZGVmaW5lZCA9PiB7XG4gICAgaWYgKCFoYXNLZXkoa2V5LCBvYmopKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGNvbnN0IHZhbHVlID0gb2JqW2tleV07XG4gICAgaWYgKCF0eXBlQ2hlY2sodmFsdWUpKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG5cbmNvbnN0IGdldFVudHlwZWRLZXlPckVycm9yID0gKGtleTogc3RyaW5nLCBvYmo6IHVua25vd24sIGVycm9yTWVzc2FnZVJvb3Q6IHN0cmluZyk6IHVua25vd24gPT4ge1xuICAgIGlmICghaGFzS2V5KGtleSwgb2JqKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZXJyb3JNZXNzYWdlUm9vdH06IG5vICR7a2V5fSBzZXRgKTtcbiAgICB9XG4gICAgcmV0dXJuIG9ialtrZXldO1xufTtcblxuY29uc3QgaXNTdHJpbmcgPSAoYTogdW5rbm93bik6IGEgaXMgc3RyaW5nID0