cdk-sops-secrets
Version:
CDK Constructs that syncs your sops secrets into AWS SecretsManager secrets.
365 lines • 57.7 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Permissions = exports.SopsSync = exports.SopsSyncProvider = exports.ResourceType = exports.UploadType = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs = require("fs");
const path = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_kms_1 = require("aws-cdk-lib/aws-kms");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
const constructs_1 = require("constructs");
var UploadType;
(function (UploadType) {
/**
* Pass the secret data inline (base64 encoded and compressed)
*/
UploadType["INLINE"] = "INLINE";
/**
* Uplaod the secret data as asset
*/
UploadType["ASSET"] = "ASSET";
})(UploadType || (exports.UploadType = UploadType = {}));
var ResourceType;
(function (ResourceType) {
ResourceType["SECRET"] = "SECRET";
ResourceType["SECRET_RAW"] = "SECRET_RAW";
ResourceType["SECRET_BINARY"] = "SECRET_BINARY";
ResourceType["PARAMETER"] = "PARAMETER";
ResourceType["PARAMETER_MULTI"] = "PARAMETER_MULTI";
})(ResourceType || (exports.ResourceType = ResourceType = {}));
class SopsSyncProvider extends aws_lambda_1.SingletonFunction {
constructor(scope, id, props) {
if (id === undefined) {
aws_cdk_lib_1.Annotations.of(scope).addWarningV2('cdk-sops-secrets:omittingIdForSopsSyncProvider', 'Omitting id is deprecated. Please provide an id for the SopsSyncProvider. Default id will be removed in V3.');
}
super(scope, id ?? 'SopsSyncProvider', {
code: aws_lambda_1.Code.fromAsset(scope.node.tryGetContext('sops_sync_provider_asset_path') ||
path.join(__dirname, '../assets/cdk-sops-lambda.zip')),
runtime: aws_lambda_1.Runtime.PROVIDED_AL2023,
handler: 'bootstrap',
uuid: props?.uuid ?? 'SopsSyncProvider',
role: props?.role,
timeout: aws_cdk_lib_1.Duration.seconds(60),
environment: {
SOPS_AGE_KEY: aws_cdk_lib_1.Lazy.string({
produce: () => (this.sopsAgeKeys.map((secret) => secret.unsafeUnwrap()) ?? []).join('\n'),
}),
SOPS_AGE_KEY_PARAMS: aws_cdk_lib_1.Lazy.string({
produce: () => this.sopsAgeKeyParams.join('\n'),
}),
},
vpc: props?.vpc,
vpcSubnets: props?.vpcSubnets,
securityGroups: props?.securityGroups,
// props.logRetention is deprecated, make sure we only set it if it is actually provided
// otherwise jsii will print warnings even for users that don't use this directly
...(props?.logRetention ? { logRetention: props.logRetention } : {}),
logGroup: props?.logGroup,
});
this.sopsAgeKeys = [];
this.sopsAgeKeyParams = [];
}
addAgeKey(key) {
this.sopsAgeKeys.push(key);
}
/**
* Configure the Lambda to fetch an age private key from an SSM Parameter
* Store SecureString at runtime, rather than injecting it as a plaintext
* environment variable at synthesis time.
*
* The KMS key used to encrypt the SecureString is required: storing an age
* private key without envelope encryption is considered insecure.
*
* The Lambda is automatically granted `ssm:GetParameter` on the parameter
* and `kms:Decrypt` on the encryption key.
*
* @param param Parameter name string (e.g. '/sops/age/key') or an
* `IStringParameter` reference from `aws-cdk-lib/aws-ssm`.
* @param encryptionKey KMS key used to encrypt the SecureString parameter.
*/
addAgeKeyFromSsmParameter(param, encryptionKey) {
const parameterName = typeof param === 'string' ? param : param.parameterName;
this.sopsAgeKeyParams.push(parameterName);
const paramArn = aws_cdk_lib_1.Stack.of(this).formatArn({
service: 'ssm',
resource: 'parameter',
resourceName: parameterName.startsWith('/')
? parameterName.slice(1)
: parameterName,
arnFormat: aws_cdk_lib_1.ArnFormat.SLASH_RESOURCE_NAME,
});
this.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ['ssm:GetParameter'],
resources: [paramArn],
}));
encryptionKey.grantDecrypt(this);
}
}
exports.SopsSyncProvider = SopsSyncProvider;
_a = JSII_RTTI_SYMBOL_1;
SopsSyncProvider[_a] = { fqn: "cdk-sops-secrets.SopsSyncProvider", version: "2.8.1" };
/**
* The custom resource, that is syncing the content from a sops file to a secret.
*/
class SopsSync extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
const provider = props.sopsProvider ?? new SopsSyncProvider(scope, 'SopsSyncProvider');
let uploadType = props.uploadType ?? UploadType.INLINE;
let sopsFileFormat = props.sopsFileFormat;
let sopsAsset = undefined;
let sopsInline = undefined;
let sopsS3File = undefined;
if ((props.sopsFilePath == undefined &&
(props.sopsS3Bucket == undefined || props.sopsS3Key == undefined)) ||
(props.sopsFilePath !== undefined &&
props.sopsS3Bucket !== undefined &&
props.sopsS3Key !== undefined)) {
throw new Error('You can either specify sopsFilePath or sopsS3Bucket and sopsS3Key!');
}
if (props.sopsFilePath !== undefined) {
if (sopsFileFormat === undefined) {
const _sopsFileFormat = props.sopsFilePath.split('.').pop();
switch (_sopsFileFormat) {
case 'json': {
sopsFileFormat = 'json';
break;
}
case 'yaml': {
sopsFileFormat = 'yaml';
break;
}
case 'yml': {
sopsFileFormat = 'yaml';
break;
}
case 'dotenv': {
sopsFileFormat = 'dotenv';
break;
}
case 'env': {
sopsFileFormat = 'dotenv';
break;
}
case 'binary': {
sopsFileFormat = 'binary';
break;
}
default: {
aws_cdk_lib_1.Annotations.of(this).addError("Failed to determine sops file format. Please specify 'sopsFileFormat'!");
}
}
}
if (!fs.existsSync(props.sopsFilePath)) {
throw new Error(`File ${props.sopsFilePath} does not exist!`);
}
const sopsFileContent = fs.readFileSync(props.sopsFilePath);
switch (uploadType) {
case UploadType.INLINE: {
sopsInline = {
Content: sopsFileContent.toString('base64'),
// We calculate the hash the same way as it would be done by new Asset(..) - so we can ensure stable version names even if switching from INLINE to ASSET and viceversa.
Hash: aws_cdk_lib_1.FileSystem.fingerprint(props.sopsFilePath),
};
break;
}
case UploadType.ASSET: {
sopsAsset = new aws_s3_assets_1.Asset(this, 'Asset', {
path: props.sopsFilePath,
});
sopsS3File = {
Bucket: sopsAsset.bucket.bucketName,
Key: sopsAsset.s3ObjectKey,
};
break;
}
}
if (
// Is allways true, but to satisfy TS we check explicitly
provider.role !== undefined &&
// Check if user has disabled automatic generation
props.autoGenerateIamPermissions !== false) {
Permissions.sopsKeys(this, {
userDefinedKeys: props.sopsKmsKey,
role: provider.role,
sopsFileContent: sopsFileContent.toString(),
});
Permissions.assetBucket(this, sopsAsset, provider.role, props.assetEncryptionKey);
Permissions.encryptionKey(props.encryptionKey, provider.role);
Permissions.secret(props.secret, provider.role);
Permissions.parameters(this, props.parameterNames, provider.role);
}
else {
aws_cdk_lib_1.Annotations.of(this).addWarning([
'Please ensure proper permissions for the passed lambda function:',
' - write Access to the secret/parameters',
' - encrypt with the sopsKmsKey',
' - download from asset bucket',
].join('\n'));
}
if (props.sopsAgeKey !== undefined) {
provider.addAgeKey(props.sopsAgeKey);
}
}
else if (props.sopsS3Bucket !== undefined &&
props.sopsS3Key !== undefined) {
sopsS3File = {
Bucket: props.sopsS3Bucket,
Key: props.sopsS3Key,
};
uploadType = UploadType.ASSET;
aws_cdk_lib_1.Annotations.of(this).addWarning('You have to manually add permissions to the sops provider to (permission to download file, to decrypt sops file)!');
}
if (sopsFileFormat === undefined) {
throw new Error('You have to specify sopsFileFormat!');
}
const cr = new aws_cdk_lib_1.CustomResource(this, 'Resource', {
serviceToken: provider.functionArn,
resourceType: 'Custom::SopsSync',
properties: {
SopsS3File: sopsS3File,
SopsInline: sopsInline,
FlattenSeparator: props.flattenSeparator,
Format: sopsFileFormat,
EncryptionKey: props.encryptionKey?.keyId,
ResourceType: props.resourceType,
Target: props.target,
},
});
this.versionId = cr.getAttString('VersionId');
}
}
exports.SopsSync = SopsSync;
_b = JSII_RTTI_SYMBOL_1;
SopsSync[_b] = { fqn: "cdk-sops-secrets.SopsSync", version: "2.8.1" };
var Permissions;
(function (Permissions) {
/**
* Grants the necessary permissions for encrypt/decrypt on the customer managed encryption key
* for the secrets / parameters.
*/
function encryptionKey(key, target) {
if (key === undefined) {
return;
}
key.grantEncryptDecrypt(target);
}
Permissions.encryptionKey = encryptionKey;
function keysFromSopsContent(ctx, c) {
const regexKey = /arn:aws:kms:[a-z0-9-]+:[\d]+:key\/[a-z0-9-]+/g;
const resultsKey = c.match(regexKey);
if (resultsKey !== null) {
return resultsKey.map((result, index) => aws_kms_1.Key.fromKeyArn(ctx, `SopsKey${index}`, result));
}
return [];
}
Permissions.keysFromSopsContent = keysFromSopsContent;
function keysFromSopsContentAlias(ctx, c) {
const regexAlias = /arn:aws:kms:[a-z0-9-]+:[\d]+:alias\/[a-zA-Z0-9/-]+/g;
const resultsAlias = c.match(regexAlias);
if (resultsAlias !== null) {
return resultsAlias.map((result, index) => aws_kms_1.Key.fromLookup(ctx, `SopsAlias${index}`, {
aliasName: `alias/${result.split('/').slice(1).join('/')}`,
}));
}
return [];
}
Permissions.keysFromSopsContentAlias = keysFromSopsContentAlias;
/**
* Grants the necessary permissions to decrypt the given sops file content.
* Takes user defined keys, and searches the sops file for keys and aliases.
*/
function sopsKeys(ctx, props) {
(props.userDefinedKeys ?? [])
.concat(keysFromSopsContent(ctx, props.sopsFileContent), keysFromSopsContentAlias(ctx, props.sopsFileContent))
.forEach((key) => key.grantDecrypt(props.role));
}
Permissions.sopsKeys = sopsKeys;
/**
* Grants the necessary permissions to write the given secrets.
*/
function secret(targetSecret, target) {
if (targetSecret === undefined) {
return;
}
targetSecret.grantWrite(target);
}
Permissions.secret = secret;
function sliceParameters(params) {
const result = [];
/**
* The maximum size of a managed policy is 6.144 bytes -> 1 character = 1 byte
* bout 300 characters are reserved for the policy apart from resource arns
* with some buffer, we end with an upper limit of 5750 bytes
*/
const limit = 5750;
/**
* Content for "arn:aws:ssm:ap-southeast-3:{account-number}:parameter/
*/
const prefix = 55;
let currentSize = 0;
let currentChunk = [];
for (const param of params) {
const paramLength = param.length + prefix;
if (currentSize + paramLength > limit) {
result.push(currentChunk);
currentChunk = [];
currentSize = 0;
}
currentChunk.push(param);
currentSize += paramLength;
}
if (currentChunk.length > 0) {
result.push(currentChunk);
}
return result;
}
/**
* Grants the necessary permissions to write the given parameters.
*/
function parameters(ctx, targetParameters, role) {
if (targetParameters === undefined) {
return;
}
const paramSlices = sliceParameters(targetParameters);
for (let i = 0; i < paramSlices.length; i++) {
const putPolicy = new aws_iam_1.ManagedPolicy(ctx, `SopsSecretParameterProviderManagedPolicyParameterAccess${i}`, {
description: 'Policy to grant parameter provider permissions to put parameter',
});
putPolicy.addStatements(new aws_iam_1.PolicyStatement({
actions: ['ssm:PutParameter'],
resources: paramSlices[i].map((param) => `arn:aws:ssm:${aws_cdk_lib_1.Stack.of(ctx).region}:${aws_cdk_lib_1.Stack.of(ctx).account}:parameter${param.startsWith('/') ? param : `/${param}`}`),
}));
role.addManagedPolicy(putPolicy);
}
}
Permissions.parameters = parameters;
/**
* Grants the necessary permissions to read the given asset from S3.
*/
function assetBucket(context, asset, target, assetKey) {
if (asset === undefined) {
return;
}
asset.bucket.grantRead(target);
if (assetKey) {
assetKey.grantDecrypt(target);
}
else {
try {
const qualifier = aws_cdk_lib_1.Stack.of(context).synthesizer.bootstrapQualifier ?? 'hnb659fds'; // hnb659fds is the AWS global default qualifier
aws_kms_1.Key.fromLookup(context, 'AssetBucketKey', {
aliasName: `alias/cdk-bootstrap/${qualifier}`,
}).grantDecrypt(target);
}
catch (error) {
aws_cdk_lib_1.Annotations.of(context).addWarningV2('no-asset-kms-key', `An error occured while retreving the KMS-Key for the Asset S3-Bucket from CDK Bootstrap. Set encryption key manually by using props.assetEncryptionKey. ${error}`);
}
}
}
Permissions.assetBucket = assetBucket;
})(Permissions || (exports.Permissions = Permissions = {}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29wc1N5bmMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU29wc1N5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDZDQVNxQjtBQUVyQixpREFLNkI7QUFDN0IsaURBQWdEO0FBQ2hELHVEQUEwRTtBQUUxRSw2REFBa0Q7QUFHbEQsMkNBQXVDO0FBR3ZDLElBQVksVUFTWDtBQVRELFdBQVksVUFBVTtJQUNwQjs7T0FFRztJQUNILCtCQUFpQixDQUFBO0lBQ2pCOztPQUVHO0lBQ0gsNkJBQWUsQ0FBQTtBQUNqQixDQUFDLEVBVFcsVUFBVSwwQkFBVixVQUFVLFFBU3JCO0FBRUQsSUFBWSxZQU1YO0FBTkQsV0FBWSxZQUFZO0lBQ3RCLGlDQUFpQixDQUFBO0lBQ2pCLHlDQUF5QixDQUFBO0lBQ3pCLCtDQUErQixDQUFBO0lBQy9CLHVDQUF1QixDQUFBO0lBQ3ZCLG1EQUFtQyxDQUFBO0FBQ3JDLENBQUMsRUFOVyxZQUFZLDRCQUFaLFlBQVksUUFNdkI7QUFzTEQsTUFBYSxnQkFBaUIsU0FBUSw4QkFBaUI7SUFJckQsWUFBWSxLQUFnQixFQUFFLEVBQVcsRUFBRSxLQUE2QjtRQUN0RSxJQUFJLEVBQUUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNyQix5QkFBVyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLENBQ2hDLGdEQUFnRCxFQUNoRCw2R0FBNkcsQ0FDOUcsQ0FBQztRQUNKLENBQUM7UUFDRCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxrQkFBa0IsRUFBRTtZQUNyQyxJQUFJLEVBQUUsaUJBQUksQ0FBQyxTQUFTLENBQ2xCLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLCtCQUErQixDQUFDO2dCQUN2RCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSwrQkFBK0IsQ0FBQyxDQUN4RDtZQUNELE9BQU8sRUFBRSxvQkFBTyxD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QkFBdUIsU0FBUyxFQUFFO2lCQUM5QyxDQUFDLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzFCLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLHlCQUFXLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLFlBQVksQ0FDbEMsa0JBQWtCLEVBQ2xCLDJKQUEySixLQUFLLEVBQUUsQ0FDbkssQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQTNCZSx1QkFBVyxjQTJCMUIsQ0FBQTtBQUNILENBQUMsRUEzS2dCLFdBQVcsMkJBQVgsV0FBVyxRQTJLM0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtcbiAgQW5ub3RhdGlvbnMsXG4gIEFybkZvcm1hdCxcbiAgQ3VzdG9tUmVzb3VyY2UsXG4gIER1cmF0aW9uLFxuICBGaWxlU3lzdGVtLFxuICBMYXp5LFxuICBTZWNyZXRWYWx1ZSxcbiAgU3RhY2ssXG59IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IElTZWN1cml0eUdyb3VwLCBJVnBjLCBTdWJuZXRTZWxlY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCB7XG4gIElHcmFudGFibGUsXG4gIElSb2xlLFxuICBNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgSUtleSwgS2V5IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWttcyc7XG5pbXBvcnQgeyBDb2RlLCBSdW50aW1lLCBTaW5nbGV0b25GdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgUmV0ZW50aW9uRGF5cywgSUxvZ0dyb3VwIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgQXNzZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMtYXNzZXRzJztcbmltcG9ydCB7IElTZWNyZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXInO1xuaW1wb3J0IHsgSVN0cmluZ1BhcmFtZXRlciB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zc20nO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBTb3BzU3luY1Jlc291cmNlUHJvcGVydGllcyB9IGZyb20gJy4vTGFtYmRhSW50ZXJmYWNlJztcblxuZXhwb3J0IGVudW0gVXBsb2FkVHlwZSB7XG4gIC8qKlxuICAgKiBQYXNzIHRoZSBzZWNyZXQgZGF0YSBpbmxpbmUgKGJhc2U2NCBlbmNvZGVkIGFuZCBjb21wcmVzc2VkKVxuICAgKi9cbiAgSU5MSU5FID0gJ0lOTElORScsXG4gIC8qKlxuICAgKiBVcGxhb2QgdGhlIHNlY3JldCBkYXRhIGFzIGFzc2V0XG4gICAqL1xuICBBU1NFVCA9ICdBU1NFVCcsXG59XG5cbmV4cG9ydCBlbnVtIFJlc291cmNlVHlwZSB7XG4gIFNFQ1JFVCA9ICdTRUNSRVQnLFxuICBTRUNSRVRfUkFXID0gJ1NFQ1JFVF9SQVcnLFxuICBTRUNSRVRfQklOQVJZID0gJ1NFQ1JFVF9CSU5BUlknLFxuICBQQVJBTUVURVIgPSAnUEFSQU1FVEVSJyxcbiAgUEFSQU1FVEVSX01VTFRJID0gJ1BBUkFNRVRFUl9NVUxUSScsXG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgU29wc1N5bmNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTb3BzU3luY09wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGN1c3RvbSByZXNvdXJjZSBwcm92aWRlciB0byB1c2UuIElmIHlvdSBkb24ndCBzcGVjaWZ5IGFueSwgYSBuZXdcbiAgICogcHJvdmlkZXIgd2lsbCBiZSBjcmVhdGVkIC0gb3IgaWYgYWxyZWFkeSBleGlzdHMgd2l0aGluIHRoaXMgc3RhY2sgLSByZXVzZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQSBuZXcgc2luZ2xldG9uIHByb3ZpZGVyIHdpbGwgYmUgY3JlYXRlZFxuICAgKi9cbiAgcmVhZG9ubHkgc29wc1Byb3ZpZGVyPzogU29wc1N5bmNQcm92aWRlcjtcblxuICAvKipcbiAgICogVGhlIGZpbGVwYXRoIHRvIHRoZSBzb3BzIGZpbGVcbiAgICovXG4gIHJlYWRvbmx5IHNvcHNGaWxlUGF0aD86IHN0cmluZztcblxuICAvKipcbiAgICogSWYgeW91IHdhbnQgdG8gcGFzcyB0aGUgc29wcyBmaWxlIHZpYSBzMywgeW91IGNhbiBzcGVjaWZ5IHRoZSBidWNrZXRcbiAgICogeW91IGNhbiB1c2UgY2ZuIHBhcmFtZXRlciBoZXJlXG4gICAqIEJvdGgsIHNvcHNTM0J1Y2tldCBhbmQgc29wc1MzS2V5IGhhdmUgdG8gYmUgc3BlY2lmaWVkXG4gICAqL1xuICByZWFkb25seSBzb3BzUzNCdWNrZXQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIElmIHlvdSB3YW50IHRvIHBhc3MgdGhlIHNvcHMgZmlsZSB2aWEgczMsIHlvdSBjYW4gc3BlY2lmeSB0aGUga2V5IGluc2lkZSB0aGUgYnVja2V0XG4gICAqIHlvdSBjYW4gdXNlIGNmbiBwYXJhbWV0ZXIgaGVyZVxuICAgKiBCb3RoLCBzb3BzUzNCdWNrZXQgYW5kIHNvcHNTM0tleSBoYXZlIHRvIGJlIHNwZWNpZmllZFxuICAgKi9cbiAgcmVhZG9ubHkgc29wc1MzS2V5Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBIb3cgc2hvdWxkIHRoZSBzZWNyZXQgYmUgcGFzc2VkIHRvIHRoZSBDdXN0b21SZXNvdXJjZT9cbiAgICogQGRlZmF1bHQgSU5MSU5FXG4gICAqL1xuICByZWFkb25seSB1cGxvYWRUeXBlPzogVXBsb2FkVHlwZTtcblxuICAvKipcbiAgICogVGhlIGZvcm1hdCBvZiB0aGUgc29wcyBmaWxlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFRoZSBmaWxlZm9ybWF0IHdpbGwgYmUgZGVyaXZlZCBmcm9tIHRoZSBmaWxlIGVuZGluZ1xuICAgKi9cbiAgcmVhZG9ubHkgc29wc0ZpbGVGb3JtYXQ/OiB1bmRlZmluZWQgfCAnanNvbicgfCAneWFtbCcgfCAnZG90ZW52JyB8ICdiaW5hcnknO1xuXG4gIC8qKlxuICAgKiBUaGUga21zS2V5IHVzZWQgdG8gZW5jcnlwdCB0aGUgc29wcyBmaWxlLiBFbmNyeXB0IHBlcm1pc3Npb25zXG4gICAqIHdpbGwgYmUgZ3JhbnRlZCB0byB0aGUgY3VzdG9tIHJlc291cmNlIHByb3ZpZGVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFRoZSBrZXkgd2lsbCBiZSBkZXJpdmVkIGZyb20gdGhlIHNvcHMgZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgc29wc0ttc0tleT86IElLZXlbXTtcblxuICAvKipcbiAgICogVGhlIGFnZSBrZXkgdGhhdCBzaG91bGQgYmUgdXNlZCBmb3IgZW5jcnlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHNvcHNBZ2VLZXk/OiBTZWNyZXRWYWx1ZTtcblxuICAvKipcbiAgICogU2hvdWxkIHRoaXMgY29uc3RydWN0IGF1dG9tYXRpY2FsbHkgY3JlYXRlIElBTSBwZXJtaXNzaW9ucz9cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgYXV0b0dlbmVyYXRlSWFtUGVybWlzc2lvbnM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgZW5jcnlwdGlvbiBrZXkgdXNlZCBieSB0aGUgQ0RLIGRlZmF1bHQgQXNzZXQgUzMgQnVja2V0LlxuICAgKiBAZGVmYXVsdCAtIFRyeWluZyB0byBnZXQgdGhlIGtleSB1c2luZyB0aGUgQ0RLIEJvb3RzdHJhcCBjb250ZXh0LlxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXRFbmNyeXB0aW9uS2V5PzogSUtleTtcbn1cblxuLyoqXG4gKiBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIGV4dGVuZGVkIGJ5IHRoZSB0YXJnZXQgU2VjcmV0IC8gUGFyYW1ldGVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU29wc1N5bmNQcm9wcyBleHRlbmRzIFNvcHNTeW5jT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgdGFyZ2V0IHRvIHBvcHVsYXRlIHdpdGggdGhlIHNvcHMgZmlsZSBjb250ZW50LlxuICAgKiAtIGZvciBzZWNyZXQsIGl0J3MgdGhlIG5hbWUgb3IgYXJuIG9mIHRoZSBzZWNyZXRcbiAgICogLSBmb3IgcGFyYW1ldGVyLCBpdCdzIHRoZSBuYW1lIG9mIHRoZSBwYXJhbWV0ZXJcbiAgICogLSBmb3IgcGFyYW1ldGVyIG11bHRpLCBpdCdzIHRoZSBwcmVmaXggb2YgdGhlIHBhcmFtZXRlcnNcbiAgICovXG4gIHJlYWRvbmx5IHRhcmdldDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJZiB0aGUgc3RydWN0dXJlIHNob3VsZCBiZSBmbGF0dGVuZWQgdXNlIHRoZSBwcm92aWRlZCBzZXBhcmF0b3IgYmV0d2VlbiBrZXlzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgZmxhdHRlblNlcGFyYXRvcj86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGVuY3J5cHRpb24ga2V5IHVzZWQgZm9yIGVuY3J5cHRpbmcgdGhlIHNzbSBwYXJhbWV0ZXIgaWYgYHBhcmFtZXRlck5hbWVgIGlzIHNldC5cbiAgICovXG4gIHJlYWRvbmx5IGVuY3J5cHRpb25LZXk/OiBJS2V5O1xuXG4gIC8qKlxuICAgKiBXaWxsIHRoaXMgU3luYyBkZXBsb3kgYSBTZWNyZXQgb3IgUGFyYW1ldGVyKHMpXG4gICAqL1xuICByZWFkb25seSByZXNvdXJjZVR5cGU6IFJlc291cmNlVHlwZTtcblxuICByZWFkb25seSBzZWNyZXQ/OiBJU2VjcmV0O1xuICByZWFkb25seSBwYXJhbWV0ZXJOYW1lcz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgYSBjdXN0b20gU29wc1N5bmNQcm92aWRlci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTb3BzU3luY1Byb3ZpZGVyUHJvcHMge1xuICAvKipcbiAgICogVlBDIG5ldHdvcmsgdG8gcGxhY2UgTGFtYmRhIG5ldHdvcmsgaW50ZXJmYWNlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBMYW1iZGEgZnVuY3Rpb24gaXMgbm90IHBsYWNlZCB3aXRoaW4gYSBWUEMuXG4gICAqL1xuICByZWFkb25seSB2cGM/OiBJVnBjO1xuICAvKipcbiAgICogV2hlcmUgdG8gcGxhY2UgdGhlIG5ldHdvcmsgaW50ZXJmYWNlcyB3aXRoaW4gdGhlIFZQQy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBTdWJuZXRzIHdpbGwgYmUgY2hvc2VuIGF1dG9tYXRpY2FsbHkuXG4gICAqL1xuICByZWFkb25seSB2cGNTdWJuZXRzPzogU3VibmV0U2VsZWN0aW9uO1xuICAvKipcbiAgICogT25seSBpZiBgdnBjYCBpcyBzdXBwbGllZDogVGhlIGxpc3Qgb2Ygc2VjdXJpdHkgZ3JvdXBzIHRvIGFzc29jaWF0ZSB3aXRoIHRoZSBMYW1iZGEncyBuZXR3b3JrIGludGVyZmFjZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQSBkZWRpY2F0ZWQgc2VjdXJpdHkgZ3JvdXAgd2lsbCBiZSBjcmVhdGVkIGZvciB0aGUgbGFtYmRhIGZ1bmN0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjdXJpdHlHcm91cHM/OiBJU2VjdXJpdHlHcm91cFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgcm9sZSB0aGF0IHNob3VsZCBiZSB1c2VkIGZvciB0aGUgY3VzdG9tIHJlc291cmNlIHByb3ZpZGVyLlxuICAgKiBJZiB5b3UgZG9uJ3Qgc3BlY2lmeSBhbnksIGEgbmV3IHJvbGUgd2lsbCBiZSBjcmVhdGVkIHdpdGggYWxsIHJlcXVpcmVkIHBlcm1pc3Npb25zXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gYSBuZXcgcm9sZSB3aWxsIGJlIGNyZWF0ZWRcbiAgICovXG4gIHJlYWRvbmx5IHJvbGU/OiBJUm9sZTtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF5cyBsb2cgZXZlbnRzIGFyZSBrZXB0IGluIENsb3VkV2F0Y2ggTG9ncy4gV2hlbiB1cGRhdGluZ1xuICAgKiB0aGlzIHByb3BlcnR5LCB1bnNldHRpbmcgaXQgZG9lc24ndCByZW1vdmUgdGhlIGxvZyByZXRlbnRpb24gcG9saWN5LiBUb1xuICAgKiByZW1vdmUgdGhlIHJldGVudGlvbiBwb2xpY3ksIHNldCB0aGUgdmFsdWUgdG8gYElORklOSVRFYC5cbiAgICpcbiAgICogVGhpcyBpcyBhIGxlZ2FjeSBBUEkgYW5kIHdlIHN0cm9uZ2x5IHJlY29tbWVuZCB5b3UgbW92ZSBhd2F5IGZyb20gaXQgaWYgeW91IGNhbi5cbiAgICogSW5zdGVhZCBjcmVhdGUgYSBmdWxseSBjdXN0b21pemFibGUgbG9nIGdyb3VwIHdpdGggYGxvZ3MuTG9nR3JvdXBgIGFuZCB1c2UgdGhlIGBsb2dHcm91cGAgcHJvcGVydHlcbiAgICogdG8gaW5zdHJ1Y3QgdGhlIExhbWJkYSBmdW5jdGlvbiB0byBzZW5kIGxvZ3MgdG8gaXQuXG4gICAqIE1pZ3JhdGluZyBmcm9tIGBsb2dSZXRlbnRpb25gIHRvIGBsb2dHcm91cGAgd2lsbCBjYXVzZSB0aGUgbmFtZSBvZiB0aGUgbG9nIGdyb3VwIHRvIGNoYW5nZS5cbiAgICogVXNlcnMgYW5kIGNvZGUgYW5kIHJlZmVyZW5jaW5nIHRoZSBuYW1lIHZlcmJhdGltIHdpbGwgaGF2ZSB0byBhZGp1c3QuXG4gICAqXG4gICAqIEluIEFXUyBDREsgY29kZSwgeW91IGNhbiBhY2Nlc3MgdGhlIGxvZyBncm91cCBuYW1lIGRpcmVjdGx5IGZyb20gdGhlIExvZ0dyb3VwIGNvbnN0cnVjdDpcbiAgICogYGBgdHNcbiAgICogaW1wb3J0ICogYXMgbG9ncyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG4gICAqXG4gICAqIGRlY2xhcmUgY29uc3QgbXlMb2dHcm91cDogbG9ncy5Mb2dHcm91cDtcbiAgICogbXlMb2dHcm91cC5sb2dHcm91cE5hbWU7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZGVmYXVsdCBsb2dzLlJldGVudGlvbkRheXMuSU5GSU5JVEVcbiAgICovXG4gIHJlYWRvbmx5IGxvZ1JldGVudGlvbj86IFJldGVudGlvbkRheXM7XG4gIC8qKlxuICAgKiBUaGUgbG9nIGdyb3VwIHRoZSBmdW5jdGlvbiBzZW5kcyBsb2dzIHRvLlxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCBMYW1iZGEgZnVuY3Rpb25zIHNlbmQgbG9ncyB0byBhbiBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgZGVmYXVsdCBsb2cgZ3JvdXAgbmFtZWQgL2F3cy9sYW1iZGEve2Z1bmN0aW9uLW5hbWV9LlxuICAgKiBIb3dldmVyIHlvdSBjYW5ub3QgY2hhbmdlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoaXMgYXV0by1jcmVhdGVkIGxvZyBncm91cCB1c2luZyB0aGUgQVdTIENESywgZS5nLiB5b3UgY2Fubm90IHNldCBhIGRpZmZlcmVudCBsb2cgcmV0ZW50aW9uLlxuICAgKlxuICAgKiBVc2UgdGhlIGBsb2dHcm91cGAgcHJvcGVydHkgdG8gY3JlYXRlIGEgZnVsbHkgY3VzdG9taXphYmxlIExvZ0dyb3VwIGFoZWFkIG9mIHRpbWUsIGFuZCBpbnN0cnVjdCB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRvIHNlbmQgbG9ncyB0byBpdC5cbiAgICpcbiAgICogUHJvdmlkaW5nIGEgdXNlci1jb250cm9sbGVkIGxvZyBncm91cCB3YXMgcm9sbGVkIG91dCB0byBjb21tZXJjaWFsIHJlZ2lvbnMgb24gMjAyMy0xMS0xNi5cbiAgICogSWYgeW91IGFyZSBkZXBsb3lpbmcgdG8gYW5vdGhlciB0eXBlIG9mIHJlZ2lvbiwgcGxlYXNlIGNoZWNrIHJlZ2lvbmFsIGF2YWlsYWJpbGl0eSBmaXJzdC5cbiAgICpcbiAgICogQGRlZmF1bHQgYC9hd3MvbGFtYmRhLyR7dGhpcy5mdW5jdGlvbk5hbWV9YCAtIGRlZmF1bHQgbG9nIGdyb3VwIGNyZWF0ZWQgYnkgTGFtYmRhXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cD86IElMb2dHcm91cDtcbiAgLyoqXG4gICAqIEEgdW5pcXVlIGlkZW50aWZpZXIgdG8gaWRlbnRpZnkgdGhpcyBwcm92aWRlclxuICAgKlxuICAgKiBPdmVyd3JpdGUgdGhlIGRlZmF1bHQsIGlmIHlvdSBuZWVkIGEgZGVkaWNhdGVkIHByb3ZpZGVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCBTb3BzU3luY1Byb3ZpZGVyXG4gICAqL1xuICByZWFkb25seSB1dWlkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgU29wc1N5bmNQcm92aWRlciBleHRlbmRzIFNpbmdsZXRvbkZ1bmN0aW9uIGltcGxlbWVudHMgSUdyYW50YWJsZSB7XG4gIHByaXZhdGUgc29wc0FnZUtleXM6IFNlY3JldFZhbHVlW107XG4gIHByaXZhdGUgc29wc0FnZUtleVBhcmFtczogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ/OiBzdHJpbmcsIHByb3BzPzogU29wc1N5bmNQcm92aWRlclByb3BzKSB7XG4gICAgaWYgKGlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIEFubm90YXRpb25zLm9mKHNjb3BlKS5hZGRXYXJuaW5nVjIoXG4gICAgICAgICdjZGstc29wcy1zZWNyZXRzOm9taXR0aW5nSWRGb3JTb3BzU3luY1Byb3ZpZGVyJyxcbiAgICAgICAgJ09taXR0aW5nIGlkIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSBwcm92aWRlIGFuIGlkIGZvciB0aGUgU29wc1N5bmNQcm92aWRlci4gRGVmYXVsdCBpZCB3aWxsIGJlIHJlbW92ZWQgaW4gVjMuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIHN1cGVyKHNjb3BlLCBpZCA/PyAnU29wc1N5bmNQcm92aWRlcicsIHtcbiAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KFxuICAgICAgICBzY29wZS5ub2RlLnRyeUdldENvbnRleHQoJ3NvcHNfc3luY19wcm92aWRlcl9hc3NldF9wYXRoJykgfHxcbiAgICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vYXNzZXRzL2Nkay1zb3BzLWxhbWJkYS56aXAnKSxcbiAgICAgICksXG4gICAgICBydW50aW1lOiBSdW50aW1lLlBST1ZJREVEX0FMMjAyMyxcbiAgICAgIGhhbmRsZXI6ICdib290c3RyYXAnLFxuICAgICAgdXVpZDogcHJvcHM/LnV1aWQgPz8gJ1NvcHNTeW5jUHJvdmlkZXInLFxuICAgICAgcm9sZTogcHJvcHM/LnJvbGUsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDYwKSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFNPUFNfQUdFX0tFWTogTGF6eS5zdHJpbmcoe1xuICAgICAgICAgIHByb2R1Y2U6ICgpID0+XG4gICAgICAgICAgICAoXG4gICAgICAgICAgICAgIHRoaXMuc29wc0FnZUtleXMubWFwKChzZWNyZXQpID0+IHNlY3JldC51bnNhZmVVbndyYXAoKSkgPz8gW11cbiAgICAgICAgICAgICkuam9pbignXFxuJyksXG4gICAgICAgIH0pLFxuICAgICAgICBTT1BTX0FHRV9LRVlfUEFSQU1TOiBMYXp5LnN0cmluZyh7XG4gICAgICAgICAgcHJvZHVjZTogKCkgPT4gdGhpcy5zb3BzQWdlS2V5UGFyYW1zLmpvaW4oJ1xcbicpLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgICB2cGM6IHByb3BzPy52cGMsXG4gICAgICB2cGNTdWJuZXRzOiBwcm9wcz8udnBjU3VibmV0cyxcbiAgICAgIHNlY3VyaXR5R3JvdXBzOiBwcm9wcz8uc2VjdXJpdHlHcm91cHMsXG4gICAgICAvLyBwcm9wcy5sb2dSZXRlbnRpb24gaXMgZGVwcmVjYXRlZCwgbWFrZSBzdXJlIHdlIG9ubHkgc2V0IGl0IGlmIGl0IGlzIGFjdHVhbGx5IHByb3ZpZGVkXG4gICAgICAvLyBvdGhlcndpc2UganNpaSB3aWxsIHByaW50IHdhcm5pbmdzIGV2ZW4gZm9yIHVzZXJzIHRoYXQgZG9uJ3QgdXNlIHRoaXMgZGlyZWN0bHlcbiAgICAgIC4uLihwcm9wcz8ubG9nUmV0ZW50aW9uID8geyBsb2dSZXRlbnRpb246IHByb3BzLmxvZ1JldGVudGlvbiB9IDoge30pLFxuICAgICAgbG9nR3JvdXA6IHByb3BzPy5sb2dHcm91cCxcbiAgICB9KTtcbiAgICB0aGlzLnNvcHNBZ2VLZXlzID0gW107XG4gICAgdGhpcy5zb3BzQWdlS2V5UGFyYW1zID0gW107XG4gIH1cblxuICBwdWJsaWMgYWRkQWdlS2V5KGtleTogU2VjcmV0VmFsdWUpIHtcbiAgICB0aGlzLnNvcHNBZ2VLZXlzLnB1c2goa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25maWd1cmUgdGhlIExhbWJkYSB0byBmZXRjaCBhbiBhZ2UgcHJpdmF0ZSBrZXkgZnJvbSBhbiBTU00gUGFyYW1ldGVyXG4gICAqIFN0b3JlIFNlY3VyZVN0cmluZyBhdCBydW50aW1lLCByYXRoZXIgdGhhbiBpbmplY3RpbmcgaXQgYXMgYSBwbGFpbnRleHRcbiAgICogZW52aXJvbm1lbnQgdmFyaWFibGUgYXQgc3ludGhlc2lzIHRpbWUuXG4gICAqXG4gICAqIFRoZSBLTVMga2V5IHVzZWQgdG8gZW5jcnlwdCB0aGUgU2VjdXJlU3RyaW5nIGlzIHJlcXVpcmVkOiBzdG9yaW5nIGFuIGFnZVxuICAgKiBwcml2YXRlIGtleSB3aXRob3V0IGVudmVsb3BlIGVuY3J5cHRpb24gaXMgY29uc2lkZXJlZCBpbnNlY3VyZS5cbiAgICpcbiAgICogVGhlIExhbWJkYSBpcyBhdXRvbWF0aWNhbGx5IGdyYW50ZWQgYHNzbTpHZXRQYXJhbWV0ZXJgIG9uIHRoZSBwYXJhbWV0ZXJcbiAgICogYW5kIGBrbXM6RGVjcnlwdGAgb24gdGhlIGVuY3J5cHRpb24ga2V5LlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW0gICAgICAgICAgUGFyYW1ldGVyIG5hbWUgc3RyaW5nIChlLmcuICcvc29wcy9hZ2Uva2V5Jykgb3IgYW5cbiAgICogICAgICAgICAgICAgICAgICAgICAgIGBJU3RyaW5nUGFyYW1ldGVyYCByZWZlcmVuY2UgZnJvbSBgYXdzLWNkay1saWIvYXdzLXNzbWAuXG4gICAqIEBwYXJhbSBlbmNyeXB0aW9uS2V5ICBLTVMga2V5IHVzZWQgdG8gZW5jcnlwdCB0aGUgU2VjdXJlU3RyaW5nIHBhcmFtZXRlci5cbiAgICovXG4gIHB1YmxpYyBhZGRBZ2VLZXlGcm9tU3NtUGFyYW1ldGVyKFxuICAgIHBhcmFtOiBzdHJpbmcgfCBJU3RyaW5nUGFyYW1ldGVyLFxuICAgIGVuY3J5cHRpb25LZXk6IElLZXksXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBhcmFtZXRlck5hbWUgPVxuICAgICAgdHlwZW9mIHBhcmFtID09PSAnc3RyaW5nJyA/IHBhcmFtIDogcGFyYW0ucGFyYW1ldGVyTmFtZTtcbiAgICB0aGlzLnNvcHNBZ2VLZXlQYXJhbXMucHVzaChwYXJhbWV0ZXJOYW1lKTtcblxuICAgIGNvbnN0IHBhcmFtQXJuID0gU3RhY2sub2YodGhpcykuZm9ybWF0QXJuKHtcbiAgICAgIHNlcnZpY2U6ICdzc20nLFxuICAgICAgcmVzb3VyY2U6ICdwYXJhbWV0ZXInLFxuICAgICAgcmVzb3VyY2VOYW1lOiBwYXJhbWV0ZXJOYW1lLnN0YXJ0c1dpdGgoJy8nKVxuICAgICAgICA/IHBhcmFtZXRlck5hbWUuc2xpY2UoMSlcbiAgICAgICAgOiBwYXJhbWV0ZXJOYW1lLFxuICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICB9KTtcblxuICAgIHRoaXMuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFsnc3NtOkdldFBhcmFtZXRlciddLFxuICAgICAgICByZXNvdXJjZXM6IFtwYXJhbUFybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgZW5jcnlwdGlvbktleS5ncmFudERlY3J5cHQodGhpcyk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgY3VzdG9tIHJlc291cmNlLCB0aGF0IGlzIHN5bmNpbmcgdGhlIGNvbnRlbnQgZnJvbSBhIHNvcHMgZmlsZSB0byBhIHNlY3JldC5cbiAqL1xuZXhwb3J0IGNsYXNzIFNvcHNTeW5jIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHZlcnNpb25JZCBvZiB0aGUgc2VjcmV0IHBvcHVsYXRlZCB2aWEgdGhpcyByZXNvdXJjZVxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbklkOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFNvcHNTeW5jUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgcHJvdmlkZXIgPVxuICAgICAgcHJvcHMuc29wc1Byb3ZpZGVyID8/IG5ldyBTb3BzU3luY1Byb3ZpZGVyKHNjb3BlLCAnU29wc1N5bmNQcm92aWRlcicpO1xuXG4gICAgbGV0IHVwbG9hZFR5cGUgPSBwcm9wcy51cGxvYWRUeXBlID8/IFVwbG9hZFR5cGUuSU5MSU5FO1xuICAgIGxldCBzb3BzRmlsZUZvcm1hdDogJ2pzb24nIHwgJ3lhbWwnIHwgJ2RvdGVudicgfCAnYmluYXJ5JyB8IHVuZGVmaW5lZCA9XG4gICAgICBwcm9wcy5zb3BzRmlsZUZvcm1hdDtcbiAgICBsZXQgc29wc0Fzc2V0OiBBc3NldCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBsZXQgc29wc0lubGluZTogeyBDb250ZW50OiBzdHJpbmc7IEhhc2g6IHN0cmluZyB9IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgIGxldCBzb3BzUzNGaWxlOiB7IEJ1Y2tldDogc3RyaW5nOyBLZXk6IHN0cmluZyB9IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXG4gICAgaWYgKFxuICAgICAgKHByb3BzLnNvcHNGaWxlUGF0aCA9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHByb3BzLnNvcHNTM0J1Y2tldCA9PSB1bmRlZmluZWQgfHwgcHJvcHMuc29wc1MzS2V5ID09IHVuZGVmaW5lZCkpIHx8XG4gICAgICAocHJvcHMuc29wc0ZpbGVQYXRoICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgcHJvcHMuc29wc1MzQnVja2V0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgcHJvcHMuc29wc1MzS2V5ICE9PSB1bmRlZmluZWQpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdZb3UgY2FuIGVpdGhlciBzcGVjaWZ5IHNvcHNGaWxlUGF0aCBvciBzb3BzUzNCdWNrZXQgYW5kIHNvcHNTM0tleSEnLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHMuc29wc0ZpbGVQYXRoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChzb3BzRmlsZUZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IF9zb3BzRmlsZUZvcm1hdCA9IHByb3BzLnNvcHNGaWxlUGF0aC5zcGxpdCgnLicpLnBvcCgpO1xuICAgICAgICBzd2l0Y2ggKF9zb3BzRmlsZUZvcm1hdCkge1xuICAgICAgICAgIGNhc2UgJ2pzb24nOiB7XG4gICAgICAgICAgICBzb3BzRmlsZUZvcm1hdCA9ICdqc29uJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICd5YW1sJzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAneWFtbCc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgY2FzZSAneW1sJzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAneWFtbCc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgY2FzZSAnZG90ZW52Jzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAnZG90ZW52JztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICdlbnYnOiB7XG4gICAgICAgICAgICBzb3BzRmlsZUZvcm1hdCA9ICdkb3RlbnYnO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNhc2UgJ2JpbmFyeSc6IHtcbiAgICAgICAgICAgIHNvcHNGaWxlRm9ybWF0ID0gJ2JpbmFyeSc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkRXJyb3IoXG4gICAgICAgICAgICAgIFwiRmFpbGVkIHRvIGRldGVybWluZSBzb3BzIGZpbGUgZm9ybWF0LiBQbGVhc2Ugc3BlY2lmeSAnc29wc0ZpbGVGb3JtYXQnIVwiLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHByb3BzLnNvcHNGaWxlUGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaWxlICR7cHJvcHMuc29wc0ZpbGVQYXRofSBkb2VzIG5vdCBleGlzdCFgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNvcHNGaWxlQ29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhwcm9wcy5zb3BzRmlsZVBhdGgpO1xuXG4gICAgICBzd2l0Y2ggKHVwbG9hZFR5cGUpIHtcbiAgICAgICAgY2FzZSBVcGxvYWRUeXBlLklOTElORToge1xuICAgICAgICAgIHNvcHNJbmxpbmUgPSB7XG4gICAgICAgICAgICBDb250ZW50OiBzb3BzRmlsZUNvbnRlbnQudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgICAgICAgICAgLy8gV2UgY2FsY3VsYXRlIHRoZSBoYXNoIHRoZSBzYW1lIHdheSBhcyBpdCB3b3VsZCBiZSBkb25lIGJ5IG5ldyBBc3NldCguLikgLSBzbyB3ZSBjYW4gZW5zdXJlIHN0YWJsZSB2ZXJzaW9uIG5hbWVzIGV2ZW4gaWYgc3dpdGNoaW5nIGZyb20gSU5MSU5FIHRvIEFTU0VUIGFuZCB2aWNldmVyc2EuXG4gICAgICAgICAgICBIYXNoOiBGaWxlU3lzdGVtLmZpbmdlcnByaW50KHByb3BzLnNvcHNGaWxlUGF0aCksXG4gICAgICAgICAgfTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFVwbG9hZFR5cGUuQVNTRVQ6IHtcbiAgICAgICAgICBzb3BzQXNzZXQgPSBuZXcgQXNzZXQodGhpcywgJ0Fzc2V0Jywge1xuICAgICAgICAgICAgcGF0aDogcHJvcHMuc29wc0ZpbGVQYXRoLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHNvcHNTM0ZpbGUgPSB7XG4gICAgICAgICAgICBCdWNrZXQ6IHNvcHNBc3NldC5idWNrZXQuYnVja2V0TmFtZSxcbiAgICAgICAgICAgIEtleTogc29wc0Fzc2V0LnMzT2JqZWN0S2V5LFxuICAgICAgICAgIH07XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICAvLyBJcyBhbGx3YXlzIHRydWUsIGJ1dCB0byBzYXRpc2Z5IFRTIHdlIGNoZWNrIGV4cGxpY2l0bHlcbiAgICAgICAgcHJvdmlkZXIucm9sZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgIC8vIENoZWNrIGlmIHVzZXIgaGFzIGRpc2FibGVkIGF1dG9tYXRpYyBnZW5lcmF0aW9uXG4gICAgICAgIHByb3BzLmF1dG9HZW5lcmF0ZUlhbVBlcm1pc3Npb25zICE9PSBmYWxzZVxuICAgICAgKSB7XG4gICAgICAgIFBlcm1pc3Npb25zLnNvcHNLZXlzKHRoaXMsIHtcbiAgICAgICAgICB1c2VyRGVmaW5lZEtleXM6IHByb3BzLnNvcHNLbXNLZXksXG4gICAgICAgICAgcm9sZTogcHJvdmlkZXIucm9sZSxcbiAgICAgICAgICBzb3BzRmlsZUNvbnRlbnQ6IHNvcHNGaWxlQ29udGVudC50b1N0cmluZygpLFxuICAgICAgICB9KTtcbiAgICAgICAgUGVybWlzc2lvbnMuYXNzZXRCdWNrZXQoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBzb3BzQXNzZXQsXG4gICAgICAgICAgcHJvdmlkZXIucm9sZSxcbiAgICAgICAgICBwcm9wcy5hc3NldEVuY3J5cHRpb25LZXksXG4gICAgICAgICk7XG4gICAgICAgIFBlcm1pc3Npb25zLmVuY3J5cHRpb25LZXkocHJvcHMuZW5jcnlwdGlvbktleSwgcHJvdmlkZXIucm9sZSk7XG4gICAgICAgIFBlcm1pc3Npb25zLnNlY3JldChwcm9wcy5zZWNyZXQsIHByb3ZpZGVyLnJvbGUpO1xuICAgICAgICBQZXJtaXNzaW9ucy5wYXJhbWV0ZXJzKHRoaXMsIHByb3BzLnBhcmFtZXRlck5hbWVzLCBwcm92aWRlci5yb2xlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIEFubm90YXRpb25zLm9mKHRoaXMpLmFkZFdhcm5pbmcoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgJ1BsZWFzZSBlbnN1cmUgcHJvcGVyIHBlcm1pc3Npb25zIGZvciB0aGUgcGFzc2VkIGxhbWJkYSBmdW5jdGlvbjonLFxuICAgICAgICAgICAgJyAgLSB3cml0ZSBBY2Nlc3MgdG8gdGhlIHNlY3JldC9wYXJhbWV0ZXJzJyxcbiAgICAgICAgICAgICcgIC0gZW5jcnlwdCB3aXRoIHRoZSBzb3BzS21zS2V5JyxcbiAgICAgICAgICAgICcgIC0gZG93bmxvYWQgZnJvbSBhc3NldCBidWNrZXQnLFxuICAgICAgICAgIF0uam9pbignXFxuJyksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAocHJvcHMuc29wc0FnZUtleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHByb3ZpZGVyLmFkZEFnZUtleShwcm9wcy5zb3BzQWdlS2V5KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKFxuICAgICAgcHJvcHMuc29wc1MzQnVja2V0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIHByb3BzLnNvcHNTM0tleSAhPT0gdW5kZWZpbmVkXG4gICAgKSB7XG4gICAgICBzb3BzUzNGaWxlID0ge1xuICAgICAgICBCdWNrZXQ6IHByb3BzLnNvcHNTM0J1Y2tldCxcbiAgICAgICAgS2V5OiBwcm9wcy5zb3BzUzNLZXksXG4gICAgICB9O1xuICAgICAgdXBsb2FkVHlwZSA9IFVwbG9hZFR5cGUuQVNTRVQ7XG4gICAgICBBbm5vdGF0aW9ucy5vZih0aGlzKS5hZGRXYXJuaW5nKFxuICAgICAgICAnWW91IGhhdmUgdG8gbWFudWFsbHkgYWRkIHBlcm1pc3Npb25zIHRvIHRoZSBzb3BzIHByb3ZpZGVyIHRvIChwZXJtaXNzaW9uIHRvIGRvd25sb2FkIGZpbGUsIHRvIGRlY3J5cHQgc29wcyBmaWxlKSEnLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoc29wc0ZpbGVGb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhy