UNPKG

@aws-cdk/aws-iam

Version:

CDK routines for easily assigning correct and minimal IAM permissions

611 lines 73.4 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.deriveEstimateSizeOptions = exports.Effect = exports.PolicyStatement = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cdk = require("@aws-cdk/core"); const group_1 = require("./group"); const principals_1 = require("./principals"); const postprocess_policy_document_1 = require("./private/postprocess-policy-document"); const util_1 = require("./util"); const ensureArrayOrUndefined = (field) => { if (field === undefined) { return undefined; } if (typeof (field) !== 'string' && !Array.isArray(field)) { throw new Error('Fields must be either a string or an array of strings'); } if (Array.isArray(field) && !!field.find((f) => typeof (f) !== 'string')) { throw new Error('Fields must be either a string or an array of strings'); } return Array.isArray(field) ? field : [field]; }; /** * An estimate on how long ARNs typically are * * This is used to decide when to start splitting statements into new Managed Policies. * Because we often can't know the length of an ARN (it may be a token and only * available at deployment time) we'll have to estimate it. * * The estimate can be overridden by setting the `@aws-cdk/aws-iam.arnSizeEstimate` context key. */ const DEFAULT_ARN_SIZE_ESTIMATE = 150; /** * Context key which can be used to override the estimated length of unresolved ARNs. */ const ARN_SIZE_ESTIMATE_CONTEXT_KEY = '@aws-cdk/aws-iam.arnSizeEstimate'; /** * Represents a statement in an IAM policy document. */ class PolicyStatement { constructor(props = {}) { this._action = new Array(); this._notAction = new Array(); this._principal = {}; this._notPrincipal = {}; this._resource = new Array(); this._notResource = new Array(); this._condition = {}; // Hold on to those principals this._principals = new Array(); this._notPrincipals = new Array(); try { jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatementProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, PolicyStatement); } throw error; } // Validate actions for (const action of [...props.actions || [], ...props.notActions || []]) { if (!/^(\*|[a-zA-Z0-9-]+:[a-zA-Z0-9*]+)$/.test(action) && !cdk.Token.isUnresolved(action)) { throw new Error(`Action '${action}' is invalid. An action string consists of a service namespace, a colon, and the name of an action. Action names can include wildcards.`); } } this.sid = props.sid; this.effect = props.effect || Effect.ALLOW; this.addActions(...props.actions || []); this.addNotActions(...props.notActions || []); this.addPrincipals(...props.principals || []); this.addNotPrincipals(...props.notPrincipals || []); this.addResources(...props.resources || []); this.addNotResources(...props.notResources || []); if (props.conditions !== undefined) { this.addConditions(props.conditions); } } /** * Creates a new PolicyStatement based on the object provided. * This will accept an object created from the `.toJSON()` call * @param obj the PolicyStatement in object form. */ static fromJson(obj) { const ret = new PolicyStatement({ sid: obj.Sid, actions: ensureArrayOrUndefined(obj.Action), resources: ensureArrayOrUndefined(obj.Resource), conditions: obj.Condition, effect: obj.Effect, notActions: ensureArrayOrUndefined(obj.NotAction), notResources: ensureArrayOrUndefined(obj.NotResource), principals: obj.Principal ? [new JsonPrincipal(obj.Principal)] : undefined, notPrincipals: obj.NotPrincipal ? [new JsonPrincipal(obj.NotPrincipal)] : undefined, }); // validate that the PolicyStatement has the correct shape const errors = ret.validateForAnyPolicy(); if (errors.length > 0) { throw new Error('Incorrect Policy Statement: ' + errors.join('\n')); } return ret; } // // Actions // /** * Specify allowed actions into the "Action" section of the policy statement. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html * * @param actions actions that will be allowed. */ addActions(...actions) { if (actions.length > 0 && this._notAction.length > 0) { throw new Error('Cannot add \'Actions\' to policy statement if \'NotActions\' have been added'); } this._action.push(...actions); } /** * Explicitly allow all actions except the specified list of actions into the "NotAction" section * of the policy document. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html * * @param notActions actions that will be denied. All other actions will be permitted. */ addNotActions(...notActions) { if (notActions.length > 0 && this._action.length > 0) { throw new Error('Cannot add \'NotActions\' to policy statement if \'Actions\' have been added'); } this._notAction.push(...notActions); } // // Principal // /** * Indicates if this permission has a "Principal" section. */ get hasPrincipal() { return this._principals.length + this._notPrincipals.length > 0; } /** * Adds principals to the "Principal" section of a policy statement. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html * * @param principals IAM principals that will be added */ addPrincipals(...principals) { try { jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(principals); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addPrincipals); } throw error; } this._principals.push(...principals); if (Object.keys(principals).length > 0 && Object.keys(this._notPrincipal).length > 0) { throw new Error('Cannot add \'Principals\' to policy statement if \'NotPrincipals\' have been added'); } for (const principal of principals) { this.validatePolicyPrincipal(principal); const fragment = principal.policyFragment; util_1.mergePrincipal(this._principal, fragment.principalJson); this.addPrincipalConditions(fragment.conditions); } } /** * Specify principals that is not allowed or denied access to the "NotPrincipal" section of * a policy statement. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html * * @param notPrincipals IAM principals that will be denied access */ addNotPrincipals(...notPrincipals) { try { jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(notPrincipals); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addNotPrincipals); } throw error; } this._notPrincipals.push(...notPrincipals); if (Object.keys(notPrincipals).length > 0 && Object.keys(this._principal).length > 0) { throw new Error('Cannot add \'NotPrincipals\' to policy statement if \'Principals\' have been added'); } for (const notPrincipal of notPrincipals) { this.validatePolicyPrincipal(notPrincipal); const fragment = notPrincipal.policyFragment; util_1.mergePrincipal(this._notPrincipal, fragment.principalJson); this.addPrincipalConditions(fragment.conditions); } } validatePolicyPrincipal(principal) { if (principal instanceof group_1.Group) { throw new Error('Cannot use an IAM Group as the \'Principal\' or \'NotPrincipal\' in an IAM Policy'); } } /** * Specify AWS account ID as the principal entity to the "Principal" section of a policy statement. */ addAwsAccountPrincipal(accountId) { this.addPrincipals(new principals_1.AccountPrincipal(accountId)); } /** * Specify a principal using the ARN identifier of the principal. * You cannot specify IAM groups and instance profiles as principals. * * @param arn ARN identifier of AWS account, IAM user, or IAM role (i.e. arn:aws:iam::123456789012:user/user-name) */ addArnPrincipal(arn) { this.addPrincipals(new principals_1.ArnPrincipal(arn)); } /** * Adds a service principal to this policy statement. * * @param service the service name for which a service principal is requested (e.g: `s3.amazonaws.com`). * @param opts options for adding the service principal (such as specifying a principal in a different region) */ addServicePrincipal(service, opts) { try { jsiiDeprecationWarnings._aws_cdk_aws_iam_ServicePrincipalOpts(opts); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addServicePrincipal); } throw error; } this.addPrincipals(new principals_1.ServicePrincipal(service, opts)); } /** * Adds a federated identity provider such as Amazon Cognito to this policy statement. * * @param federated federated identity provider (i.e. 'cognito-identity.amazonaws.com') * @param conditions The conditions under which the policy is in effect. * See [the IAM documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html). */ addFederatedPrincipal(federated, conditions) { this.addPrincipals(new principals_1.FederatedPrincipal(federated, conditions)); } /** * Adds an AWS account root user principal to this policy statement */ addAccountRootPrincipal() { this.addPrincipals(new principals_1.AccountRootPrincipal()); } /** * Adds a canonical user ID principal to this policy document * * @param canonicalUserId unique identifier assigned by AWS for every account */ addCanonicalUserPrincipal(canonicalUserId) { this.addPrincipals(new principals_1.CanonicalUserPrincipal(canonicalUserId)); } /** * Adds all identities in all accounts ("*") to this policy statement */ addAnyPrincipal() { this.addPrincipals(new principals_1.AnyPrincipal()); } // // Resources // /** * Specify resources that this policy statement applies into the "Resource" section of * this policy statement. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html * * @param arns Amazon Resource Names (ARNs) of the resources that this policy statement applies to */ addResources(...arns) { if (arns.length > 0 && this._notResource.length > 0) { throw new Error('Cannot add \'Resources\' to policy statement if \'NotResources\' have been added'); } this._resource.push(...arns); } /** * Specify resources that this policy statement will not apply to in the "NotResource" section * of this policy statement. All resources except the specified list will be matched. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html * * @param arns Amazon Resource Names (ARNs) of the resources that this policy statement does not apply to */ addNotResources(...arns) { if (arns.length > 0 && this._resource.length > 0) { throw new Error('Cannot add \'NotResources\' to policy statement if \'Resources\' have been added'); } this._notResource.push(...arns); } /** * Adds a ``"*"`` resource to this statement. */ addAllResources() { this.addResources('*'); } /** * Indicates if this permission has at least one resource associated with it. */ get hasResource() { return this._resource && this._resource.length > 0; } // // Condition // /** * Add a condition to the Policy * * If multiple calls are made to add a condition with the same operator and field, only * the last one wins. For example: * * ```ts * declare const stmt: iam.PolicyStatement; * * stmt.addCondition('StringEquals', { 'aws:SomeField': '1' }); * stmt.addCondition('StringEquals', { 'aws:SomeField': '2' }); * ``` * * Will end up with the single condition `StringEquals: { 'aws:SomeField': '2' }`. * * If you meant to add a condition to say that the field can be *either* `1` or `2`, write * this: * * ```ts * declare const stmt: iam.PolicyStatement; * * stmt.addCondition('StringEquals', { 'aws:SomeField': ['1', '2'] }); * ``` */ addCondition(key, value) { const existingValue = this._condition[key]; this._condition[key] = existingValue ? { ...existingValue, ...value } : value; } /** * Add multiple conditions to the Policy * * See the `addCondition` function for a caveat on calling this method multiple times. */ addConditions(conditions) { Object.keys(conditions).map(key => { this.addCondition(key, conditions[key]); }); } /** * Add a condition that limits to a given account * * This method can only be called once: subsequent calls will overwrite earlier calls. */ addAccountCondition(accountId) { this.addCondition('StringEquals', { 'sts:ExternalId': accountId }); } /** * Create a new `PolicyStatement` with the same exact properties * as this one, except for the overrides */ copy(overrides = {}) { try { jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatementProps(overrides); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.copy); } throw error; } return new PolicyStatement({ sid: overrides.sid ?? this.sid, effect: overrides.effect ?? this.effect, actions: overrides.actions ?? this.actions, notActions: overrides.notActions ?? this.notActions, principals: overrides.principals ?? this.principals, notPrincipals: overrides.notPrincipals ?? this.notPrincipals, resources: overrides.resources ?? this.resources, notResources: overrides.notResources ?? this.notResources, conditions: overrides.conditions ?? this.conditions, }); } /** * JSON-ify the policy statement * * Used when JSON.stringify() is called */ toStatementJson() { return postprocess_policy_document_1.normalizeStatement({ Action: this._action, NotAction: this._notAction, Condition: this._condition, Effect: this.effect, Principal: this._principal, NotPrincipal: this._notPrincipal, Resource: this._resource, NotResource: this._notResource, Sid: this.sid, }); } /** * String representation of this policy statement */ toString() { return cdk.Token.asString(this, { displayHint: 'PolicyStatement', }); } /** * JSON-ify the statement * * Used when JSON.stringify() is called */ toJSON() { return this.toStatementJson(); } /** * Add a principal's conditions * * For convenience, principals have been modeled as both a principal * and a set of conditions. This makes it possible to have a single * object represent e.g. an "SNS Topic" (SNS service principal + aws:SourcArn * condition) or an Organization member (* + aws:OrgId condition). * * However, when using multiple principals in the same policy statement, * they must all have the same conditions or the OR samentics * implied by a list of principals cannot be guaranteed (user needs to * add multiple statements in that case). */ addPrincipalConditions(conditions) { // Stringifying the conditions is an easy way to do deep equality const theseConditions = JSON.stringify(conditions); if (this.principalConditionsJson === undefined) { // First principal, anything goes this.principalConditionsJson = theseConditions; } else { if (this.principalConditionsJson !== theseConditions) { throw new Error(`All principals in a PolicyStatement must have the same Conditions (got '${this.principalConditionsJson}' and '${theseConditions}'). Use multiple statements instead.`); } } this.addConditions(conditions); } /** * Validate that the policy statement satisfies base requirements for a policy. * * @returns An array of validation error messages, or an empty array if the statement is valid. */ validateForAnyPolicy() { const errors = new Array(); if (this._action.length === 0 && this._notAction.length === 0) { errors.push('A PolicyStatement must specify at least one \'action\' or \'notAction\'.'); } return errors; } /** * Validate that the policy statement satisfies all requirements for a resource-based policy. * * @returns An array of validation error messages, or an empty array if the statement is valid. */ validateForResourcePolicy() { const errors = this.validateForAnyPolicy(); if (Object.keys(this._principal).length === 0 && Object.keys(this._notPrincipal).length === 0) { errors.push('A PolicyStatement used in a resource-based policy must specify at least one IAM principal.'); } return errors; } /** * Validate that the policy statement satisfies all requirements for an identity-based policy. * * @returns An array of validation error messages, or an empty array if the statement is valid. */ validateForIdentityPolicy() { const errors = this.validateForAnyPolicy(); if (Object.keys(this._principal).length > 0 || Object.keys(this._notPrincipal).length > 0) { errors.push('A PolicyStatement used in an identity-based policy cannot specify any IAM principals.'); } if (Object.keys(this._resource).length === 0 && Object.keys(this._notResource).length === 0) { errors.push('A PolicyStatement used in an identity-based policy must specify at least one resource.'); } return errors; } /** * The Actions added to this statement */ get actions() { return [...this._action]; } /** * The NotActions added to this statement */ get notActions() { return [...this._notAction]; } /** * The Principals added to this statement */ get principals() { return [...this._principals]; } /** * The NotPrincipals added to this statement */ get notPrincipals() { return [...this._notPrincipals]; } /** * The Resources added to this statement */ get resources() { return [...this._resource]; } /** * The NotResources added to this statement */ get notResources() { return [...this._notResource]; } /** * The conditions added to this statement */ get conditions() { return { ...this._condition }; } /** * Estimate the size of this policy statement * * By necessity, this will not be accurate. We'll do our best to overestimate * so we won't have nasty surprises. * * @internal */ _estimateSize(options) { let ret = 0; const { actionEstimate, arnEstimate } = options; ret += `"Effect": "${this.effect}",`.length; count('Action', this.actions, actionEstimate); count('NotAction', this.notActions, actionEstimate); count('Resource', this.resources, arnEstimate); count('NotResource', this.notResources, arnEstimate); ret += this.principals.length * arnEstimate; ret += this.notPrincipals.length * arnEstimate; ret += JSON.stringify(this.conditions).length; return ret; function count(key, values, tokenSize) { if (values.length > 0) { ret += key.length + 5 /* quotes, colon, brackets */ + util_1.sum(values.map(v => (cdk.Token.isUnresolved(v) ? tokenSize : v.length) + 3 /* quotes, separator */)); } } } } exports.PolicyStatement = PolicyStatement; _a = JSII_RTTI_SYMBOL_1; PolicyStatement[_a] = { fqn: "@aws-cdk/aws-iam.PolicyStatement", version: "1.204.0" }; /** * The Effect element of an IAM policy * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_effect.html */ var Effect; (function (Effect) { /** * Allows access to a resource in an IAM policy statement. By default, access to resources are denied. */ Effect["ALLOW"] = "Allow"; /** * Explicitly deny access to a resource. By default, all requests are denied implicitly. * * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html */ Effect["DENY"] = "Deny"; })(Effect = exports.Effect || (exports.Effect = {})); class JsonPrincipal extends principals_1.PrincipalBase { constructor(json = {}) { super(); // special case: if principal is a string, turn it into a "LiteralString" principal, // so we render the exact same string back out. if (typeof (json) === 'string') { json = { [util_1.LITERAL_STRING_KEY]: [json] }; } if (typeof (json) !== 'object') { throw new Error(`JSON IAM principal should be an object, got ${JSON.stringify(json)}`); } this.policyFragment = { principalJson: json, conditions: {}, }; } dedupeString() { return JSON.stringify(this.policyFragment); } } /** * Derive the size estimation options from context * * @internal */ function deriveEstimateSizeOptions(scope) { const actionEstimate = 20; const arnEstimate = scope.node.tryGetContext(ARN_SIZE_ESTIMATE_CONTEXT_KEY) ?? DEFAULT_ARN_SIZE_ESTIMATE; if (typeof arnEstimate !== 'number') { throw new Error(`Context value ${ARN_SIZE_ESTIMATE_CONTEXT_KEY} should be a number, got ${JSON.stringify(arnEstimate)}`); } return { actionEstimate, arnEstimate }; } exports.deriveEstimateSizeOptions = deriveEstimateSizeOptions; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9saWN5LXN0YXRlbWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInBvbGljeS1zdGF0ZW1lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEscUNBQXFDO0FBRXJDLG1DQUFnQztBQUNoQyw2Q0FHc0I7QUFDdEIsdUZBQTJFO0FBQzNFLGlDQUFpRTtBQUVqRSxNQUFNLHNCQUFzQixHQUFHLENBQUMsS0FBVSxFQUFFLEVBQUU7SUFDNUMsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFO1FBQ3ZCLE9BQU8sU0FBUyxDQUFDO0tBQ2xCO0lBQ0QsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUN4RCxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7S0FDMUU7SUFDRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENBQUMsRUFBRTtRQUM3RSxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7S0FDMUU7SUFDRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDLENBQUM7QUFFRjs7Ozs7Ozs7R0FRRztBQUNILE1BQU0seUJBQXlCLEdBQUcsR0FBRyxDQUFDO0FBRXRDOztHQUVHO0FBQ0gsTUFBTSw2QkFBNkIsR0FBRyxrQ0FBa0MsQ0FBQztBQUV6RTs7R0FFRztBQUNILE1BQWEsZUFBZTtJQW9EMUIsWUFBWSxRQUE4QixFQUFFO1FBYjNCLFlBQU8sR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFD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QUM7QUFSRCw4REFRQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNkayBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCB7IElDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCB7IEdyb3VwIH0gZnJvbSAnLi9ncm91cCc7XG5pbXBvcnQge1xuICBBY2NvdW50UHJpbmNpcGFsLCBBY2NvdW50Um9vdFByaW5jaXBhbCwgQW55UHJpbmNpcGFsLCBBcm5QcmluY2lwYWwsIENhbm9uaWNhbFVzZXJQcmluY2lwYWwsXG4gIEZlZGVyYXRlZFByaW5jaXBhbCwgSVByaW5jaXBhbCwgUHJpbmNpcGFsQmFzZSwgUHJpbmNpcGFsUG9saWN5RnJhZ21lbnQsIFNlcnZpY2VQcmluY2lwYWwsIFNlcnZpY2VQcmluY2lwYWxPcHRzLFxufSBmcm9tICcuL3ByaW5jaXBhbHMnO1xuaW1wb3J0IHsgbm9ybWFsaXplU3RhdGVtZW50IH0gZnJvbSAnLi9wcml2YXRlL3Bvc3Rwcm9jZXNzLXBvbGljeS1kb2N1bWVudCc7XG5pbXBvcnQgeyBMSVRFUkFMX1NUUklOR19LRVksIG1lcmdlUHJpbmNpcGFsLCBzdW0gfSBmcm9tICcuL3V0aWwnO1xuXG5jb25zdCBlbnN1cmVBcnJheU9yVW5kZWZpbmVkID0gKGZpZWxkOiBhbnkpID0+IHtcbiAgaWYgKGZpZWxkID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGlmICh0eXBlb2YgKGZpZWxkKSAhPT0gJ3N0cmluZycgJiYgIUFycmF5LmlzQXJyYXkoZmllbGQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGaWVsZHMgbXVzdCBiZSBlaXRoZXIgYSBzdHJpbmcgb3IgYW4gYXJyYXkgb2Ygc3RyaW5ncycpO1xuICB9XG4gIGlmIChBcnJheS5pc0FycmF5KGZpZWxkKSAmJiAhIWZpZWxkLmZpbmQoKGY6IGFueSkgPT4gdHlwZW9mIChmKSAhPT0gJ3N0cmluZycpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGaWVsZHMgbXVzdCBiZSBlaXRoZXIgYSBzdHJpbmcgb3IgYW4gYXJyYXkgb2Ygc3RyaW5ncycpO1xuICB9XG4gIHJldHVybiBBcnJheS5pc0FycmF5KGZpZWxkKSA/IGZpZWxkIDogW2ZpZWxkXTtcbn07XG5cbi8qKlxuICogQW4gZXN0aW1hdGUgb24gaG93IGxvbmcgQVJOcyB0eXBpY2FsbHkgYXJlXG4gKlxuICogVGhpcyBpcyB1c2VkIHRvIGRlY2lkZSB3aGVuIHRvIHN0YXJ0IHNwbGl0dGluZyBzdGF0ZW1lbnRzIGludG8gbmV3IE1hbmFnZWQgUG9saWNpZXMuXG4gKiBCZWNhdXNlIHdlIG9mdGVuIGNhbid0IGtub3cgdGhlIGxlbmd0aCBvZiBhbiBBUk4gKGl0IG1heSBiZSBhIHRva2VuIGFuZCBvbmx5XG4gKiBhdmFpbGFibGUgYXQgZGVwbG95bWVudCB0aW1lKSB3ZSdsbCBoYXZlIHRvIGVzdGltYXRlIGl0LlxuICpcbiAqIFRoZSBlc3RpbWF0ZSBjYW4gYmUgb3ZlcnJpZGRlbiBieSBzZXR0aW5nIHRoZSBgQGF3cy1jZGsvYXdzLWlhbS5hcm5TaXplRXN0aW1hdGVgIGNvbnRleHQga2V5LlxuICovXG5jb25zdCBERUZBVUxUX0FSTl9TSVpFX0VTVElNQVRFID0gMTUwO1xuXG4vKipcbiAqIENvbnRleHQga2V5IHdoaWNoIGNhbiBiZSB1c2VkIHRvIG92ZXJyaWRlIHRoZSBlc3RpbWF0ZWQgbGVuZ3RoIG9mIHVucmVzb2x2ZWQgQVJOcy5cbiAqL1xuY29uc3QgQVJOX1NJWkVfRVNUSU1BVEVfQ09OVEVYVF9LRVkgPSAnQGF3cy1jZGsvYXdzLWlhbS5hcm5TaXplRXN0aW1hdGUnO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBzdGF0ZW1lbnQgaW4gYW4gSUFNIHBvbGljeSBkb2N1bWVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIFBvbGljeVN0YXRlbWVudCB7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgUG9saWN5U3RhdGVtZW50IGJhc2VkIG9uIHRoZSBvYmplY3QgcHJvdmlkZWQuXG4gICAqIFRoaXMgd2lsbCBhY2NlcHQgYW4gb2JqZWN0IGNyZWF0ZWQgZnJvbSB0aGUgYC50b0pTT04oKWAgY2FsbFxuICAgKiBAcGFyYW0gb2JqIHRoZSBQb2xpY3lTdGF0ZW1lbnQgaW4gb2JqZWN0IGZvcm0uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21Kc29uKG9iajogYW55KSB7XG4gICAgY29uc3QgcmV0ID0gbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICBzaWQ6IG9iai5TaWQsXG4gICAgICBhY3Rpb25zOiBlbnN1cmVBcnJheU9yVW5kZWZpbmVkKG9iai5BY3Rpb24pLFxuICAgICAgcmVzb3VyY2VzOiBlbnN1cmVBcnJheU9yVW5kZWZpbmVkKG9iai5SZXNvdXJjZSksXG4gICAgICBjb25kaXRpb25zOiBvYmouQ29uZGl0aW9uLFxuICAgICAgZWZmZWN0OiBvYmouRWZmZWN0LFxuICAgICAgbm90QWN0aW9uczogZW5zdXJlQXJyYXlPclVuZGVmaW5lZChvYmouTm90QWN0aW9uKSxcbiAgICAgIG5vdFJlc291cmNlczogZW5zdXJlQXJyYXlPclVuZGVmaW5lZChvYmouTm90UmVzb3VyY2UpLFxuICAgICAgcHJpbmNpcGFsczogb2JqLlByaW5jaXBhbCA/IFtuZXcgSnNvblByaW5jaXBhbChvYmouUHJpbmNpcGFsKV0gOiB1bmRlZmluZWQsXG4gICAgICBub3RQcmluY2lwYWxzOiBvYmouTm90UHJpbmNpcGFsID8gW25ldyBKc29uUHJpbmNpcGFsKG9iai5Ob3RQcmluY2lwYWwpXSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIC8vIHZhbGlkYXRlIHRoYXQgdGhlIFBvbGljeVN0YXRlbWVudCBoYXMgdGhlIGNvcnJlY3Qgc2hhcGVcbiAgICBjb25zdCBlcnJvcnMgPSByZXQudmFsaWRhdGVGb3JBbnlQb2xpY3koKTtcbiAgICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW5jb3JyZWN0IFBvbGljeSBTdGF0ZW1lbnQ6ICcgKyBlcnJvcnMuam9pbignXFxuJykpO1xuICAgIH1cblxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvKipcbiAgICogU3RhdGVtZW50IElEIGZvciB0aGlzIHN0YXRlbWVudFxuICAgKi9cbiAgcHVibGljIHNpZD86IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0byBhbGxvdyBvciBkZW55IHRoZSBhY3Rpb25zIGluIHRoaXMgc3RhdGVtZW50XG4gICAqL1xuICBwdWJsaWMgZWZmZWN0OiBFZmZlY3Q7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfYWN0aW9uID0gbmV3IEFycmF5PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbm90QWN0aW9uID0gbmV3IEFycmF5PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJpbmNpcGFsOiB7IFtrZXk6IHN0cmluZ106IGFueVtdIH0gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbm90UHJpbmNpcGFsOiB7IFtrZXk6IHN0cmluZ106IGFueVtdIH0gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcmVzb3VyY2UgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9ub3RSZXNvdXJjZSA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2NvbmRpdGlvbjogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHsgfTtcbiAgcHJpdmF0ZSBwcmluY2lwYWxDb25kaXRpb25zSnNvbj86IHN0cmluZztcblxuICAvLyBIb2xkIG9uIHRvIHRob3NlIHByaW5jaXBhbHNcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJpbmNpcGFscyA9IG5ldyBBcnJheTxJUHJpbmNpcGFsPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9ub3RQcmluY2lwYWxzID0gbmV3IEFycmF5PElQcmluY2lwYWw+KCk7XG5cbiAgY29uc3RydWN0b3IocHJvcHM6IFBvbGljeVN0YXRlbWVudFByb3BzID0ge30pIHtcbiAgICAvLyBWYWxpZGF0ZSBhY3Rpb25zXG4gICAgZm9yIChjb25zdCBhY3Rpb24gb2YgWy4uLnByb3BzLmFjdGlvbnMgfHwgW10sIC4uLnByb3BzLm5vdEFjdGlvbnMgfHwgW11dKSB7XG5cbiAgICAgIGlmICghL14oXFwqfFthLXpBLVowLTktXSs6W2EtekEtWjAtOSpdKykkLy50ZXN0KGFjdGlvbikgJiYgIWNkay5Ub2tlbi5pc1VucmVzb2x2ZWQoYWN0aW9uKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEFjdGlvbiAnJHthY3Rpb259JyBpcyBpbnZhbGlkLiBBbiBhY3Rpb24gc3RyaW5nIGNvbnNpc3RzIG9mIGEgc2VydmljZSBuYW1lc3BhY2UsIGEgY29sb24sIGFuZCB0aGUgbmFtZSBvZiBhbiBhY3Rpb24uIEFjdGlvbiBuYW1lcyBjYW4gaW5jbHVkZSB3aWxkY2FyZHMuYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5zaWQgPSBwcm9wcy5zaWQ7XG4gICAgdGhpcy5lZmZlY3QgPSBwcm9wcy5lZmZlY3QgfHwgRWZmZWN0LkFMTE9XO1xuXG4gICAgdGhpcy5hZGRBY3Rpb25zKC4uLnByb3BzLmFjdGlvbnMgfHwgW10pO1xuICAgIHRoaXMuYWRkTm90QWN0aW9ucyguLi5wcm9wcy5ub3RBY3Rpb25zIHx8IFtdKTtcbiAgICB0aGlzLmFkZFByaW5jaXBhbHMoLi4ucHJvcHMucHJpbmNpcGFscyB8fCBbXSk7XG4gICAgdGhpcy5hZGROb3RQcmluY2lwYWxzKC4uLnByb3BzLm5vdFByaW5jaXBhbHMgfHwgW10pO1xuICAgIHRoaXMuYWRkUmVzb3VyY2VzKC4uLnByb3BzLnJlc291cmNlcyB8fCBbXSk7XG4gICAgdGhpcy5hZGROb3RSZXNvdXJjZXMoLi4ucHJvcHMubm90UmVzb3VyY2VzIHx8IFtdKTtcbiAgICBpZiAocHJvcHMuY29uZGl0aW9ucyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmFkZENvbmRpdGlvbnMocHJvcHMuY29uZGl0aW9ucyk7XG4gICAgfVxuICB9XG5cbiAgLy9cbiAgLy8gQWN0aW9uc1xuICAvL1xuXG4gIC8qKlxuICAgKiBTcGVjaWZ5IGFsbG93ZWQgYWN0aW9ucyBpbnRvIHRoZSBcIkFjdGlvblwiIHNlY3Rpb24gb2YgdGhlIHBvbGljeSBzdGF0ZW1lbnQuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL3JlZmVyZW5jZV9wb2xpY2llc19lbGVtZW50c19hY3Rpb24uaHRtbFxuICAgKlxuICAgKiBAcGFyYW0gYWN0aW9ucyBhY3Rpb25zIHRoYXQgd2lsbCBiZSBhbGxvd2VkLlxuICAgKi9cbiAgcHVibGljIGFkZEFjdGlvbnMoLi4uYWN0aW9uczogc3RyaW5nW10pIHtcbiAgICBpZiAoYWN0aW9ucy5sZW5ndGggPiAwICYmIHRoaXMuX25vdEFjdGlvbi5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBhZGQgXFwnQWN0aW9uc1xcJyB0byBwb2xpY3kgc3RhdGVtZW50IGlmIFxcJ05vdEFjdGlvbnNcXCcgaGF2ZSBiZWVuIGFkZGVkJyk7XG4gICAgfVxuICAgIHRoaXMuX2FjdGlvbi5wdXNoKC4uLmFjdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxpY2l0bHkgYWxsb3cgYWxsIGFjdGlvbnMgZXhjZXB0IHRoZSBzcGVjaWZpZWQgbGlzdCBvZiBhY3Rpb25zIGludG8gdGhlIFwiTm90QWN0aW9uXCIgc2VjdGlvblxuICAgKiBvZiB0aGUgcG9saWN5IGRvY3VtZW50LlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9yZWZlcmVuY2VfcG9saWNpZXNfZWxlbWVudHNfbm90YWN0aW9uLmh0bWxcbiAgICpcbiAgICogQHBhcmFtIG5vdEFjdGlvbnMgYWN0aW9ucyB0aGF0IHdpbGwgYmUgZGVuaWVkLiBBbGwgb3RoZXIgYWN0aW9ucyB3aWxsIGJlIHBlcm1pdHRlZC5cbiAgICovXG4gIHB1YmxpYyBhZGROb3RBY3Rpb25zKC4uLm5vdEFjdGlvbnM6IHN0cmluZ1tdKSB7XG4gICAgaWYgKG5vdEFjdGlvbnMubGVuZ3RoID4gMCAmJiB0aGlzLl9hY3Rpb24ubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgYWRkIFxcJ05vdEFjdGlvbnNcXCcgdG8gcG9saWN5IHN0YXRlbWVudCBpZiBcXCdBY3Rpb25zXFwnIGhhdmUgYmVlbiBhZGRlZCcpO1xuICAgIH1cbiAgICB0aGlzLl9ub3RBY3Rpb24ucHVzaCguLi5ub3RBY3Rpb25zKTtcbiAgfVxuXG4gIC8vXG4gIC8vIFByaW5jaXBhbFxuICAvL1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhpcyBwZXJtaXNzaW9uIGhhcyBhIFwiUHJpbmNpcGFsXCIgc2VjdGlvbi5cbiAgICovXG4gIHB1YmxpYyBnZXQgaGFzUHJpbmNpcGFsKCkge1xuICAgIHJldHVybiB0aGlzLl9wcmluY2lwYWxzLmxlbmd0aCArIHRoaXMuX25vdFByaW5jaXBhbHMubGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIHByaW5jaXBhbHMgdG8gdGhlIFwiUHJpbmNpcGFsXCIgc2VjdGlvbiBvZiBhIHBvbGljeSBzdGF0ZW1lbnQuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL3JlZmVyZW5jZV9wb2xpY2llc19lbGVtZW50c19wcmluY2lwYWwuaHRtbFxuICAgKlxuICAgKiBAcGFyYW0gcHJpbmNpcGFscyBJQU0gcHJpbmNpcGFscyB0aGF0IHdpbGwgYmUgYWRkZWRcbiAgICovXG4gIHB1YmxpYyBhZGRQcmluY2lwYWxzKC4uLnByaW5jaXBhbHM6IElQcmluY2lwYWxbXSkge1xuICAgIHRoaXMuX3ByaW5jaXBhbHMucHVzaCguLi5wcmluY2lwYWxzKTtcbiAgICBpZiAoT2JqZWN0LmtleXMocHJpbmNpcGFscykubGVuZ3RoID4gMCAmJiBPYmplY3Qua2V5cyh0aGlzLl9ub3RQcmluY2lwYWwpLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGFkZCBcXCdQcmluY2lwYWxzXFwnIHRvIHBvbGljeSBzdGF0ZW1lbnQgaWYgXFwnTm90UHJpbmNpcGFsc1xcJyBoYXZlIGJlZW4gYWRkZWQnKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBwcmluY2lwYWwgb2YgcHJpbmNpcGFscykge1xuICAgICAgdGhpcy52YWxpZGF0ZVBvbGljeVByaW5jaXBhbChwcmluY2lwYWwpO1xuICAgICAgY29uc3QgZnJhZ21lbnQgPSBwcmluY2lwYWwucG9saWN5RnJhZ21lbnQ7XG4gICAgICBtZXJnZVByaW5jaXBhbCh0aGlzLl9wcmluY2lwYWwsIGZyYWdtZW50LnByaW5jaXBhbEpzb24pO1xuICAgICAgdGhpcy5hZGRQcmluY2lwYWxDb25kaXRpb25zKGZyYWdtZW50LmNvbmRpdGlvbnMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTcGVjaWZ5IHByaW5jaXBhbHMgdGhhdCBpcyBub3QgYWxsb3dlZCBvciBkZW5pZWQgYWNjZXNzIHRvIHRoZSBcIk5vdFByaW5jaXBhbFwiIHNlY3Rpb24gb2ZcbiAgICogYSBwb2xpY3kgc3RhdGVtZW50LlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9yZWZlcmVuY2VfcG9saWNpZXNfZWxlbWVudHNfbm90cHJpbmNpcGFsLmh0bWxcbiAgICpcbiAgICogQHBhcmFtIG5vdFByaW5jaXBhbHMgSUFNIHByaW5jaXBhbHMgdGhhdCB3aWxsIGJlIGRlbmllZCBhY2Nlc3NcbiAgICovXG4gIHB1YmxpYyBhZGROb3RQcmluY2lwYWxzKC4uLm5vdFByaW5jaXBhbHM6IElQcmluY2lwYWxbXSkge1xuICAgIHRoaXMuX25vdFByaW5jaXBhbHMucHVzaCguLi5ub3RQcmluY2lwYWxzKTtcbiAgICBpZiAoT2JqZWN0LmtleXMobm90UHJpbmNpcGFscykubGVuZ3RoID4gMCAmJiBPYmplY3Qua2V5cyh0aGlzLl9wcmluY2lwYWwpLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGFkZCBcXCdOb3RQcmluY2lwYWxzXFwnIHRvIHBvbGljeSBzdGF0ZW1lbnQgaWYgXFwnUHJpbmNpcGFsc1xcJyBoYXZlIGJlZW4gYWRkZWQnKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBub3RQcmluY2lwYWwgb2Ygbm90UHJpbmNpcGFscykge1xuICAgICAgdGhpcy52YWxpZGF0ZVBvbGljeVByaW5jaXBhbChub3RQcmluY2lwYWwpO1xuICAgICAgY29uc3QgZnJhZ21lbnQgPSBub3RQcmluY2lwYWwucG9saWN5RnJhZ21lbnQ7XG4gICAgICBtZXJnZVByaW5jaXBhbCh0aGlzLl9ub3RQcmluY2lwYWwsIGZyYWdtZW50LnByaW5jaXBhbEpzb24pO1xuICAgICAgdGhpcy5hZGRQcmluY2lwYWxDb25kaXRpb25zKGZyYWdtZW50LmNvbmRpdGlvbnMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVQb2xpY3lQcmluY2lwYWwocHJpbmNpcGFsOiBJUHJpbmNpcGFsKSB7XG4gICAgaWYgKHByaW5jaXBhbCBpbnN0YW5jZW9mIEdyb3VwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCB1c2UgYW4gSUFNIEdyb3VwIGFzIHRoZSBcXCdQcmluY2lwYWxcXCcgb3IgXFwnTm90UHJpbmNpcGFsXFwnIGluIGFuIElBTSBQb2xpY3knKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3BlY2lmeSBBV1MgYWNjb3VudCBJRCBhcyB0aGUgcHJpbmNpcGFsIGVudGl0eSB0byB0aGUgXCJQcmluY2lwYWxcI