@k9securityio/k9-cdk
Version:
Provision strong AWS security policies easily using the AWS CDK.
112 lines • 18.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.grantAccessViaResourcePolicy = exports.makeResourcePolicy = exports.SID_DENY_EVERYONE_ELSE = void 0;
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);
policy.validateForResourcePolicy();
return policy;
}
exports.makeResourcePolicy = makeResourcePolicy;
/**
* 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;
}
exports.grantAccessViaResourcePolicy = grantAccessViaResourcePolicy;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Nxcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxpREFNNkI7QUFDN0IsMkNBQTJDO0FBRTNDLHlDQU1vQjtBQVFwQixJQUFJLHNCQUFzQixHQUFHLElBQUksS0FBSyxDQUNwQywyQkFBZ0IsQ0FBQyxtQkFBbUIsRUFDcEMsMkJBQWdCLENBQUMsV0FBVyxFQUM1QiwyQkFBZ0IsQ0FBQyxTQUFTLEVBQzFCLDJCQUFnQixDQUFDLFVBQVUsRUFDM0IsMkJBQWdCLENBQUMsV0FBVyxDQUM3QixDQUFDO0FBRVcsUUFBQSxzQkFBc0IsR0FBRyxrQkFBa0IsQ0FBQztBQUV6RCxTQUFTLGNBQWMsQ0FBSSxHQUFRLEVBQUUsU0FBaUI7SUFDcEQsTUFBTSxNQUFNLEdBQVUsRUFBRSxDQUFDO0lBQ3pCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUMvQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxLQUErQjtJQUNoRSxNQUFNLGFBQWEsR0FBRyxJQUFJLDBCQUFlLEVBQUUsQ0FBQztJQUM1QyxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUV4QyxNQUFNLFlBQVksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRTNCLElBQUksMkJBQTJCLEdBQUcsYUFBYSxDQUFDLG1DQUFtQyxDQUFDLHNCQUFzQixFQUFFLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNuSSxJQUFJLHVCQUF1QixHQUF1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QUFDLEdBQUc7WUFDeEIsR0FBRyx1QkFBdUI7U0FDM0I7S0FDRixDQUFDLENBQUM7SUFFSCxNQUFNLENBQUMsYUFBYSxDQUNsQix5QkFBeUIsQ0FDMUIsQ0FBQztJQUVGLE1BQU0sQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO0lBRW5DLE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUE3RUQsZ0RBNkVDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFnQiw0QkFBNEIsQ0FBQyxLQUErQjtJQUUxRSxNQUFNLGNBQWMsR0FBRyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUVqRCxjQUFjLENBQUMseUJBQXlCLEVBQUUsQ0FBQztJQUUzQyxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDM0MsTUFBTSxZQUFZLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQztJQUMxQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzFCLE1BQU0sMEJBQTBCLEdBQUcsSUFBSSxLQUFLLEVBQTZCLENBQUM7SUFFMUUsS0FBSyxJQUFJLFNBQVMsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQyxJQUFJLHlCQUF5QixHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FDdkQseUJBQWUsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQ3BDLENBQUM7UUFDRiwwQkFBMEIsQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQsT0FBTywwQkFBMEIsQ0FBQztBQUNwQyxDQUFDO0FBbkJELG9FQW1CQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFjY291bnRSb290UHJpbmNpcGFsLFxuICBBZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0LFxuICBFZmZlY3QsXG4gIFBvbGljeURvY3VtZW50LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgSVF1ZXVlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNxcyc7XG5pbXBvcnQge1xuICBBY2Nlc3NDYXBhYmlsaXR5LFxuICBjYW5QcmluY2lwYWxzTWFuYWdlUmVzb3VyY2VzLFxuICBnZXRBY2Nlc3NDYXBhYmlsaXR5RnJvbVZhbHVlLFxuICBJQWNjZXNzU3BlYyxcbiAgSzlQb2xpY3lGYWN0b3J5LFxufSBmcm9tICcuL2s5cG9saWN5JztcblxuXG5leHBvcnQgaW50ZXJmYWNlIEs5U1FTUmVzb3VyY2VQb2xpY3lQcm9wcyB7XG4gIHJlYWRvbmx5IHF1ZXVlOiBJUXVldWU7XG4gIHJlYWRvbmx5IGs5RGVzaXJlZEFjY2VzczogQXJyYXk8SUFjY2Vzc1NwZWM+O1xufVxuXG5sZXQgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyA9IG5ldyBBcnJheTxBY2Nlc3NDYXBhYmlsaXR5PihcbiAgQWNjZXNzQ2FwYWJpbGl0eS5BRE1JTklTVEVSX1JFU09VUkNFLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfQ09ORklHLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfREFUQSxcbiAgQWNjZXNzQ2FwYWJpbGl0eS5XUklURV9EQVRBLFxuICBBY2Nlc3NDYXBhYmlsaXR5LkRFTEVURV9EQVRBLFxuKTtcblxuZXhwb3J0IGNvbnN0IFNJRF9ERU5ZX0VWRVJZT05FX0VMU0UgPSAnRGVueUV2ZXJ5b25lRWxzZSc7XG5cbmZ1bmN0aW9uIHBhcnRpdGlvbkFycmF5PFQ+KGFycjogVFtdLCBtYXhMZW5ndGg6IG51bWJlcik6IFRbXVtdIHtcbiAgY29uc3QgcmVzdWx0OiBUW11bXSA9IFtdO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkgKz0gbWF4TGVuZ3RoKSB7XG4gICAgcmVzdWx0LnB1c2goYXJyLnNsaWNlKGksIGkgKyBtYXhMZW5ndGgpKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgU1FTIHJlc291cmNlIHBvbGljeSBmcm9tIHRoZSBwcm92aWRlZCBwcm9wcyB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhIHF1ZXVlLlxuICpcbiAqIEBwYXJhbSBwcm9wcyBzcGVjaWZ5aW5nIGRlc2lyZWQgYWNjZXNzXG4gKiBAcmV0dXJuIGEgUG9saWN5RG9jdW1lbnQgdGhhdCBjYW4gYmUgYXR0YWNoZWQgdG8gYW4gU1FTIHF1ZXVlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYWtlUmVzb3VyY2VQb2xpY3kocHJvcHM6IEs5U1FTUmVzb3VyY2VQb2xpY3lQcm9wcyk6IFBvbGljeURvY3VtZW50IHtcbiAgY29uc3QgcG9saWN5RmFjdG9yeSA9IG5ldyBLOVBvbGljeUZhY3RvcnkoKTtcbiAgY29uc3QgcG9saWN5ID0gbmV3IGlhbS5Qb2xpY3lEb2N1bWVudCgpO1xuXG4gIGNvbnN0IHJlc291cmNlQXJucyA9IFsnKiddO1xuXG4gIGxldCBhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eVJlY3MgPSBwb2xpY3lGYWN0b3J5Lm1lcmdlRGVzaXJlZEFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5KFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsIHByb3BzLms5RGVzaXJlZEFjY2Vzcyk7XG4gIGxldCBhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eTogTWFwPEFjY2Vzc0NhcGFiaWxpdHksIElBY2Nlc3NTcGVjPiA9IG5ldyBNYXAoKTtcblxuICBmb3IgKGxldCBbY2FwYWJpbGl0eVN0ciwgYWNjZXNzU3BlY10gb2YgT2JqZWN0LmVudHJpZXMoYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHlSZWNzKSkge1xuICAgIGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LnNldChnZXRBY2Nlc3NDYXBhYmlsaXR5RnJvbVZhbHVlKGNhcGFiaWxpdHlTdHIpLCBhY2Nlc3NTcGVjKTtcbiAgfVxuXG4gIGlmICghY2FuUHJpbmNpcGFsc01hbmFnZVJlc291cmNlcyhhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eSkpIHtcbiAgICB0aHJvdyBFcnJvcignQXQgbGVhc3Qgb25lIHByaW5jaXBhbCBtdXN0IGJlIGFibGUgdG8gYWRtaW5pc3RlciBhbmQgcmVhZC1jb25maWcgZm9yIFNRUyByZXNvdXJjZXMnICtcbiAgICAgICAgICAgICcgc28gZGF0YSByZW1haW5zIGFjY2Vzc2libGU7IGZvdW5kOlxcbicgK1xuICAgICAgICAgICAgYGFkbWluaXN0ZXItcmVzb3VyY2U6ICcke2FjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LmdldChBY2Nlc3NDYXBhYmlsaXR5LkFETUlOSVNURVJfUkVTT1VSQ0UpPy5hbGxvd1ByaW5jaXBhbEFybnN9J1xcbmAgK1xuICAgICAgICAgICAgYHJlYWQtY29uZmlnOiAnJHthY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eS5nZXQoQWNjZXNzQ2FwYWJpbGl0eS5SRUFEX0NPTkZJRyk/LmFsbG93UHJpbmNpcGFsQXJuc30nYCxcbiAgICApO1xuICB9XG5cbiAgY29uc3QgYWxsb3dTdGF0ZW1lbnRzID0gcG9saWN5RmFjdG9yeS5tYWtlQWxsb3dTdGF0ZW1lbnRzKCdTUVMnLFxuICAgIFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsXG4gICAgQXJyYXkuZnJvbShhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eS52YWx1ZXMoKSksXG4gICAgcmVzb3VyY2VBcm5zKTtcblxuICBjb25zdCBtYXhfYWN0aW9uc19pbl9zdGF0ZW1lbnQgPSA3O1xuICBmb3IgKGxldCBhbGxvd1N0YXRlbWVudCBvZiBhbGxvd1N0YXRlbWVudHMpIHtcbiAgICAvL1NRUyByZXNvdXJjZSBwb2xpY3kgaGFzIGEgbGltaXQgb2YgNyBhY3Rpb25zIHBlciBzdGF0ZW1lbnQgKFJlYWxseSkuXG4gICAgLy9CdXQgeW91IGNhbiBoYXZlIGFzIG1hbnkgc3RhdGVtZW50cyBhcyB5b3Ugd2FudCB1cCB0byB0aGUgcXVldWUgcG9saWN5IHNpemUgbGltaXQuXG4gICAgLy9TbywgaWYgYW4gYWxsb3dTdGF0ZW1lbnQgaGFzIG1vcmUgdGhhbiA3IGFjdGlvbnMgKGxpa2UgdGhlIGFkbWluaXN0ZXItcmVzb3VyY2Ugc3RhdGVtZW50IGRvZXMpLFxuICAgIC8vdGhlbiBjcmVhdGUgYWRkaXRpb25hbCBzdGF0ZW1lbnRzIGFuZCBzcHJlYWQgdGhlIG9yaWdpbmFsIHN0YXRlbWVudCdzIHBlcm1pc3Npb25zIGFjcm9zcyB0aGVtXG4gICAgaWYgKGFsbG93U3RhdGVtZW50LmFjdGlvbnMubGVuZ3RoID4gbWF4X2FjdGlvbnNfaW5fc3RhdGVtZW50KSB7XG4gICAgICBjb25zdCBwYXJ0aXRpb25lZEFjdGlvbnMgPSBwYXJ0aXRpb25BcnJheShhbGxvd1N0YXRlbWVudC5hY3Rpb25zLCBtYXhfYWN0aW9uc19pbl9zdGF0ZW1lbnQpO1xuICAgICAgcGFydGl0aW9uZWRBY3Rpb25zLmZvckVhY2goKGFjdGlvbnMsIGluZGV4KSA9PiB7XG4gICAgICAgIGNvbnN0IG5ld1N0YXRlbWVudCA9IGFsbG93U3RhdGVtZW50LmNvcHkoe1xuICAgICAgICAgIHNpZDogYCR7YWxsb3dTdGF0ZW1lbnQuc2lkfSAke2luZGV4ICsgMX1gLFxuICAgICAgICAgIGFjdGlvbnM6IGFjdGlvbnMsXG4gICAgICAgIH0pO1xuICAgICAgICBwb2xpY3kuYWRkU3RhdGVtZW50cyhuZXdTdGF0ZW1lbnQpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBvbGljeS5hZGRTdGF0ZW1lbnRzKGFsbG93U3RhdGVtZW50KTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50ID0gbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgc2lkOiBTSURfREVOWV9FVkVSWU9ORV9FTFNFLFxuICAgIGVmZmVjdDogRWZmZWN0LkRFTlksXG4gICAgcHJpbmNpcGFsczogcG9saWN5RmFjdG9yeS5tYWtlRGVueUV2ZXJ5b25lRWxzZVByaW5jaXBhbHMoKSxcbiAgICBhY3Rpb25zOiBbJ3NxczoqJ10sXG4gICAgcmVzb3VyY2VzOiByZXNvdXJjZUFybnMsXG4gIH0pO1xuICBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50LmFkZENvbmRpdGlvbignQm9vbCcsIHtcbiAgICAnYXdzOlByaW5jaXBhbElzQVdTU2VydmljZSc6IFsnZmFsc2UnXSxcbiAgfSk7XG4gIGNvbnN0IGRlbnlFdmVyeW9uZUVsc2VUZXN0ID0gcG9saWN5RmFjdG9yeS53YXNMaWtlVXNlZChwcm9wcy5rOURlc2lyZWRBY2Nlc3MpID9cbiAgICAnQXJuTm90TGlrZScgOlxuICAgICdBcm5Ob3RFcXVhbHMnO1xuICBjb25zdCBhbGxBbGxvd2VkUHJpbmNpcGFsQXJucyA9IHBvbGljeUZhY3RvcnkuZ2V0QWxsb3dlZFByaW5jaXBhbEFybnMocHJvcHMuazlEZXNpcmVkQWNjZXNzKTtcbiAgY29uc3QgYWNjb3VudFJvb3RQcmluY2lwYWwgPSBuZXcgQWNjb3VudFJvb3RQcmluY2lwYWwoKTtcbiAgZGVueUV2ZXJ5b25lRWxzZVN0YXRlbWVudC5hZGRDb25kaXRpb24oZGVueUV2ZXJ5b25lRWxzZVRlc3QsIHtcbiAgICAnYXdzOlByaW5jaXBhbEFybic6IFtcbiAgICAgIC8vIFBsYWNlIFJvb3QgUHJpbmNpcGFsIGFybiBpbiBzdGFibGUsIHByb21pbmVudCBwb3NpdGlvbjtcbiAgICAgIC8vIHdpbGwgcmVuZGVyIGFzIGFuIG9iamVjdCBGbjo6Sm9pbidpbmcgUGFydGl0aW9uICYgQWNjb3VudElkXG4gICAgICBhY2NvdW50Um9vdFByaW5jaXBhbC5hcm4sXG4gICAgICAuLi5hbGxBbGxvd2VkUHJpbmNpcGFsQXJucyxcbiAgICBdLFxuICB9KTtcblxuICBwb2xpY3kuYWRkU3RhdGVtZW50cyhcbiAgICBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50LFxuICApO1xuXG4gIHBvbGljeS52YWxpZGF0ZUZvclJlc291cmNlUG9saWN5KCk7XG5cbiAgcmV0dXJuIHBvbGljeTtcbn1cblxuLyoqXG4gKiBHcmFudCBhY2Nlc3MgdG8gYSBxdWV1ZSB2aWEgcmVzb3VyY2UgcG9saWN5IHVzaW5nIGs5IElBY2Nlc3NTcGVjIGRlZmluaXRpb25zLiBUaGlzIGZ1bmN0aW9uXG4gKiBpcyB0aGUgcHJlZmVycmVkIGludGVyZmFjZSBmb3IgZ3JhbnRpbmcgYWNjZXNzIHRvIGEgcXVldWUuXG4gKlxuICogVGhlIGdyYW50IGFuZCBtYWtlIG9wZXJhdGlvbnMgYXJlIHNwbGl0IGJlY2F1c2UgU1FTIHBvbGljaWVzIGNhbiBvbmx5IGJlIG1hbmFnZWQgdmlhIHRoZVxuICogSVF1ZXVlLmFkZFRvUmVzb3VyY2VQb2xpY3kgbWV0aG9kIGJ1dCBJUXVldWUgZG9lcyBub3Qgb2ZmZXIgYSB3YXkgdG8gcmVhZCB0aGUgcG9saWN5LlxuICogU28gbWFraW5nIHRoZSBwb2xpY3kgaXMgZG9uZSBpbiBhIHNlcGFyYXRlIGZ1bmN0aW9uIHNvIHBvbGljeSBnZW5lcmF0aW9uIGNhbiBiZSB0ZXN0ZWQuXG4gKlxuICogQHBhcmFtIHByb3BzIHNwZWNpZnlpbmcgdGhlIHF1ZXVlIGFuZCBkZXNpcmVkIGFjY2Vzc1xuICpcbiAqIEByZXR1cm4gdGhlIHJlc3VsdHMgZm9yIGFkZGluZyBlYWNoIHN0YXRlbWVudFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ3JhbnRBY2Nlc3NWaWFSZXNvdXJjZVBvbGljeShwcm9wczogSzlTUVNSZXNvdXJjZVBvbGljeVByb3BzKTpcbkFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHRbXSB7XG4gIGNvbnN0IHJlc291cmNlUG9saWN5ID0gbWFrZVJlc291cmNlUG9saWN5KHByb3BzKTtcblxuICByZXNvdXJjZVBvbGljeS52YWxpZGF0ZUZvclJlc291cmNlUG9saWN5KCk7XG5cbiAgY29uc3QgcG9saWN5SnNvbiA9IHJlc291cmNlUG9saWN5LnRvSlNPTigpO1xuICBjb25zdCBrOVN0YXRlbWVudHMgPSBwb2xpY3lKc29uLlN0YXRlbWVudDtcbiAgY29uc3QgcXVldWUgPSBwcm9wcy5xdWV1ZTtcbiAgY29uc3QgYWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdHMgPSBuZXcgQXJyYXk8QWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdD4oKTtcblxuICBmb3IgKGxldCBzdGF0ZW1lbnQgb2YgazlTdGF0ZW1lbnRzKSB7XG4gICAgbGV0IGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQgPSBxdWV1ZS5hZGRUb1Jlc291cmNlUG9saWN5KFxuICAgICAgUG9saWN5U3RhdGVtZW50LmZyb21Kc29uKHN0YXRlbWVudCksXG4gICAgKTtcbiAgICBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0cy5wdXNoKGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQpO1xuICB9XG5cbiAgcmV0dXJuIGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHRzO1xufVxuIl19