UNPKG

@k9securityio/k9-cdk

Version:

Provision strong AWS security policies easily using the AWS CDK.

198 lines 32.4 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.CloudFrontOACReadAccessGenerator = exports.SID_ALLOW_PUBLIC_READ_ACCESS = exports.SID_DENY_UNENCRYPTED_STORAGE = exports.SID_DENY_UNEXPECTED_ENCRYPTION_METHOD = void 0; exports.grantAccessViaResourcePolicy = grantAccessViaResourcePolicy; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const s3 = require("aws-cdk-lib/aws-s3"); const aws_s3_1 = require("aws-cdk-lib/aws-s3"); const aws_iam_utils = require("./aws-iam-utils"); 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_UNEXPECTED_ENCRYPTION_METHOD = 'DenyUnexpectedEncryptionMethod'; exports.SID_DENY_UNENCRYPTED_STORAGE = 'DenyUnencryptedStorage'; exports.SID_ALLOW_PUBLIC_READ_ACCESS = 'AllowPublicReadAccess'; class CloudFrontOACReadAccessGenerator { constructor(bucket, distributionArn) { this.bucket = bucket; this.distributionArn = distributionArn; } makeAllowStatements() { return [new aws_iam_1.PolicyStatement({ sid: CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_OAC_READ_ACCESS, effect: aws_iam_1.Effect.ALLOW, principals: [new aws_iam_1.ServicePrincipal('cloudfront.amazonaws.com')], actions: ['s3:GetObject'], resources: [`${this.bucket.arnForObjects('*')}`], conditions: { StringEquals: { 'aws:SourceArn': this.distributionArn }, }, })]; } makeConditionsToExceptFromDenyEveryoneElse() { // return a (TypeScript) Record of the form: // {"Operator": { "keyInRequestContext": "value" } } return { StringNotEqualsIfExists: { 'aws:PrincipalServiceName': 'cloudfront.amazonaws.com' } }; } } exports.CloudFrontOACReadAccessGenerator = CloudFrontOACReadAccessGenerator; _a = JSII_RTTI_SYMBOL_1; CloudFrontOACReadAccessGenerator[_a] = { fqn: "@k9securityio/k9-cdk.s3.CloudFrontOACReadAccessGenerator", version: "2.2.1" }; CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_OAC_READ_ACCESS = 'AllowCloudFrontOACReadAccess'; /** * Grants least-privilege access to a bucket by generating a BucketPolicy from the access capabilities * described by `props`; the policy will be set on the Bucket specified in `props`. * * When a BucketPolicy already exists on the Bucket referenced in `props`: * * the BucketPolicy's existing Statements will pass through unmodified * * k9 will identify IAM principals there were allowed by the original policy and add those principals to * the `DenyEveryoneElse` Statement's exclusion list so that, e.g. autoDeleteObjects works as expected * * k9's Allow and Deny statements will be added to the policy * * @remarks * * k9 modifies the existing BucketPolicy in place instead of replacing or copying and modifying that * to preserve dependency references created by certain S3 CDK features such as `autoDeleteObjects`. * * @param scope The scope in which to define this construct. * @param id The scoped construct ID. * @param props describing the desired access capabilities for the bucket * * @return an array of AddToResourcePolicyResult */ function grantAccessViaResourcePolicy(scope, id, props) { const policyFactory = new k9policy_1.K9PolicyFactory(); // If the bucket already has a policy, use it. Maintaining the existing policy instance // is important because other CDK features like S3 autoDeleteObjects may have expressed dependencies // on that instance which must be maintained. if (!props.bucket.policy) { props.bucket.policy = new s3.BucketPolicy(scope, `${id}Policy`, { bucket: props.bucket }); } const policy = props.bucket.policy; const addToResourcePolicyResults = new Array(); let resourceArns = [ `${props.bucket.bucketArn}`, `${props.bucket.arnForObjects('*')}`, ]; // Capture the principals that were allowed prior to modifying policy // One could argue this can be done at the end because we're going to // narrow the DenyEveryoneElse to the unique set of allowed principals. // Record here for now to preserve ability to generate fine-grained DenyEveryoneElse-$capability statements. const origAllowedAWSPrincipals = aws_iam_utils.getAllowedPrincipalArns(policy.document); // Make Allow Statements const k9Statements = policyFactory.makeAllowStatements('S3', SUPPORTED_CAPABILITIES, props.k9DesiredAccess, resourceArns); if (props.publicReadAccess) { k9Statements.unshift(// very important statement; put at beginning. new aws_iam_1.PolicyStatement({ sid: exports.SID_ALLOW_PUBLIC_READ_ACCESS, effect: aws_iam_1.Effect.ALLOW, principals: [new aws_iam_1.AnyPrincipal()], actions: ['s3:GetObject'], resources: [`${props.bucket.arnForObjects('*')}`], })); } if (props.awsServiceAccessGenerators) { for (let serviceAccessSpec of props.awsServiceAccessGenerators) { let allowStatements = serviceAccessSpec.makeAllowStatements(); k9Statements.unshift(...allowStatements); } } // Make Deny Statement const denyEveryoneElseTest = policyFactory.wasLikeUsed(props.k9DesiredAccess) ? 'ArnNotLike' : 'ArnNotEquals'; let denyEveryoneElseStatement; if (props.publicReadAccess) { denyEveryoneElseStatement = new aws_iam_1.PolicyStatement({ sid: 'DenyEveryoneElse', effect: aws_iam_1.Effect.DENY, principals: policyFactory.makeDenyEveryoneElsePrincipals(), notActions: ['s3:GetObject'], resources: resourceArns, }); } else { denyEveryoneElseStatement = new aws_iam_1.PolicyStatement({ sid: 'DenyEveryoneElse', effect: aws_iam_1.Effect.DENY, principals: policyFactory.makeDenyEveryoneElsePrincipals(), actions: ['s3:*'], resources: resourceArns, }); } const allAllowedPrincipalArns = new Set(policyFactory.getAllowedPrincipalArns(props.k9DesiredAccess)); for (let origAWSPrincipal of origAllowedAWSPrincipals) { allAllowedPrincipalArns.add(origAWSPrincipal); } denyEveryoneElseStatement.addCondition(denyEveryoneElseTest, { 'aws:PrincipalArn': [...allAllowedPrincipalArns] }); if (props.awsServiceAccessGenerators) { for (let serviceAccessSpec of props.awsServiceAccessGenerators) { let conditionsToExceptFromDenyEveryoneElse = serviceAccessSpec.makeConditionsToExceptFromDenyEveryoneElse(); let conditionOps = Object.keys(conditionsToExceptFromDenyEveryoneElse); for (let conditionOp of conditionOps) { // note: when you call PolicyStatement#addCondition with the same conditionOp (e.g. StringEquals) // multiple times, addCondition will collect the values into an array. // c.f. https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-iam/lib/policy-statement.ts#L364 denyEveryoneElseStatement.addCondition(conditionOp, conditionsToExceptFromDenyEveryoneElse[conditionOp]); } } } // default encryption method to SSE-KMS, // allow override to SSE-S3 (AES256) let encryptionMethod = 'aws:kms'; if (props.encryption) { if (aws_s3_1.BucketEncryption.S3_MANAGED == props.encryption) { encryptionMethod = 'AES256'; } } k9Statements.push(new aws_iam_1.PolicyStatement({ sid: 'DenyInsecureCommunications', effect: aws_iam_1.Effect.DENY, principals: [new aws_iam_1.AnyPrincipal()], actions: ['s3:*'], resources: resourceArns, conditions: { Bool: { 'aws:SecureTransport': false }, }, })); if (props.enforceEncryptionAtRest ?? true) { k9Statements.push(new aws_iam_1.PolicyStatement({ sid: exports.SID_DENY_UNENCRYPTED_STORAGE, effect: aws_iam_1.Effect.DENY, principals: [new aws_iam_1.AnyPrincipal()], actions: ['s3:PutObject', 's3:ReplicateObject'], resources: resourceArns, conditions: { Null: { 's3:x-amz-server-side-encryption': true }, }, }), new aws_iam_1.PolicyStatement({ sid: exports.SID_DENY_UNEXPECTED_ENCRYPTION_METHOD, effect: aws_iam_1.Effect.DENY, principals: [new aws_iam_1.AnyPrincipal()], actions: ['s3:PutObject', 's3:ReplicateObject'], resources: resourceArns, conditions: { StringNotEquals: { 's3:x-amz-server-side-encryption': encryptionMethod }, }, })); } k9Statements.push(denyEveryoneElseStatement); // Build accessSpecsByCapability map for DenyUntrustedOrgs const accessSpecsByCapabilityRecs = policyFactory.mergeDesiredAccessSpecsByCapability(SUPPORTED_CAPABILITIES, props.k9DesiredAccess); const accessSpecsByCapability = new Map(); for (let [capabilityStr, accessSpec] of Object.entries(accessSpecsByCapabilityRecs)) { accessSpecsByCapability.set((0, k9policy_1.getAccessCapabilityFromValue)(capabilityStr), accessSpec); } const denyUntrustedOrgsStatement = policyFactory._makeDenyUntrustedOrgsStatement('S3', SUPPORTED_CAPABILITIES, accessSpecsByCapability, resourceArns); if (denyUntrustedOrgsStatement) { k9Statements.push(denyUntrustedOrgsStatement); } for (let statement of k9Statements) { let addToResourcePolicyResult = props.bucket.addToResourcePolicy(statement); addToResourcePolicyResults.push(addToResourcePolicyResult); } policy.document.validateForResourcePolicy(); return addToResourcePolicyResults; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvczMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQXdIQSxvRUErSkM7O0FBdlJELGlEQU82QjtBQUM3Qix5Q0FBeUM7QUFDekMsK0NBQStEO0FBRS9ELGlEQUFpRDtBQUNqRCx5Q0FBc0k7QUEyQ3RJLElBQUksc0JBQXNCLEdBQUcsSUFBSSxLQUFLLENBQ3BDLDJCQUFnQixDQUFDLG1CQUFtQixFQUNwQywyQkFBZ0IsQ0FBQyxXQUFXLEVBQzVCLDJCQUFnQixDQUFDLFNBQVMsRUFDMUIsMkJBQWdCLENBQUMsVUFBVSxFQUMzQiwyQkFBZ0IsQ0FBQyxXQUFXLENBQzdCLENBQUM7QUFFVyxRQUFBLHFDQUFxQyxHQUFHLGdDQUFnQyxDQUFDO0FBQ3pFLFFBQUEsNEJBQTRCLEdBQUcsd0JBQXdCLENBQUM7QUFDeEQsUUFBQSw0QkFBNEIsR0FBRyx1QkFBdUIsQ0FBQztBQUVwRSxNQUFhLGdDQUFnQztJQU8zQyxZQUFZLE1BQWUsRUFBRSxlQUF1QjtRQUNsRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztJQUN6QyxDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLE9BQU8sQ0FBQyxJQUFJLHlCQUFlLENBQUM7Z0JBQzFCLEdBQUcsRUFBRSxnQ0FBZ0MsQ0FBQyxvQ0FBb0M7Z0JBQzFFLE1BQU0sRUFBRSxnQkFBTSxDQUFDLEtBQUs7Z0JBQ3BCLFVBQVUsRUFBRSxDQUFDLElBQUksMEJBQWdCLENBQUMsMEJBQTBCLENBQUMsQ0FBQztnQkFDOUQsT0FBTyxFQUFFLENBQUMsY0FBYyxDQUFDO2dCQUN6QixTQUFTLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hELFVBQVUsRUFBRTtvQkFDVixZQUFZLEVBQUUsRUFBRSxlQUFlLEVBQUUsSUFB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UUFDbkMsSUFBSSx5QkFBeUIsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzVFLDBCQUEwQixDQUFDLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxNQUFNLENBQUMsUUFBUSxDQUFDLHlCQUF5QixFQUFFLENBQUM7SUFFNUMsT0FBTywwQkFBMEIsQ0FBQztBQUNwQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdCxcbiAgQW55UHJpbmNpcGFsLFxuICBDb25kaXRpb25zLFxuICBFZmZlY3QsXG4gIFBvbGljeVN0YXRlbWVudCxcbiAgU2VydmljZVByaW5jaXBhbCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBzMyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMnO1xuaW1wb3J0IHsgSUJ1Y2tldCwgQnVja2V0RW5jcnlwdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBJQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgKiBhcyBhd3NfaWFtX3V0aWxzIGZyb20gJy4vYXdzLWlhbS11dGlscyc7XG5pbXBvcnQgeyBBY2Nlc3NDYXBhYmlsaXR5LCBnZXRBY2Nlc3NDYXBhYmlsaXR5RnJvbVZhbHVlLCBJQWNjZXNzU3BlYywgSUFXU1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3IsIEs5UG9saWN5RmFjdG9yeSB9IGZyb20gJy4vazlwb2xpY3knO1xuXG4vKipcbiAqIENvbmZpZ3VyZSB0aGUgazkgU2VjdXJpdHkgUzMgQnVja2V0IHBvbGljeSBnZW5lcmF0b3Igd2l0aCB0aGUgSzlCdWNrZXRQb2xpY3lQcm9wcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBLOUJ1Y2tldFBvbGljeVByb3BzIGV4dGVuZHMgczMuQnVja2V0UG9saWN5UHJvcHMge1xuICAvKipcbiAgICogQW4gYXJyYXkgb2YgSUFjY2Vzc1NwZWMgZGVmaW5pbmcgdGhlIGRlc2lyZWQgYWNjZXNzLiAgVGhlIHBvbGljeVxuICAgKiBnZW5lcmF0b3Igd2lsbCBjb21iaW5lIGFuZCBub3JtYWxpemUgb3ZlcmxhcHBpbmcgYWNjZXNzIHNwZWNzLlxuICAgKi9cbiAgcmVhZG9ubHkgazlEZXNpcmVkQWNjZXNzOiBBcnJheTxJQWNjZXNzU3BlYz47XG5cbiAgLyoqXG4gICAqIChPcHRpb25hbGx5KSBQcm92aWRlIHRoZSBCdWNrZXRFbmNyeXB0aW9uIG9iamVjdCBmb3IgdGhlIEJ1Y2tldCB0b1xuICAgKiBhbGxvdyB0aGUgcG9saWN5IGdlbmVyYXRvciB0byBjdXN0b21pemUgdGhlIHBvbGljeSBmb3IgdGhlIEJ1Y2tldCdzXG4gICAqIGNvbmZpZ3VyYXRpb24gd2l0aG91dCBoYW5kbGluZywgZS5nLiB0aGUgZW5jcnlwdGlvbiBtZXRob2Qgb3B0aW9ucyBkaXJlY3RseVxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbj86IEJ1Y2tldEVuY3J5cHRpb247XG5cbiAgLyoqXG4gICAqIEVuZm9yY2UgZW5jcnlwdGlvbiBhdCByZXN0IHdpdGggcG9saWN5IGNvbmRpdGlvbnMuICBUaGUgcG9saWN5IHdpbGwgdXNlXG4gICAqIHRoZSBlbmNyeXB0aW9uIG1ldGhvZCBkZWZpbmVkIGJ5IHRoZSBlbmNyeXB0aW9uIHByb3BlcnR5IG9yIGRlZmF1bHQgdG8gYGF3czprbXNgLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBlbmZvcmNlRW5jcnlwdGlvbkF0UmVzdD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFsbG93IHB1YmxpYyByZWFkIGFjY2VzcyB0byB0aGUgYnVja2V0LlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcHVibGljUmVhZEFjY2Vzcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFuIChvcHRpb25hbCkgYXJyYXkgb2YgSUFXU1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3IgaW5zdGFuY2VzIHdoaWNoIHdpbGwgZ2VuZXJhdGUgc3RhdGVtZW50cyB0byBhbGxvdyBhY2Nlc3MgdG8gdGhlXG4gICAqIGJ1Y2tldCBvciBidWNrZXQgb2JqZWN0KHMpIGJ5IGFuIEFXUyBzZXJ2aWNlIGxpa2UgQ2xvdWRGcm9udCBvciBLaW5lc2lzLlxuICAgKlxuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcbiAgICovXG4gIHJlYWRvbmx5IGF3c1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3JzPzogQXJyYXk8SUFXU1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3I+O1xufVxuXG5sZXQgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyA9IG5ldyBBcnJheTxBY2Nlc3NDYXBhYmlsaXR5PihcbiAgQWNjZXNzQ2FwYWJpbGl0eS5BRE1JTklTVEVSX1JFU09VUkNFLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfQ09ORklHLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfREFUQSxcbiAgQWNjZXNzQ2FwYWJpbGl0eS5XUklURV9EQVRBLFxuICBBY2Nlc3NDYXBhYmlsaXR5LkRFTEVURV9EQVRBLFxuKTtcblxuZXhwb3J0IGNvbnN0IFNJRF9ERU5ZX1VORVhQRUNURURfRU5DUllQVElPTl9NRVRIT0QgPSAnRGVueVVuZXhwZWN0ZWRFbmNyeXB0aW9uTWV0aG9kJztcbmV4cG9ydCBjb25zdCBTSURfREVOWV9VTkVOQ1JZUFRFRF9TVE9SQUdFID0gJ0RlbnlVbmVuY3J5cHRlZFN0b3JhZ2UnO1xuZXhwb3J0IGNvbnN0IFNJRF9BTExPV19QVUJMSUNfUkVBRF9BQ0NFU1MgPSAnQWxsb3dQdWJsaWNSZWFkQWNjZXNzJztcblxuZXhwb3J0IGNsYXNzIENsb3VkRnJvbnRPQUNSZWFkQWNjZXNzR2VuZXJhdG9yIGltcGxlbWVudHMgSUFXU1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3Ige1xuXG4gIHN0YXRpYyByZWFkb25seSBTSURfQUxMT1dfQ0xPVURGUk9OVF9PQUNfUkVBRF9BQ0NFU1MgPSAnQWxsb3dDbG91ZEZyb250T0FDUmVhZEFjY2Vzcyc7XG5cbiAgcmVhZG9ubHkgYnVja2V0OiBJQnVja2V0O1xuICByZWFkb25seSBkaXN0cmlidXRpb25Bcm46IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihidWNrZXQ6IElCdWNrZXQsIGRpc3RyaWJ1dGlvbkFybjogc3RyaW5nKSB7XG4gICAgdGhpcy5idWNrZXQgPSBidWNrZXQ7XG4gICAgdGhpcy5kaXN0cmlidXRpb25Bcm4gPSBkaXN0cmlidXRpb25Bcm47XG4gIH1cblxuICBtYWtlQWxsb3dTdGF0ZW1lbnRzKCk6IEFycmF5PFBvbGljeVN0YXRlbWVudD4ge1xuICAgIHJldHVybiBbbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICBzaWQ6IENsb3VkRnJvbnRPQUNSZWFkQWNjZXNzR2VuZXJhdG9yLlNJRF9BTExPV19DTE9VREZST05UX09BQ19SRUFEX0FDQ0VTUyxcbiAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgcHJpbmNpcGFsczogW25ldyBTZXJ2aWNlUHJpbmNpcGFsKCdjbG91ZGZyb250LmFtYXpvbmF3cy5jb20nKV0sXG4gICAgICBhY3Rpb25zOiBbJ3MzOkdldE9iamVjdCddLFxuICAgICAgcmVzb3VyY2VzOiBbYCR7dGhpcy5idWNrZXQuYXJuRm9yT2JqZWN0cygnKicpfWBdLFxuICAgICAgY29uZGl0aW9uczoge1xuICAgICAgICBTdHJpbmdFcXVhbHM6IHsgJ2F3czpTb3VyY2VBcm4nOiB0aGlzLmRpc3RyaWJ1dGlvbkFybiB9LFxuICAgICAgfSxcbiAgICB9KV07XG4gIH1cblxuICBtYWtlQ29uZGl0aW9uc1RvRXhjZXB0RnJvbURlbnlFdmVyeW9uZUVsc2UoKTogQ29uZGl0aW9ucyB7XG4gICAgLy8gcmV0dXJuIGEgKFR5cGVTY3JpcHQpIFJlY29yZCBvZiB0aGUgZm9ybTpcbiAgICAvLyAgICAge1wiT3BlcmF0b3JcIjogeyBcImtleUluUmVxdWVzdENvbnRleHRcIjogXCJ2YWx1ZVwiIH0gfVxuICAgIHJldHVybiB7IFN0cmluZ05vdEVxdWFsc0lmRXhpc3RzOiB7ICdhd3M6UHJpbmNpcGFsU2VydmljZU5hbWUnOiAnY2xvdWRmcm9udC5hbWF6b25hd3MuY29tJyB9IH07XG4gIH1cbn1cblxuLyoqXG4gKiBHcmFudHMgbGVhc3QtcHJpdmlsZWdlIGFjY2VzcyB0byBhIGJ1Y2tldCBieSBnZW5lcmF0aW5nIGEgQnVja2V0UG9saWN5IGZyb20gdGhlIGFjY2VzcyBjYXBhYmlsaXRpZXNcbiAqIGRlc2NyaWJlZCBieSBgcHJvcHNgOyB0aGUgcG9saWN5IHdpbGwgYmUgc2V0IG9uIHRoZSBCdWNrZXQgc3BlY2lmaWVkIGluIGBwcm9wc2AuXG4gKlxuICogV2hlbiBhIEJ1Y2tldFBvbGljeSBhbHJlYWR5IGV4aXN0cyBvbiB0aGUgQnVja2V0IHJlZmVyZW5jZWQgaW4gYHByb3BzYDpcbiAqICAgKiB0aGUgQnVja2V0UG9saWN5J3MgZXhpc3RpbmcgU3RhdGVtZW50cyB3aWxsIHBhc3MgdGhyb3VnaCB1bm1vZGlmaWVkXG4gKiAgICogazkgd2lsbCBpZGVudGlmeSBJQU0gcHJpbmNpcGFscyB0aGVyZSB3ZXJlIGFsbG93ZWQgYnkgdGhlIG9yaWdpbmFsIHBvbGljeSBhbmQgYWRkIHRob3NlIHByaW5jaXBhbHMgdG9cbiAqICAgdGhlIGBEZW55RXZlcnlvbmVFbHNlYCBTdGF0ZW1lbnQncyBleGNsdXNpb24gbGlzdCBzbyB0aGF0LCBlLmcuIGF1dG9EZWxldGVPYmplY3RzIHdvcmtzIGFzIGV4cGVjdGVkXG4gKiAgICogazkncyBBbGxvdyBhbmQgRGVueSBzdGF0ZW1lbnRzIHdpbGwgYmUgYWRkZWQgdG8gdGhlIHBvbGljeVxuICpcbiAqIEByZW1hcmtzXG4gKlxuICogazkgbW9kaWZpZXMgdGhlIGV4aXN0aW5nIEJ1Y2tldFBvbGljeSBpbiBwbGFjZSBpbnN0ZWFkIG9mIHJlcGxhY2luZyBvciBjb3B5aW5nIGFuZCBtb2RpZnlpbmcgdGhhdFxuICogdG8gcHJlc2VydmUgZGVwZW5kZW5jeSByZWZlcmVuY2VzIGNyZWF0ZWQgYnkgY2VydGFpbiBTMyBDREsgZmVhdHVyZXMgc3VjaCBhcyBgYXV0b0RlbGV0ZU9iamVjdHNgLlxuICpcbiAqIEBwYXJhbSBzY29wZSBUaGUgc2NvcGUgaW4gd2hpY2ggdG8gZGVmaW5lIHRoaXMgY29uc3RydWN0LlxuICogQHBhcmFtIGlkIFRoZSBzY29wZWQgY29uc3RydWN0IElELlxuICogQHBhcmFtIHByb3BzIGRlc2NyaWJpbmcgdGhlIGRlc2lyZWQgYWNjZXNzIGNhcGFiaWxpdGllcyBmb3IgdGhlIGJ1Y2tldFxuICpcbiAqIEByZXR1cm4gYW4gYXJyYXkgb2YgQWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ3JhbnRBY2Nlc3NWaWFSZXNvdXJjZVBvbGljeShzY29wZTogSUNvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEs5QnVja2V0UG9saWN5UHJvcHMpOiBBZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0W10ge1xuICBjb25zdCBwb2xpY3lGYWN0b3J5ID0gbmV3IEs5UG9saWN5RmFjdG9yeSgpO1xuICAvLyBJZiB0aGUgYnVja2V0IGFscmVhZHkgaGFzIGEgcG9saWN5LCB1c2UgaXQuICBNYWludGFpbmluZyB0aGUgZXhpc3RpbmcgcG9saWN5IGluc3RhbmNlXG4gIC8vIGlzIGltcG9ydGFudCBiZWNhdXNlIG90aGVyIENESyBmZWF0dXJlcyBsaWtlIFMzIGF1dG9EZWxldGVPYmplY3RzIG1heSBoYXZlIGV4cHJlc3NlZCBkZXBlbmRlbmNpZXNcbiAgLy8gb24gdGhhdCBpbnN0YW5jZSB3aGljaCBtdXN0IGJlIG1haW50YWluZWQuXG4gIGlmICghcHJvcHMuYnVja2V0LnBvbGljeSkge1xuICAgIHByb3BzLmJ1Y2tldC5wb2xpY3kgPSBuZXcgczMuQnVja2V0UG9saWN5KHNjb3BlLCBgJHtpZH1Qb2xpY3lgLCB7IGJ1Y2tldDogcHJvcHMuYnVja2V0IH0pO1xuICB9XG4gIGNvbnN0IHBvbGljeSA9IHByb3BzLmJ1Y2tldC5wb2xpY3k7XG5cbiAgY29uc3QgYWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdHMgPSBuZXcgQXJyYXk8QWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdD4oKTtcbiAgbGV0IHJlc291cmNlQXJucyA9IFtcbiAgICBgJHtwcm9wcy5idWNrZXQuYnVja2V0QXJufWAsXG4gICAgYCR7cHJvcHMuYnVja2V0LmFybkZvck9iamVjdHMoJyonKX1gLFxuICBdO1xuXG4gIC8vIENhcHR1cmUgdGhlIHByaW5jaXBhbHMgdGhhdCB3ZXJlIGFsbG93ZWQgcHJpb3IgdG8gbW9kaWZ5aW5nIHBvbGljeVxuICAvLyBPbmUgY291bGQgYXJndWUgdGhpcyBjYW4gYmUgZG9uZSBhdCB0aGUgZW5kIGJlY2F1c2Ugd2UncmUgZ29pbmcgdG9cbiAgLy8gbmFycm93IHRoZSBEZW55RXZlcnlvbmVFbHNlIHRvIHRoZSB1bmlxdWUgc2V0IG9mIGFsbG93ZWQgcHJpbmNpcGFscy5cbiAgLy8gUmVjb3JkIGhlcmUgZm9yIG5vdyB0byBwcmVzZXJ2ZSBhYmlsaXR5IHRvIGdlbmVyYXRlIGZpbmUtZ3JhaW5lZCBEZW55RXZlcnlvbmVFbHNlLSRjYXBhYmlsaXR5IHN0YXRlbWVudHMuXG4gIGNvbnN0IG9yaWdBbGxvd2VkQVdTUHJpbmNpcGFscyA9IGF3c19pYW1fdXRpbHMuZ2V0QWxsb3dlZFByaW5jaXBhbEFybnMocG9saWN5LmRvY3VtZW50KTtcblxuICAvLyBNYWtlIEFsbG93IFN0YXRlbWVudHNcbiAgY29uc3QgazlTdGF0ZW1lbnRzID0gcG9saWN5RmFjdG9yeS5tYWtlQWxsb3dTdGF0ZW1lbnRzKCdTMycsXG4gICAgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyxcbiAgICBwcm9wcy5rOURlc2lyZWRBY2Nlc3MsXG4gICAgcmVzb3VyY2VBcm5zKTtcblxuICBpZiAocHJvcHMucHVibGljUmVhZEFjY2Vzcykge1xuICAgIGs5U3RhdGVtZW50cy51bnNoaWZ0KCAvLyB2ZXJ5IGltcG9ydGFudCBzdGF0ZW1lbnQ7IHB1dCBhdCBiZWdpbm5pbmcuXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgc2lkOiBTSURfQUxMT1dfUFVCTElDX1JFQURfQUNDRVNTLFxuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgcHJpbmNpcGFsczogW25ldyBBbnlQcmluY2lwYWwoKV0sXG4gICAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0J10sXG4gICAgICAgIHJlc291cmNlczogW2Ake3Byb3BzLmJ1Y2tldC5hcm5Gb3JPYmplY3RzKCcqJyl9YF0sXG4gICAgICB9KSxcbiAgICApO1xuICB9XG5cbiAgaWYgKHByb3BzLmF3c1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3JzKSB7XG4gICAgZm9yIChsZXQgc2VydmljZUFjY2Vzc1NwZWMgb2YgcHJvcHMuYXdzU2VydmljZUFjY2Vzc0dlbmVyYXRvcnMpIHtcbiAgICAgIGxldCBhbGxvd1N0YXRlbWVudHM6QXJyYXk8UG9saWN5U3RhdGVtZW50PiA9IHNlcnZpY2VBY2Nlc3NTcGVjLm1ha2VBbGxvd1N0YXRlbWVudHMoKTtcbiAgICAgIGs5U3RhdGVtZW50cy51bnNoaWZ0KC4uLmFsbG93U3RhdGVtZW50cyk7XG4gICAgfVxuICB9XG5cbiAgLy8gTWFrZSBEZW55IFN0YXRlbWVudFxuICBjb25zdCBkZW55RXZlcnlvbmVFbHNlVGVzdCA9IHBvbGljeUZhY3Rvcnkud2FzTGlrZVVzZWQocHJvcHMuazlEZXNpcmVkQWNjZXNzKSA/XG4gICAgJ0Fybk5vdExpa2UnIDpcbiAgICAnQXJuTm90RXF1YWxzJztcbiAgbGV0IGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQ6IFBvbGljeVN0YXRlbWVudDtcblxuICBpZiAocHJvcHMucHVibGljUmVhZEFjY2Vzcykge1xuICAgIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQgPSBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIHNpZDogJ0RlbnlFdmVyeW9uZUVsc2UnLFxuICAgICAgZWZmZWN0OiBFZmZlY3QuREVOWSxcbiAgICAgIHByaW5jaXBhbHM6IHBvbGljeUZhY3RvcnkubWFrZURlbnlFdmVyeW9uZUVsc2VQcmluY2lwYWxzKCksXG4gICAgICBub3RBY3Rpb25zOiBbJ3MzOkdldE9iamVjdCddLFxuICAgICAgcmVzb3VyY2VzOiByZXNvdXJjZUFybnMsXG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgZGVueUV2ZXJ5b25lRWxzZVN0YXRlbWVudCA9IG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgc2lkOiAnRGVueUV2ZXJ5b25lRWxzZScsXG4gICAgICBlZmZlY3Q6IEVmZmVjdC5ERU5ZLFxuICAgICAgcHJpbmNpcGFsczogcG9saWN5RmFjdG9yeS5tYWtlRGVueUV2ZXJ5b25lRWxzZVByaW5jaXBhbHMoKSxcbiAgICAgIGFjdGlvbnM6IFsnczM6KiddLFxuICAgICAgcmVzb3VyY2VzOiByZXNvdXJjZUFybnMsXG4gICAgfSk7XG4gIH1cbiAgY29uc3QgYWxsQWxsb3dlZFByaW5jaXBhbEFybnMgPSBuZXcgU2V0PHN0cmluZz4ocG9saWN5RmFjdG9yeS5nZXRBbGxvd2VkUHJpbmNpcGFsQXJucyhwcm9wcy5rOURlc2lyZWRBY2Nlc3MpKTtcbiAgZm9yIChsZXQgb3JpZ0FXU1ByaW5jaXBhbCBvZiBvcmlnQWxsb3dlZEFXU1ByaW5jaXBhbHMpIHtcbiAgICBhbGxBbGxvd2VkUHJpbmNpcGFsQXJucy5hZGQob3JpZ0FXU1ByaW5jaXBhbCk7XG4gIH1cbiAgZGVueUV2ZXJ5b25lRWxzZVN0YXRlbWVudC5hZGRDb25kaXRpb24oZGVueUV2ZXJ5b25lRWxzZVRlc3QsXG4gICAgeyAnYXdzOlByaW5jaXBhbEFybic6IFsuLi5hbGxBbGxvd2VkUHJpbmNpcGFsQXJuc10gfSk7XG5cbiAgaWYgKHByb3BzLmF3c1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3JzKSB7XG4gICAgZm9yIChsZXQgc2VydmljZUFjY2Vzc1NwZWMgb2YgcHJvcHMuYXdzU2VydmljZUFjY2Vzc0dlbmVyYXRvcnMpIHtcbiAgICAgIGxldCBjb25kaXRpb25zVG9FeGNlcHRGcm9tRGVueUV2ZXJ5b25lRWxzZSA9IHNlcnZpY2VBY2Nlc3NTcGVjLm1ha2VDb25kaXRpb25zVG9FeGNlcHRGcm9tRGVueUV2ZXJ5b25lRWxzZSgpO1xuICAgICAgbGV0IGNvbmRpdGlvbk9wcyA9IE9iamVjdC5rZXlzKGNvbmRpdGlvbnNUb0V4Y2VwdEZyb21EZW55RXZlcnlvbmVFbHNlKSBhcyBBcnJheTxzdHJpbmc+O1xuICAgICAgZm9yIChsZXQgY29uZGl0aW9uT3Agb2YgY29uZGl0aW9uT3BzKSB7XG4gICAgICAgIC8vIG5vdGU6IHdoZW4geW91IGNhbGwgUG9saWN5U3RhdGVtZW50I2FkZENvbmRpdGlvbiB3aXRoIHRoZSBzYW1lIGNvbmRpdGlvbk9wIChlLmcuIFN0cmluZ0VxdWFscylcbiAgICAgICAgLy8gbXVsdGlwbGUgdGltZXMsIGFkZENvbmRpdGlvbiB3aWxsIGNvbGxlY3QgdGhlIHZhbHVlcyBpbnRvIGFuIGFycmF5LlxuICAgICAgICAvLyBjLmYuIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9ibG9iL21haW4vcGFja2FnZXMvYXdzLWNkay1saWIvYXdzLWlhbS9saWIvcG9saWN5LXN0YXRlbWVudC50cyNMMzY0XG4gICAgICAgIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQuYWRkQ29uZGl0aW9uKGNvbmRpdGlvbk9wLCBjb25kaXRpb25zVG9FeGNlcHRGcm9tRGVueUV2ZXJ5b25lRWxzZVtjb25kaXRpb25PcF0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIGRlZmF1bHQgZW5jcnlwdGlvbiBtZXRob2QgdG8gU1NFLUtNUyxcbiAgLy8gYWxsb3cgb3ZlcnJpZGUgdG8gU1NFLVMzIChBRVMyNTYpXG4gIGxldCBlbmNyeXB0aW9uTWV0aG9kID0gJ2F3czprbXMnO1xuICBpZiAocHJvcHMuZW5jcnlwdGlvbikge1xuICAgIGlmIChCdWNrZXRFbmNyeXB0aW9uLlMzX01BTkFHRUQgPT0gcHJvcHMuZW5jcnlwdGlvbikge1xuICAgICAgZW5jcnlwdGlvbk1ldGhvZCA9ICdBRVMyNTYnO1xuICAgIH1cbiAgfVxuICBrOVN0YXRlbWVudHMucHVzaChcbiAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIHNpZDogJ0RlbnlJbnNlY3VyZUNvbW11bmljYXRpb25zJyxcbiAgICAgIGVmZmVjdDogRWZmZWN0LkRFTlksXG4gICAgICBwcmluY2lwYWxzOiBbbmV3IEFueVByaW5jaXBhbCgpXSxcbiAgICAgIGFjdGlvbnM6IFsnczM6KiddLFxuICAgICAgcmVzb3VyY2VzOiByZXNvdXJjZUFybnMsXG4gICAgICBjb25kaXRpb25zOiB7XG4gICAgICAgIEJvb2w6IHsgJ2F3czpTZWN1cmVUcmFuc3BvcnQnOiBmYWxzZSB9LFxuICAgICAgfSxcbiAgICB9KSxcbiAgKTtcblxuICBpZiAocHJvcHMuZW5mb3JjZUVuY3J5cHRpb25BdFJlc3QgPz8gdHJ1ZSkge1xuICAgIGs5U3RhdGVtZW50cy5wdXNoKFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIHNpZDogU0lEX0RFTllfVU5FTkNSWVBURURfU1RPUkFHRSxcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuREVOWSxcbiAgICAgICAgcHJpbmNpcGFsczogW25ldyBBbnlQcmluY2lwYWwoKV0sXG4gICAgICAgIGFjdGlvbnM6IFsnczM6UHV0T2JqZWN0JywgJ3MzOlJlcGxpY2F0ZU9iamVjdCddLFxuICAgICAgICByZXNvdXJjZXM6IHJlc291cmNlQXJucyxcbiAgICAgICAgY29uZGl0aW9uczoge1xuICAgICAgICAgIE51bGw6IHsgJ3MzOngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24nOiB0cnVlIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgKSxcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBzaWQ6IFNJRF9ERU5ZX1VORVhQRUNURURfRU5DUllQVElPTl9NRVRIT0QsXG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkRFTlksXG4gICAgICAgIHByaW5jaXBhbHM6IFtuZXcgQW55UHJpbmNpcGFsKCldLFxuICAgICAgICBhY3Rpb25zOiBbJ3MzOlB1dE9iamVjdCcsICdzMzpSZXBsaWNhdGVPYmplY3QnXSxcbiAgICAgICAgcmVzb3VyY2VzOiByZXNvdXJjZUFybnMsXG4gICAgICAgIGNvbmRpdGlvbnM6IHtcbiAgICAgICAgICBTdHJpbmdOb3RFcXVhbHM6IHsgJ3MzOngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24nOiBlbmNyeXB0aW9uTWV0aG9kIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgKSk7XG4gIH1cblxuICBrOVN0YXRlbWVudHMucHVzaChkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50KTtcblxuICAvLyBCdWlsZCBhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eSBtYXAgZm9yIERlbnlVbnRydXN0ZWRPcmdzXG4gIGNvbnN0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5UmVjcyA9IHBvbGljeUZhY3RvcnkubWVyZ2VEZXNpcmVkQWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkoU1VQUE9SVEVEX0NBUEFCSUxJVElFUywgcHJvcHMuazlEZXNpcmVkQWNjZXNzKTtcbiAgY29uc3QgYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHk6IE1hcDxBY2Nlc3NDYXBhYmlsaXR5LCBJQWNjZXNzU3BlYz4gPSBuZXcgTWFwKCk7XG4gIGZvciAobGV0IFtjYXBhYmlsaXR5U3RyLCBhY2Nlc3NTcGVjXSBvZiBPYmplY3QuZW50cmllcyhhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eVJlY3MpKSB7XG4gICAgYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuc2V0KGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUoY2FwYWJpbGl0eVN0ciksIGFjY2Vzc1NwZWMpO1xuICB9XG4gIGNvbnN0IGRlbnlVbnRydXN0ZWRPcmdzU3RhdGVtZW50ID0gcG9saWN5RmFjdG9yeS5fbWFrZURlbnlVbnRydXN0ZWRPcmdzU3RhdGVtZW50KFxuICAgICdTMycsIFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsIGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LCByZXNvdXJjZUFybnMpO1xuICBpZiAoZGVueVVudHJ1c3RlZE9yZ3NTdGF0ZW1lbnQpIHtcbiAgICBrOVN0YXRlbWVudHMucHVzaChkZW55VW50cnVzdGVkT3Jnc1N0YXRlbWVudCk7XG4gIH1cblxuICBmb3IgKGxldCBzdGF0ZW1lbnQgb2YgazlTdGF0ZW1lbnRzKSB7XG4gICAgbGV0IGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQgPSBwcm9wcy5idWNrZXQuYWRkVG9SZXNvdXJjZVBvbGljeShzdGF0ZW1lbnQpO1xuICAgIGFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHRzLnB1c2goYWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdCk7XG4gIH1cblxuICBwb2xpY3kuZG9jdW1lbnQudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIHJldHVybiBhZGRUb1Jlc291cmNlUG9saWN5UmVzdWx0cztcbn1cbiJdfQ==