UNPKG

@k9securityio/k9-cdk

Version:

Provision strong AWS security policies easily using the AWS CDK.

116 lines 18.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SID_DENY_EVERYONE_ELSE = void 0; exports.makeResourcePolicy = makeResourcePolicy; exports.grantAccessViaResourcePolicy = grantAccessViaResourcePolicy; const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const iam = require("aws-cdk-lib/aws-iam"); const k9policy_1 = require("./k9policy"); let SUPPORTED_CAPABILITIES = new Array(k9policy_1.AccessCapability.ADMINISTER_RESOURCE, k9policy_1.AccessCapability.READ_CONFIG, k9policy_1.AccessCapability.READ_DATA, k9policy_1.AccessCapability.WRITE_DATA, k9policy_1.AccessCapability.DELETE_DATA); exports.SID_DENY_EVERYONE_ELSE = 'DenyEveryoneElse'; function partitionArray(arr, maxLength) { const result = []; for (let i = 0; i < arr.length; i += maxLength) { result.push(arr.slice(i, i + maxLength)); } return result; } /** * Generate a SQS resource policy from the provided props that can be attached to a queue. * * @param props specifying desired access * @return a PolicyDocument that can be attached to an SQS queue */ function makeResourcePolicy(props) { const policyFactory = new k9policy_1.K9PolicyFactory(); const policy = new iam.PolicyDocument(); const resourceArns = ['*']; let accessSpecsByCapabilityRecs = policyFactory.mergeDesiredAccessSpecsByCapability(SUPPORTED_CAPABILITIES, props.k9DesiredAccess); let accessSpecsByCapability = new Map(); for (let [capabilityStr, accessSpec] of Object.entries(accessSpecsByCapabilityRecs)) { accessSpecsByCapability.set((0, k9policy_1.getAccessCapabilityFromValue)(capabilityStr), accessSpec); } if (!(0, k9policy_1.canPrincipalsManageResources)(accessSpecsByCapability)) { throw Error('At least one principal must be able to administer and read-config for SQS resources' + ' so data remains accessible; found:\n' + `administer-resource: '${accessSpecsByCapability.get(k9policy_1.AccessCapability.ADMINISTER_RESOURCE)?.allowPrincipalArns}'\n` + `read-config: '${accessSpecsByCapability.get(k9policy_1.AccessCapability.READ_CONFIG)?.allowPrincipalArns}'`); } const allowStatements = policyFactory.makeAllowStatements('SQS', SUPPORTED_CAPABILITIES, Array.from(accessSpecsByCapability.values()), resourceArns); const max_actions_in_statement = 7; for (let allowStatement of allowStatements) { //SQS resource policy has a limit of 7 actions per statement (Really). //But you can have as many statements as you want up to the queue policy size limit. //So, if an allowStatement has more than 7 actions (like the administer-resource statement does), //then create additional statements and spread the original statement's permissions across them if (allowStatement.actions.length > max_actions_in_statement) { const partitionedActions = partitionArray(allowStatement.actions, max_actions_in_statement); partitionedActions.forEach((actions, index) => { const newStatement = allowStatement.copy({ sid: `${allowStatement.sid} ${index + 1}`, actions: actions, }); policy.addStatements(newStatement); }); } else { policy.addStatements(allowStatement); } } const denyEveryoneElseStatement = new aws_iam_1.PolicyStatement({ sid: exports.SID_DENY_EVERYONE_ELSE, effect: aws_iam_1.Effect.DENY, principals: policyFactory.makeDenyEveryoneElsePrincipals(), actions: ['sqs:*'], resources: resourceArns, }); denyEveryoneElseStatement.addCondition('Bool', { 'aws:PrincipalIsAWSService': ['false'], }); const denyEveryoneElseTest = policyFactory.wasLikeUsed(props.k9DesiredAccess) ? 'ArnNotLike' : 'ArnNotEquals'; const allAllowedPrincipalArns = policyFactory.getAllowedPrincipalArns(props.k9DesiredAccess); const accountRootPrincipal = new aws_iam_1.AccountRootPrincipal(); denyEveryoneElseStatement.addCondition(denyEveryoneElseTest, { 'aws:PrincipalArn': [ // Place Root Principal arn in stable, prominent position; // will render as an object Fn::Join'ing Partition & AccountId accountRootPrincipal.arn, ...allAllowedPrincipalArns, ], }); policy.addStatements(denyEveryoneElseStatement); const denyUntrustedOrgsStatement = policyFactory._makeDenyUntrustedOrgsStatement('SQS', SUPPORTED_CAPABILITIES, accessSpecsByCapability, resourceArns); if (denyUntrustedOrgsStatement) { policy.addStatements(denyUntrustedOrgsStatement); } policy.validateForResourcePolicy(); return policy; } /** * Grant access to a queue via resource policy using k9 IAccessSpec definitions. This function * is the preferred interface for granting access to a queue. * * The grant and make operations are split because SQS policies can only be managed via the * IQueue.addToResourcePolicy method but IQueue does not offer a way to read the policy. * So making the policy is done in a separate function so policy generation can be tested. * * @param props specifying the queue and desired access * * @return the results for adding each statement */ function grantAccessViaResourcePolicy(props) { const resourcePolicy = makeResourcePolicy(props); resourcePolicy.validateForResourcePolicy(); const policyJson = resourcePolicy.toJSON(); const k9Statements = policyJson.Statement; const queue = props.queue; const addToResourcePolicyResults = new Array(); for (let statement of k9Statements) { let addToResourcePolicyResult = queue.addToResourcePolicy(aws_iam_1.PolicyStatement.fromJson(statement)); addToResourcePolicyResults.push(addToResourcePolicyResult); } return addToResourcePolicyResults; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Nxcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUErQ0EsZ0RBbUZDO0FBY0Qsb0VBbUJDO0FBbktELGlEQU02QjtBQUM3QiwyQ0FBMkM7QUFFM0MseUNBTW9CO0FBUXBCLElBQUksc0JBQXNCLEdBQUcsSUFBSSxLQUFLLENBQ3BDLDJCQUFnQixDQUFDLG1CQUFtQixFQUNwQywyQkFBZ0IsQ0FBQyxXQUFXLEVBQzVCLDJCQUFnQixDQUFDLFNBQVMsRUFDMUIsMkJBQWdCLENBQUMsVUFBVSxFQUMzQiwyQkFBZ0IsQ0FBQyxXQUFXLENBQzdCLENBQUM7QUFFVyxRQUFBLHNCQUFzQixHQUFHLGtCQUFrQixDQUFDO0FBRXpELFNBQVMsY0FBYyxDQUFJLEdBQVEsRUFBRSxTQUFpQjtJQUNwRCxNQUFNLE1BQU0sR0FBVSxFQUFFLENBQUM7SUFDekIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQy9DLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLEtBQStCO0lBQ2hFLE1BQU0sYUFBYSxHQUFHLElBQUksMEJBQWUsRUFBRSxDQUFDO0lBQzVDLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBRXhDLE1BQU0sWUFBWSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFM0IsSUFBSSwyQkFBMkIsR0FBRyxhQUFhLENBQUMsbUNBQW1DLENBQUMsc0JBQXNCLEVBQUUsS0FBSyxDQUFDLGVBQWUsQ0FBQyxD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b3J0IHtcbiAgQWNjb3VudFJvb3RQcmluY2lwYWwsXG4gIEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQsXG4gIEVmZmVjdCxcbiAgUG9saWN5RG9jdW1lbnQsXG4gIFBvbGljeVN0YXRlbWVudCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgeyBJUXVldWUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc3FzJztcbmltcG9ydCB7XG4gIEFjY2Vzc0NhcGFiaWxpdHksXG4gIGNhblByaW5jaXBhbHNNYW5hZ2VSZXNvdXJjZXMsXG4gIGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUsXG4gIElBY2Nlc3NTcGVjLFxuICBLOVBvbGljeUZhY3RvcnksXG59IGZyb20gJy4vazlwb2xpY3knO1xuXG5cbmV4cG9ydCBpbnRlcmZhY2UgSzlTUVNSZXNvdXJjZVBvbGljeVByb3BzIHtcbiAgcmVhZG9ubHkgcXVldWU6IElRdWV1ZTtcbiAgcmVhZG9ubHkgazlEZXNpcmVkQWNjZXNzOiBBcnJheTxJQWNjZXNzU3BlYz47XG59XG5cbmxldCBTVVBQT1JURURfQ0FQQUJJTElUSUVTID0gbmV3IEFycmF5PEFjY2Vzc0NhcGFiaWxpdHk+KFxuICBBY2Nlc3NDYXBhYmlsaXR5LkFETUlOSVNURVJfUkVTT1VSQ0UsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuUkVBRF9DT05GSUcsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuUkVBRF9EQVRBLFxuICBBY2Nlc3NDYXBhYmlsaXR5LldSSVRFX0RBVEEsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuREVMRVRFX0RBVEEsXG4pO1xuXG5leHBvcnQgY29uc3QgU0lEX0RFTllfRVZFUllPTkVfRUxTRSA9ICdEZW55RXZlcnlvbmVFbHNlJztcblxuZnVuY3Rpb24gcGFydGl0aW9uQXJyYXk8VD4oYXJyOiBUW10sIG1heExlbmd0aDogbnVtYmVyKTogVFtdW10ge1xuICBjb25zdCByZXN1bHQ6IFRbXVtdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgaSArPSBtYXhMZW5ndGgpIHtcbiAgICByZXN1bHQucHVzaChhcnIuc2xpY2UoaSwgaSArIG1heExlbmd0aCkpO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgYSBTUVMgcmVzb3VyY2UgcG9saWN5IGZyb20gdGhlIHByb3ZpZGVkIHByb3BzIHRoYXQgY2FuIGJlIGF0dGFjaGVkIHRvIGEgcXVldWUuXG4gKlxuICogQHBhcmFtIHByb3BzIHNwZWNpZnlpbmcgZGVzaXJlZCBhY2Nlc3NcbiAqIEByZXR1cm4gYSBQb2xpY3lEb2N1bWVudCB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhbiBTUVMgcXVldWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1ha2VSZXNvdXJjZVBvbGljeShwcm9wczogSzlTUVNSZXNvdXJjZVBvbGljeVByb3BzKTogUG9saWN5RG9jdW1lbnQge1xuICBjb25zdCBwb2xpY3lGYWN0b3J5ID0gbmV3IEs5UG9saWN5RmFjdG9yeSgpO1xuICBjb25zdCBwb2xpY3kgPSBuZXcgaWFtLlBvbGljeURvY3VtZW50KCk7XG5cbiAgY29uc3QgcmVzb3VyY2VBcm5zID0gWycqJ107XG5cbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5UmVjcyA9IHBvbGljeUZhY3RvcnkubWVyZ2VEZXNpcmVkQWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkoU1VQUE9SVEVEX0NBUEFCSUxJVElFUywgcHJvcHMuazlEZXNpcmVkQWNjZXNzKTtcbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5OiBNYXA8QWNjZXNzQ2FwYWJpbGl0eSwgSUFjY2Vzc1NwZWM+ID0gbmV3IE1hcCgpO1xuXG4gIGZvciAobGV0IFtjYXBhYmlsaXR5U3RyLCBhY2Nlc3NTcGVjXSBvZiBPYmplY3QuZW50cmllcyhhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eVJlY3MpKSB7XG4gICAgYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuc2V0KGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUoY2FwYWJpbGl0eVN0ciksIGFjY2Vzc1NwZWMpO1xuICB9XG5cbiAgaWYgKCFjYW5QcmluY2lwYWxzTWFuYWdlUmVzb3VyY2VzKGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5KSkge1xuICAgIHRocm93IEVycm9yKCdBdCBsZWFzdCBvbmUgcHJpbmNpcGFsIG11c3QgYmUgYWJsZSB0byBhZG1pbmlzdGVyIGFuZCByZWFkLWNvbmZpZyBmb3IgU1FTIHJlc291cmNlcycgK1xuICAgICAgICAgICAgJyBzbyBkYXRhIHJlbWFpbnMgYWNjZXNzaWJsZTsgZm91bmQ6XFxuJyArXG4gICAgICAgICAgICBgYWRtaW5pc3Rlci1yZXNvdXJjZTogJyR7YWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuZ2V0KEFjY2Vzc0NhcGFiaWxpdHkuQURNSU5JU1RFUl9SRVNPVVJDRSk/LmFsbG93UHJpbmNpcGFsQXJuc30nXFxuYCArXG4gICAgICAgICAgICBgcmVhZC1jb25maWc6ICcke2FjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LmdldChBY2Nlc3NDYXBhYmlsaXR5LlJFQURfQ09ORklHKT8uYWxsb3dQcmluY2lwYWxBcm5zfSdgLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBhbGxvd1N0YXRlbWVudHMgPSBwb2xpY3lGYWN0b3J5Lm1ha2VBbGxvd1N0YXRlbWVudHMoJ1NRUycsXG4gICAgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyxcbiAgICBBcnJheS5mcm9tKGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LnZhbHVlcygpKSxcbiAgICByZXNvdXJjZUFybnMpO1xuXG4gIGNvbnN0IG1heF9hY3Rpb25zX2luX3N0YXRlbWVudCA9IDc7XG4gIGZvciAobGV0IGFsbG93U3RhdGVtZW50IG9mIGFsbG93U3RhdGVtZW50cykge1xuICAgIC8vU1FTIHJlc291cmNlIHBvbGljeSBoYXMgYSBsaW1pdCBvZiA3IGFjdGlvbnMgcGVyIHN0YXRlbWVudCAoUmVhbGx5KS5cbiAgICAvL0J1dCB5b3UgY2FuIGhhdmUgYXMgbWFueSBzdGF0ZW1lbnRzIGFzIHlvdSB3YW50IHVwIHRvIHRoZSBxdWV1ZSBwb2xpY3kgc2l6ZSBsaW1pdC5cbiAgICAvL1NvLCBpZiBhbiBhbGxvd1N0YXRlbWVudCBoYXMgbW9yZSB0aGFuIDcgYWN0aW9ucyAobGlrZSB0aGUgYWRtaW5pc3Rlci1yZXNvdXJjZSBzdGF0ZW1lbnQgZG9lcyksXG4gICAgLy90aGVuIGNyZWF0ZSBhZGRpdGlvbmFsIHN0YXRlbWVudHMgYW5kIHNwcmVhZCB0aGUgb3JpZ2luYWwgc3RhdGVtZW50J3MgcGVybWlzc2lvbnMgYWNyb3NzIHRoZW1cbiAgICBpZiAoYWxsb3dTdGF0ZW1lbnQuYWN0aW9ucy5sZW5ndGggPiBtYXhfYWN0aW9uc19pbl9zdGF0ZW1lbnQpIHtcbiAgICAgIGNvbnN0IHBhcnRpdGlvbmVkQWN0aW9ucyA9IHBhcnRpdGlvbkFycmF5KGFsbG93U3RhdGVtZW50LmFjdGlvbnMsIG1heF9hY3Rpb25zX2luX3N0YXRlbWVudCk7XG4gICAgICBwYXJ0aXRpb25lZEFjdGlvbnMuZm9yRWFjaCgoYWN0aW9ucywgaW5kZXgpID0+IHtcbiAgICAgICAgY29uc3QgbmV3U3RhdGVtZW50ID0gYWxsb3dTdGF0ZW1lbnQuY29weSh7XG4gICAgICAgICAgc2lkOiBgJHthbGxvd1N0YXRlbWVudC5zaWR9ICR7aW5kZXggKyAxfWAsXG4gICAgICAgICAgYWN0aW9uczogYWN0aW9ucyxcbiAgICAgICAgfSk7XG4gICAgICAgIHBvbGljeS5hZGRTdGF0ZW1lbnRzKG5ld1N0YXRlbWVudCk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcG9saWN5LmFkZFN0YXRlbWVudHMoYWxsb3dTdGF0ZW1lbnQpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQgPSBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICBzaWQ6IFNJRF9ERU5ZX0VWRVJZT05FX0VMU0UsXG4gICAgZWZmZWN0OiBFZmZlY3QuREVOWSxcbiAgICBwcmluY2lwYWxzOiBwb2xpY3lGYWN0b3J5Lm1ha2VEZW55RXZlcnlvbmVFbHNlUHJpbmNpcGFscygpLFxuICAgIGFjdGlvbnM6IFsnc3FzOionXSxcbiAgICByZXNvdXJjZXM6IHJlc291cmNlQXJucyxcbiAgfSk7XG4gIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQuYWRkQ29uZGl0aW9uKCdCb29sJywge1xuICAgICdhd3M6UHJpbmNpcGFsSXNBV1NTZXJ2aWNlJzogWydmYWxzZSddLFxuICB9KTtcbiAgY29uc3QgZGVueUV2ZXJ5b25lRWxzZVRlc3QgPSBwb2xpY3lGYWN0b3J5Lndhc0xpa2VVc2VkKHByb3BzLms5RGVzaXJlZEFjY2VzcykgP1xuICAgICdBcm5Ob3RMaWtlJyA6XG4gICAgJ0Fybk5vdEVxdWFscyc7XG4gIGNvbnN0IGFsbEFsbG93ZWRQcmluY2lwYWxBcm5zID0gcG9saWN5RmFjdG9yeS5nZXRBbGxvd2VkUHJpbmNpcGFsQXJucyhwcm9wcy5rOURlc2lyZWRBY2Nlc3MpO1xuICBjb25zdCBhY2NvdW50Um9vdFByaW5jaXBhbCA9IG5ldyBBY2NvdW50Um9vdFByaW5jaXBhbCgpO1xuICBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50LmFkZENvbmRpdGlvbihkZW55RXZlcnlvbmVFbHNlVGVzdCwge1xuICAgICdhd3M6UHJpbmNpcGFsQXJuJzogW1xuICAgICAgLy8gUGxhY2UgUm9vdCBQcmluY2lwYWwgYXJuIGluIHN0YWJsZSwgcHJvbWluZW50IHBvc2l0aW9uO1xuICAgICAgLy8gd2lsbCByZW5kZXIgYXMgYW4gb2JqZWN0IEZuOjpKb2luJ2luZyBQYXJ0aXRpb24gJiBBY2NvdW50SWRcbiAgICAgIGFjY291bnRSb290UHJpbmNpcGFsLmFybixcbiAgICAgIC4uLmFsbEFsbG93ZWRQcmluY2lwYWxBcm5zLFxuICAgIF0sXG4gIH0pO1xuXG4gIHBvbGljeS5hZGRTdGF0ZW1lbnRzKFxuICAgIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQsXG4gICk7XG5cbiAgY29uc3QgZGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQgPSBwb2xpY3lGYWN0b3J5Ll9tYWtlRGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQoXG4gICAgJ1NRUycsIFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsIGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LCByZXNvdXJjZUFybnMpO1xuICBpZiAoZGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQpIHtcbiAgICBwb2xpY3kuYWRkU3RhdGVtZW50cyhkZW55VW50cnVzdGVkT3Jnc1N0YXRlbWVudCk7XG4gIH1cblxuICBwb2xpY3kudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIHJldHVybiBwb2xpY3k7XG59XG5cbi8qKlxuICogR3JhbnQgYWNjZXNzIHRvIGEgcXVldWUgdmlhIHJlc291cmNlIHBvbGljeSB1c2luZyBrOSBJQWNjZXNzU3BlYyBkZWZpbml0aW9ucy4gVGhpcyBmdW5jdGlvblxuICogaXMgdGhlIHByZWZlcnJlZCBpbnRlcmZhY2UgZm9yIGdyYW50aW5nIGFjY2VzcyB0byBhIHF1ZXVlLlxuICpcbiAqIFRoZSBncmFudCBhbmQgbWFrZSBvcGVyYXRpb25zIGFyZSBzcGxpdCBiZWNhdXNlIFNRUyBwb2xpY2llcyBjYW4gb25seSBiZSBtYW5hZ2VkIHZpYSB0aGVcbiAqIElRdWV1ZS5hZGRUb1Jlc291cmNlUG9saWN5IG1ldGhvZCBidXQgSVF1ZXVlIGRvZXMgbm90IG9mZmVyIGEgd2F5IHRvIHJlYWQgdGhlIHBvbGljeS5cbiAqIFNvIG1ha2luZyB0aGUgcG9saWN5IGlzIGRvbmUgaW4gYSBzZXBhcmF0ZSBmdW5jdGlvbiBzbyBwb2xpY3kgZ2VuZXJhdGlvbiBjYW4gYmUgdGVzdGVkLlxuICpcbiAqIEBwYXJhbSBwcm9wcyBzcGVjaWZ5aW5nIHRoZSBxdWV1ZSBhbmQgZGVzaXJlZCBhY2Nlc3NcbiAqXG4gKiBAcmV0dXJuIHRoZSByZXN1bHRzIGZvciBhZGRpbmcgZWFjaCBzdGF0ZW1lbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyYW50QWNjZXNzVmlhUmVzb3VyY2VQb2xpY3kocHJvcHM6IEs5U1FTUmVzb3VyY2VQb2xpY3lQcm9wcyk6XG5BZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0W10ge1xuICBjb25zdCByZXNvdXJjZVBvbGljeSA9IG1ha2VSZXNvdXJjZVBvbGljeShwcm9wcyk7XG5cbiAgcmVzb3VyY2VQb2xpY3kudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIGNvbnN0IHBvbGljeUpzb24gPSByZXNvdXJjZVBvbGljeS50b0pTT04oKTtcbiAgY29uc3QgazlTdGF0ZW1lbnRzID0gcG9saWN5SnNvbi5TdGF0ZW1lbnQ7XG4gIGNvbnN0IHF1ZXVlID0gcHJvcHMucXVldWU7XG4gIGNvbnN0IGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHRzID0gbmV3IEFycmF5PEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQ+KCk7XG5cbiAgZm9yIChsZXQgc3RhdGVtZW50IG9mIGs5U3RhdGVtZW50cykge1xuICAgIGxldCBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0ID0gcXVldWUuYWRkVG9SZXNvdXJjZVBvbGljeShcbiAgICAgIFBvbGljeVN0YXRlbWVudC5mcm9tSnNvbihzdGF0ZW1lbnQpLFxuICAgICk7XG4gICAgYWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdHMucHVzaChhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0KTtcbiAgfVxuXG4gIHJldHVybiBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0cztcbn1cbiJdfQ==