@aws-cdk/aws-iam
Version:
CDK routines for easily assigning correct and minimal IAM permissions
611 lines • 73.4 kB
JavaScript
"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