@k9securityio/k9-cdk
Version:
Provision strong AWS security policies easily using the AWS CDK.
116 lines • 18.9 kB
JavaScript
;
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Nxcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUErQ0EsZ0RBbUZDO0FBY0Qsb0VBbUJDO0FBbktELGlEQU02QjtBQUM3QiwyQ0FBMkM7QUFFM0MseUNBTW9CO0FBUXBCLElBQUksc0JBQXNCLEdBQUcsSUFBSSxLQUFLLENBQ3BDLDJCQUFnQixDQUFDLG1CQUFtQixFQUNwQywyQkFBZ0IsQ0FBQyxXQUFXLEVBQzVCLDJCQUFnQixDQUFDLFNBQVMsRUFDMUIsMkJBQWdCLENBQUMsVUFBVSxFQUMzQiwyQkFBZ0IsQ0FBQyxXQUFXLENBQzdCLENBQUM7QUFFVyxRQUFBLHNCQUFzQixHQUFHLGtCQUFrQixDQUFDO0FBRXpELFNBQVMsY0FBYyxDQUFJLEdBQVEsRUFBRSxTQUFpQjtJQUNwRCxNQUFNLE1BQU0sR0FBVSxFQUFFLENBQUM7SUFDekIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQy9DLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLEtBQStCO0lBQ2hFLE1BQU0sYUFBYSxHQUFHLElBQUksMEJBQWUsRUFBRSxDQUFDO0lBQzVDLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBRXhDLE1BQU0sWUFBWSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFM0IsSUFBSSwyQkFBMkIsR0FBRyxhQUFhLENBQUMsbUNBQW1DLENBQUMsc0JBQXNCLEVBQUUsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ25JLElBQUksdUJBQXVCLEdBQXVDLElBQUksR0FBRyxFQUFFLENBQUM7SUFFNUUsS0FBSyxJQUFJLENBQUMsYUFBYSxFQUFFLFVBQVUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsMkJBQTJCLENBQUMsRUFBRSxDQUFDO1FBQ3BGLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxJQUFBLHVDQUE0QixFQUFDLGFBQWEsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFFRCxJQUFJLENBQUMsSUFBQSx1Q0FBNEIsRUFBQyx1QkFBdUIsQ0FBQyxFQUFFLENBQUM7UUFDM0QsTUFBTSxLQUFLLENBQUMscUZBQXFGO1lBQ3pGLHVDQUF1QztZQUN2Qyx5QkFBeUIsdUJBQXVCLENBQUMsR0FBRyxDQUFDLDJCQUFnQixDQUFDLG1CQUFtQixDQUFDLEVBQUUsa0JBQWtCLEtBQUs7WUFDbkgsaUJBQWlCLHVCQUF1QixDQUFDLEdBQUcsQ0FBQywyQkFBZ0IsQ0FBQyxXQUFXLENBQUMsRUFBRSxrQkFBa0IsR0FBRyxDQUN4RyxDQUFDO0lBQ0osQ0FBQztJQUVELE1BQU0sZUFBZSxHQUFHLGFBQWEsQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQzdELHNCQUFzQixFQUN0QixLQUFLLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQzVDLFlBQVksQ0FBQyxDQUFDO0lBRWhCLE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxDQUFDO0lBQ25DLEtBQUssSUFBSSxjQUFjLElBQUksZUFBZSxFQUFFLENBQUM7UUFDM0Msc0VBQXNFO1FBQ3RFLG9GQUFvRjtRQUNwRixpR0FBaUc7UUFDakcsK0ZBQStGO1FBQy9GLElBQUksY0FBYyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsd0JBQXdCLEVBQUUsQ0FBQztZQUM3RCxNQUFNLGtCQUFrQixHQUFHLGNBQWMsQ0FBQyxjQUFjLENBQUMsT0FBTyxFQUFFLHdCQUF3QixDQUFDLENBQUM7WUFDNUYsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFO2dCQUM1QyxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDO29CQUN2QyxHQUFHLEVBQUUsR0FBRyxjQUFjLENBQUMsR0FBRyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7b0JBQ3pDLE9BQU8sRUFBRSxPQUFPO2lCQUNqQixDQUFDLENBQUM7Z0JBQ0gsTUFBTSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNyQyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUN2QyxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0seUJBQXlCLEdBQUcsSUFBSSx5QkFBZSxDQUFDO1FBQ3BELEdBQUcsRUFBRSw4QkFBc0I7UUFDM0IsTUFBTSxFQUFFLGdCQUFNLENBQUMsSUFBSTtRQUNuQixVQUFVLEVBQUUsYUFBYSxDQUFDLDhCQUE4QixFQUFFO1FBQzFELE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQztRQUNsQixTQUFTLEVBQUUsWUFBWTtLQUN4QixDQUFDLENBQUM7SUFDSCx5QkFBeUIsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFO1FBQzdDLDJCQUEyQixFQUFFLENBQUMsT0FBTyxDQUFDO0tBQ3ZDLENBQUMsQ0FBQztJQUNILE1BQU0sb0JBQW9CLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQztRQUM3RSxZQUFZLENBQUMsQ0FBQztRQUNkLGNBQWMsQ0FBQztJQUNqQixNQUFNLHVCQUF1QixHQUFHLGFBQWEsQ0FBQyx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDN0YsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLDhCQUFvQixFQUFFLENBQUM7SUFDeEQseUJBQXlCLENBQUMsWUFBWSxDQUFDLG9CQUFvQixFQUFFO1FBQzNELGtCQUFrQixFQUFFO1lBQ2xCLDBEQUEwRDtZQUMxRCw4REFBOEQ7WUFDOUQsb0JBQW9CLENBQUMsR0FBRztZQUN4QixHQUFHLHVCQUF1QjtTQUMzQjtLQUNGLENBQUMsQ0FBQztJQUVILE1BQU0sQ0FBQyxhQUFhLENBQ2xCLHlCQUF5QixDQUMxQixDQUFDO0lBRUYsTUFBTSwwQkFBMEIsR0FBRyxhQUFhLENBQUMsK0JBQStCLENBQzlFLEtBQUssRUFBRSxzQkFBc0IsRUFBRSx1QkFBdUIsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUN4RSxJQUFJLDBCQUEwQixFQUFFLENBQUM7UUFDL0IsTUFBTSxDQUFDLGFBQWEsQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxNQUFNLENBQUMseUJBQXlCLEVBQUUsQ0FBQztJQUVuQyxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFnQiw0QkFBNEIsQ0FBQyxLQUErQjtJQUUxRSxNQUFNLGNBQWMsR0FBRyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUVqRCxjQUFjLENBQUMseUJBQXlCLEVBQUUsQ0FBQztJQUUzQyxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDM0MsTUFBTSxZQUFZLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQztJQUMxQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzFCLE1BQU0sMEJBQTBCLEdBQUcsSUFBSSxLQUFLLEVBQTZCLENBQUM7SUFFMUUsS0FBSyxJQUFJLFNBQVMsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQyxJQUFJLHlCQUF5QixHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FDdkQseUJBQWUsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQ3BDLENBQUM7UUFDRiwwQkFBMEIsQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQsT0FBTywwQkFBMEIsQ0FBQztBQUNwQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWNjb3VudFJvb3RQcmluY2lwYWwsXG4gIEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQsXG4gIEVmZmVjdCxcbiAgUG9saWN5RG9jdW1lbnQsXG4gIFBvbGljeVN0YXRlbWVudCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgeyBJUXVldWUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc3FzJztcbmltcG9ydCB7XG4gIEFjY2Vzc0NhcGFiaWxpdHksXG4gIGNhblByaW5jaXBhbHNNYW5hZ2VSZXNvdXJjZXMsXG4gIGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUsXG4gIElBY2Nlc3NTcGVjLFxuICBLOVBvbGljeUZhY3RvcnksXG59IGZyb20gJy4vazlwb2xpY3knO1xuXG5cbmV4cG9ydCBpbnRlcmZhY2UgSzlTUVNSZXNvdXJjZVBvbGljeVByb3BzIHtcbiAgcmVhZG9ubHkgcXVldWU6IElRdWV1ZTtcbiAgcmVhZG9ubHkgazlEZXNpcmVkQWNjZXNzOiBBcnJheTxJQWNjZXNzU3BlYz47XG59XG5cbmxldCBTVVBQT1JURURfQ0FQQUJJTElUSUVTID0gbmV3IEFycmF5PEFjY2Vzc0NhcGFiaWxpdHk+KFxuICBBY2Nlc3NDYXBhYmlsaXR5LkFETUlOSVNURVJfUkVTT1VSQ0UsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuUkVBRF9DT05GSUcsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuUkVBRF9EQVRBLFxuICBBY2Nlc3NDYXBhYmlsaXR5LldSSVRFX0RBVEEsXG4gIEFjY2Vzc0NhcGFiaWxpdHkuREVMRVRFX0RBVEEsXG4pO1xuXG5leHBvcnQgY29uc3QgU0lEX0RFTllfRVZFUllPTkVfRUxTRSA9ICdEZW55RXZlcnlvbmVFbHNlJztcblxuZnVuY3Rpb24gcGFydGl0aW9uQXJyYXk8VD4oYXJyOiBUW10sIG1heExlbmd0aDogbnVtYmVyKTogVFtdW10ge1xuICBjb25zdCByZXN1bHQ6IFRbXVtdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgaSArPSBtYXhMZW5ndGgpIHtcbiAgICByZXN1bHQucHVzaChhcnIuc2xpY2UoaSwgaSArIG1heExlbmd0aCkpO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgYSBTUVMgcmVzb3VyY2UgcG9saWN5IGZyb20gdGhlIHByb3ZpZGVkIHByb3BzIHRoYXQgY2FuIGJlIGF0dGFjaGVkIHRvIGEgcXVldWUuXG4gKlxuICogQHBhcmFtIHByb3BzIHNwZWNpZnlpbmcgZGVzaXJlZCBhY2Nlc3NcbiAqIEByZXR1cm4gYSBQb2xpY3lEb2N1bWVudCB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhbiBTUVMgcXVldWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1ha2VSZXNvdXJjZVBvbGljeShwcm9wczogSzlTUVNSZXNvdXJjZVBvbGljeVByb3BzKTogUG9saWN5RG9jdW1lbnQge1xuICBjb25zdCBwb2xpY3lGYWN0b3J5ID0gbmV3IEs5UG9saWN5RmFjdG9yeSgpO1xuICBjb25zdCBwb2xpY3kgPSBuZXcgaWFtLlBvbGljeURvY3VtZW50KCk7XG5cbiAgY29uc3QgcmVzb3VyY2VBcm5zID0gWycqJ107XG5cbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5UmVjcyA9IHBvbGljeUZhY3RvcnkubWVyZ2VEZXNpcmVkQWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkoU1VQUE9SVEVEX0NBUEFCSUxJVElFUywgcHJvcHMuazlEZXNpcmVkQWNjZXNzKTtcbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5OiBNYXA8QWNjZXNzQ2FwYWJpbGl0eSwgSUFjY2Vzc1NwZWM+ID0gbmV3IE1hcCgpO1xuXG4gIGZvciAobGV0IFtjYXBhYmlsaXR5U3RyLCBhY2Nlc3NTcGVjXSBvZiBPYmplY3QuZW50cmllcyhhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eVJlY3MpKSB7XG4gICAgYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuc2V0KGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUoY2FwYWJpbGl0eVN0ciksIGFjY2Vzc1NwZWMpO1xuICB9XG5cbiAgaWYgKCFjYW5QcmluY2lwYWxzTWFuYWdlUmVzb3VyY2VzKGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5KSkge1xuICAgIHRocm93IEVycm9yKCdBdCBsZWFzdCBvbmUgcHJpbmNpcGFsIG11c3QgYmUgYWJsZSB0byBhZG1pbmlzdGVyIGFuZCByZWFkLWNvbmZpZyBmb3IgU1FTIHJlc291cmNlcycgK1xuICAgICAgICAgICAgJyBzbyBkYXRhIHJlbWFpbnMgYWNjZXNzaWJsZTsgZm91bmQ6XFxuJyArXG4gICAgICAgICAgICBgYWRtaW5pc3Rlci1yZXNvdXJjZTogJyR7YWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuZ2V0KEFjY2Vzc0NhcGFiaWxpdHkuQURNSU5JU1RFUl9SRVNPVVJDRSk/LmFsbG93UHJpbmNpcGFsQXJuc30nXFxuYCArXG4gICAgICAgICAgICBgcmVhZC1jb25maWc6ICcke2FjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LmdldChBY2Nlc3NDYXBhYmlsaXR5LlJFQURfQ09ORklHKT8uYWxsb3dQcmluY2lwYWxBcm5zfSdgLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBhbGxvd1N0YXRlbWVudHMgPSBwb2xpY3lGYWN0b3J5Lm1ha2VBbGxvd1N0YXRlbWVudHMoJ1NRUycsXG4gICAgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyxcbiAgICBBcnJheS5mcm9tKGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LnZhbHVlcygpKSxcbiAgICByZXNvdXJjZUFybnMpO1xuXG4gIGNvbnN0IG1heF9hY3Rpb25zX2luX3N0YXRlbWVudCA9IDc7XG4gIGZvciAobGV0IGFsbG93U3RhdGVtZW50IG9mIGFsbG93U3RhdGVtZW50cykge1xuICAgIC8vU1FTIHJlc291cmNlIHBvbGljeSBoYXMgYSBsaW1pdCBvZiA3IGFjdGlvbnMgcGVyIHN0YXRlbWVudCAoUmVhbGx5KS5cbiAgICAvL0J1dCB5b3UgY2FuIGhhdmUgYXMgbWFueSBzdGF0ZW1lbnRzIGFzIHlvdSB3YW50IHVwIHRvIHRoZSBxdWV1ZSBwb2xpY3kgc2l6ZSBsaW1pdC5cbiAgICAvL1NvLCBpZiBhbiBhbGxvd1N0YXRlbWVudCBoYXMgbW9yZSB0aGFuIDcgYWN0aW9ucyAobGlrZSB0aGUgYWRtaW5pc3Rlci1yZXNvdXJjZSBzdGF0ZW1lbnQgZG9lcyksXG4gICAgLy90aGVuIGNyZWF0ZSBhZGRpdGlvbmFsIHN0YXRlbWVudHMgYW5kIHNwcmVhZCB0aGUgb3JpZ2luYWwgc3RhdGVtZW50J3MgcGVybWlzc2lvbnMgYWNyb3NzIHRoZW1cbiAgICBpZiAoYWxsb3dTdGF0ZW1lbnQuYWN0aW9ucy5sZW5ndGggPiBtYXhfYWN0aW9uc19pbl9zdGF0ZW1lbnQpIHtcbiAgICAgIGNvbnN0IHBhcnRpdGlvbmVkQWN0aW9ucyA9IHBhcnRpdGlvbkFycmF5KGFsbG93U3RhdGVtZW50LmFjdGlvbnMsIG1heF9hY3Rpb25zX2luX3N0YXRlbWVudCk7XG4gICAgICBwYXJ0aXRpb25lZEFjdGlvbnMuZm9yRWFjaCgoYWN0aW9ucywgaW5kZXgpID0+IHtcbiAgICAgICAgY29uc3QgbmV3U3RhdGVtZW50ID0gYWxsb3dTdGF0ZW1lbnQuY29weSh7XG4gICAgICAgICAgc2lkOiBgJHthbGxvd1N0YXRlbWVudC5zaWR9ICR7aW5kZXggKyAxfWAsXG4gICAgICAgICAgYWN0aW9uczogYWN0aW9ucyxcbiAgICAgICAgfSk7XG4gICAgICAgIHBvbGljeS5hZGRTdGF0ZW1lbnRzKG5ld1N0YXRlbWVudCk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcG9saWN5LmFkZFN0YXRlbWVudHMoYWxsb3dTdGF0ZW1lbnQpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQgPSBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICBzaWQ6IFNJRF9ERU5ZX0VWRVJZT05FX0VMU0UsXG4gICAgZWZmZWN0OiBFZmZlY3QuREVOWSxcbiAgICBwcmluY2lwYWxzOiBwb2xpY3lGYWN0b3J5Lm1ha2VEZW55RXZlcnlvbmVFbHNlUHJpbmNpcGFscygpLFxuICAgIGFjdGlvbnM6IFsnc3FzOionXSxcbiAgICByZXNvdXJjZXM6IHJlc291cmNlQXJucyxcbiAgfSk7XG4gIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQuYWRkQ29uZGl0aW9uKCdCb29sJywge1xuICAgICdhd3M6UHJpbmNpcGFsSXNBV1NTZXJ2aWNlJzogWydmYWxzZSddLFxuICB9KTtcbiAgY29uc3QgZGVueUV2ZXJ5b25lRWxzZVRlc3QgPSBwb2xpY3lGYWN0b3J5Lndhc0xpa2VVc2VkKHByb3BzLms5RGVzaXJlZEFjY2VzcykgP1xuICAgICdBcm5Ob3RMaWtlJyA6XG4gICAgJ0Fybk5vdEVxdWFscyc7XG4gIGNvbnN0IGFsbEFsbG93ZWRQcmluY2lwYWxBcm5zID0gcG9saWN5RmFjdG9yeS5nZXRBbGxvd2VkUHJpbmNpcGFsQXJucyhwcm9wcy5rOURlc2lyZWRBY2Nlc3MpO1xuICBjb25zdCBhY2NvdW50Um9vdFByaW5jaXBhbCA9IG5ldyBBY2NvdW50Um9vdFByaW5jaXBhbCgpO1xuICBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50LmFkZENvbmRpdGlvbihkZW55RXZlcnlvbmVFbHNlVGVzdCwge1xuICAgICdhd3M6UHJpbmNpcGFsQXJuJzogW1xuICAgICAgLy8gUGxhY2UgUm9vdCBQcmluY2lwYWwgYXJuIGluIHN0YWJsZSwgcHJvbWluZW50IHBvc2l0aW9uO1xuICAgICAgLy8gd2lsbCByZW5kZXIgYXMgYW4gb2JqZWN0IEZuOjpKb2luJ2luZyBQYXJ0aXRpb24gJiBBY2NvdW50SWRcbiAgICAgIGFjY291bnRSb290UHJpbmNpcGFsLmFybixcbiAgICAgIC4uLmFsbEFsbG93ZWRQcmluY2lwYWxBcm5zLFxuICAgIF0sXG4gIH0pO1xuXG4gIHBvbGljeS5hZGRTdGF0ZW1lbnRzKFxuICAgIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQsXG4gICk7XG5cbiAgY29uc3QgZGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQgPSBwb2xpY3lGYWN0b3J5Ll9tYWtlRGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQoXG4gICAgJ1NRUycsIFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsIGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LCByZXNvdXJjZUFybnMpO1xuICBpZiAoZGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQpIHtcbiAgICBwb2xpY3kuYWRkU3RhdGVtZW50cyhkZW55VW50cnVzdGVkT3Jnc1N0YXRlbWVudCk7XG4gIH1cblxuICBwb2xpY3kudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIHJldHVybiBwb2xpY3k7XG59XG5cbi8qKlxuICogR3JhbnQgYWNjZXNzIHRvIGEgcXVldWUgdmlhIHJlc291cmNlIHBvbGljeSB1c2luZyBrOSBJQWNjZXNzU3BlYyBkZWZpbml0aW9ucy4gVGhpcyBmdW5jdGlvblxuICogaXMgdGhlIHByZWZlcnJlZCBpbnRlcmZhY2UgZm9yIGdyYW50aW5nIGFjY2VzcyB0byBhIHF1ZXVlLlxuICpcbiAqIFRoZSBncmFudCBhbmQgbWFrZSBvcGVyYXRpb25zIGFyZSBzcGxpdCBiZWNhdXNlIFNRUyBwb2xpY2llcyBjYW4gb25seSBiZSBtYW5hZ2VkIHZpYSB0aGVcbiAqIElRdWV1ZS5hZGRUb1Jlc291cmNlUG9saWN5IG1ldGhvZCBidXQgSVF1ZXVlIGRvZXMgbm90IG9mZmVyIGEgd2F5IHRvIHJlYWQgdGhlIHBvbGljeS5cbiAqIFNvIG1ha2luZyB0aGUgcG9saWN5IGlzIGRvbmUgaW4gYSBzZXBhcmF0ZSBmdW5jdGlvbiBzbyBwb2xpY3kgZ2VuZXJhdGlvbiBjYW4gYmUgdGVzdGVkLlxuICpcbiAqIEBwYXJhbSBwcm9wcyBzcGVjaWZ5aW5nIHRoZSBxdWV1ZSBhbmQgZGVzaXJlZCBhY2Nlc3NcbiAqXG4gKiBAcmV0dXJuIHRoZSByZXN1bHRzIGZvciBhZGRpbmcgZWFjaCBzdGF0ZW1lbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyYW50QWNjZXNzVmlhUmVzb3VyY2VQb2xpY3kocHJvcHM6IEs5U1FTUmVzb3VyY2VQb2xpY3lQcm9wcyk6XG5BZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0W10ge1xuICBjb25zdCByZXNvdXJjZVBvbGljeSA9IG1ha2VSZXNvdXJjZVBvbGljeShwcm9wcyk7XG5cbiAgcmVzb3VyY2VQb2xpY3kudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIGNvbnN0IHBvbGljeUpzb24gPSByZXNvdXJjZVBvbGljeS50b0pTT04oKTtcbiAgY29uc3QgazlTdGF0ZW1lbnRzID0gcG9saWN5SnNvbi5TdGF0ZW1lbnQ7XG4gIGNvbnN0IHF1ZXVlID0gcHJvcHMucXVldWU7XG4gIGNvbnN0IGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHRzID0gbmV3IEFycmF5PEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQ+KCk7XG5cbiAgZm9yIChsZXQgc3RhdGVtZW50IG9mIGs5U3RhdGVtZW50cykge1xuICAgIGxldCBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0ID0gcXVldWUuYWRkVG9SZXNvdXJjZVBvbGljeShcbiAgICAgIFBvbGljeVN0YXRlbWVudC5mcm9tSnNvbihzdGF0ZW1lbnQpLFxuICAgICk7XG4gICAgYWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdHMucHVzaChhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0KTtcbiAgfVxuXG4gIHJldHVybiBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0cztcbn1cbiJdfQ==