sops-secretsmanager-cdk
Version:
Safely load secrets from sops into secretsmanager using the CDK
408 lines • 55.4 kB
JavaScript
"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