@cdklabs/cdk-hyperledger-fabric-network
Version:
CDK construct to deploy a Hyperledger Fabric network running on Amazon Managed Blockchain
132 lines • 20.2 kB
JavaScript
;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0
Object.defineProperty(exports, "__esModule", { value: true });
exports.HyperledgerFabricIdentity = void 0;
const child_process_1 = require("child_process");
const path = require("path");
const cdk = require("aws-cdk-lib");
const ec2 = require("aws-cdk-lib/aws-ec2");
const iam = require("aws-cdk-lib/aws-iam");
const lambda = require("aws-cdk-lib/aws-lambda");
const logs = require("aws-cdk-lib/aws-logs");
const customresources = require("aws-cdk-lib/custom-resources");
const constructs = require("constructs");
const utilities = require("./utilities");
/**
* Creates custom resources to enroll admin and register user
* identities with the CA using the fabric-ca-client SDK.
* Admin identity is enrolled by default. User identities are
* registered and enrolled, if provided.
*/
class HyperledgerFabricIdentity extends constructs.Construct {
constructor(scope, id) {
super(scope, id);
// Collect metadata on the stack
const partition = cdk.Stack.of(this).partition;
const region = cdk.Stack.of(this).region;
// Retrieve the S3 Bucket and key that contains the TLS cert file
const tlsBucketData = utilities.getTlsBucket(region);
const adminPasswordArn = scope.adminPasswordSecret.secretArn;
const adminPrivateKeyArn = scope.adminPrivateKeySecret.secretArn;
const adminSignedCertArn = scope.adminSignedCertSecret.secretArn;
const caEndpoint = scope.caEndpoint;
const client = scope.client;
const memberName = scope.memberName;
// Role for the custom resource lambda functions
const customResourceRole = new iam.Role(this, 'CustomResourceRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com') });
// Policies for the custom resource lambda to enroll and register users
customResourceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'));
customResourceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole'));
customResourceRole.addToPolicy(new iam.PolicyStatement({
actions: ['s3:GetObject', 'secretsmanager:CreateSecret', 'secretsmanager:GetSecretValue', 'secretsmanager:PutSecretValue'],
resources: [
`arn:${partition}:s3:::${tlsBucketData.bucketName}/*`,
adminPasswordArn,
adminPrivateKeyArn,
adminSignedCertArn,
],
}));
const lambdaDirectory = '../lambdas/fabric';
// Have to use docker local bundling as esbuild doesn't resolve the path on the fabric-proto package
const codeProp = {
bundling: {
image: lambda.Runtime.NODEJS_14_X.bundlingImage,
command: [
'bash', '-c', 'cp -a . /asset-output',
'npm install --prefix /asset-output',
],
local: {
tryBundle(outputDir) {
try {
(0, child_process_1.execSync)('npm --version');
(0, child_process_1.execSync)(`cp -a ${path.join(__dirname, lambdaDirectory)}/. ${outputDir}`);
(0, child_process_1.execSync)(`npm install --prefix ${outputDir}`);
}
catch {
return false;
}
return true;
},
},
},
};
// Lambda function to enroll the admin and import credentials to secrets manager.
const adminFunction = new lambda.Function(this, 'AdminFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'enroll-admin.handler',
code: lambda.Code.fromAsset(path.join(__dirname, lambdaDirectory), codeProp),
environment: {
ADMIN_PASSWORD_ARN: adminPasswordArn,
CA_ENDPOINT: caEndpoint,
PRIVATE_KEY_ARN: adminPrivateKeyArn,
SIGNED_CERT_ARN: adminSignedCertArn,
TLS_CERT_BUCKET: tlsBucketData.bucketName,
TLS_CERT_KEY: tlsBucketData.key,
},
role: customResourceRole,
vpc: client.vpc,
vpcSubnets: client.vpc.selectSubnets(),
timeout: cdk.Duration.minutes(1),
});
// Port range to access the Network
const ledgerPortRange = ec2.Port.tcpRange(utilities.STARTING_PORT, utilities.ENDING_PORT);
// Add access to the lambda for the Network ports
client.vpcEndpoint.connections.allowFrom(adminFunction, ledgerPortRange);
// Custom Resource provider
this.adminProvider = new customresources.Provider(this, 'AdminProvider', {
onEventHandler: adminFunction,
logRetention: logs.RetentionDays.ONE_DAY,
});
// Lambda function to register and enroll users and
// import credentials to secrets manager.
const userFunction = new lambda.Function(scope, 'UserFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'register-user.handler',
code: lambda.Code.fromAsset(path.join(__dirname, lambdaDirectory), codeProp),
environment: {
CA_ENDPOINT: caEndpoint,
MEMBER_NAME: memberName,
PRIVATE_KEY_ARN: adminPrivateKeyArn,
SIGNED_CERT_ARN: adminSignedCertArn,
TLS_CERT_BUCKET: tlsBucketData.bucketName,
TLS_CERT_KEY: tlsBucketData.key,
},
role: customResourceRole,
vpc: client.vpc,
vpcSubnets: client.vpc.selectSubnets(),
timeout: cdk.Duration.minutes(1),
});
// Add access to the lambda for the Network ports
scope.client.vpcEndpoint.connections.allowFrom(userFunction, ledgerPortRange);
// Custom Resource provider
HyperledgerFabricIdentity.userProvider = new customresources.Provider(scope, 'UserProvider', {
onEventHandler: userFunction,
logRetention: logs.RetentionDays.ONE_DAY,
});
// Populate the custom role static variable
HyperledgerFabricIdentity.customRole = customResourceRole;
}
}
exports.HyperledgerFabricIdentity = HyperledgerFabricIdentity;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRlbnRpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaWRlbnRpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHFFQUFxRTtBQUNyRSxpQ0FBaUM7OztBQUVqQyxpREFBeUM7QUFDekMsNkJBQTZCO0FBQzdCLG1DQUFtQztBQUNuQywyQ0FBMkM7QUFDM0MsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCw2Q0FBNkM7QUFDN0MsZ0VBQWdFO0FBQ2hFLHlDQUF5QztBQUd6Qyx5Q0FBeUM7QUFFekM7Ozs7O0dBS0c7QUFDSCxNQUFhLHlCQUEwQixTQUFRLFVBQVUsQ0FBQyxTQUFTO0lBa0JqRSxZQUFZLEtBQXVDLEVBQUUsRUFBVTtRQUM3RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLGdDQUFnQztRQUNoQyxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDL0MsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDO1FBRXpDLGlFQUFpRTtRQUNqRSxNQUFNLGFBQWEsR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXJELE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQztRQUM3RCxNQUFNLGtCQUFrQixHQUFHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUM7UUFDakUsTUFBTSxrQkFBa0IsR0FBRyxLQUFLLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDO1FBQ2pFLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUM7UUFDcEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUM1QixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsVUFB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QUNqRCxLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxlQUFlLENBQUMsQ0FBQztRQUU5RSwyQkFBMkI7UUFDM0IseUJBQXlCLENBQUMsWUFBWSxHQUFHLElBQUksZUFBZSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsY0FBYyxFQUFFO1lBQzNGLGNBQWMsRUFBRSxZQUFZO1lBQzVCLFlBQVksRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU87U0FDekMsQ0FBQyxDQUFDO1FBRUgsMkNBQTJDO1FBQzNDLHlCQUF5QixDQUFDLFVBQVUsR0FBRyxrQkFBa0IsQ0FBQztJQUU1RCxDQUFDO0NBRUY7QUE3SUQsOERBNklDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlULTBcblxuaW1wb3J0IHsgZXhlY1N5bmMgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0ICogYXMgbG9ncyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG5pbXBvcnQgKiBhcyBjdXN0b21yZXNvdXJjZXMgZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgKiBhcyBjb25zdHJ1Y3RzIGZyb20gJ2NvbnN0cnVjdHMnO1xuXG5pbXBvcnQgKiBhcyBuZXR3b3JrIGZyb20gJy4vbmV0d29yayc7XG5pbXBvcnQgKiBhcyB1dGlsaXRpZXMgZnJvbSAnLi91dGlsaXRpZXMnO1xuXG4vKipcbiAqIENyZWF0ZXMgY3VzdG9tIHJlc291cmNlcyB0byBlbnJvbGwgYWRtaW4gYW5kIHJlZ2lzdGVyIHVzZXJcbiAqIGlkZW50aXRpZXMgd2l0aCB0aGUgQ0EgdXNpbmcgdGhlIGZhYnJpYy1jYS1jbGllbnQgU0RLLlxuICogQWRtaW4gaWRlbnRpdHkgaXMgZW5yb2xsZWQgYnkgZGVmYXVsdC4gVXNlciBpZGVudGl0aWVzIGFyZVxuICogcmVnaXN0ZXJlZCBhbmQgZW5yb2xsZWQsIGlmIHByb3ZpZGVkLlxuICovXG5leHBvcnQgY2xhc3MgSHlwZXJsZWRnZXJGYWJyaWNJZGVudGl0eSBleHRlbmRzIGNvbnN0cnVjdHMuQ29uc3RydWN0IHtcblxuICAvKipcbiAgICogUm9sZSBmb3IgY3VzdG9tIHJlc291cmNlIGxhbWJkYSB0byBhc3N1bWVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY3VzdG9tUm9sZTogaWFtLlJvbGU7XG5cbiAgLyoqXG4gICAqIEN1c3RvbSBwcm92aWRlciB0byByZWdpc3RlciB1c2VyIGlkZW50aXR5XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHVzZXJQcm92aWRlcjogY3VzdG9tcmVzb3VyY2VzLlByb3ZpZGVyO1xuXG4gIC8qKlxuICAgKiBDdXN0b20gcHJvdmlkZXIgdG8gZW5yb2xsIGFkbWluIGlkZW50aXR5XG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYWRtaW5Qcm92aWRlcjogY3VzdG9tcmVzb3VyY2VzLlByb3ZpZGVyO1xuXG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IG5ldHdvcmsuSHlwZXJsZWRnZXJGYWJyaWNOZXR3b3JrLCBpZDogc3RyaW5nKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIENvbGxlY3QgbWV0YWRhdGEgb24gdGhlIHN0YWNrXG4gICAgY29uc3QgcGFydGl0aW9uID0gY2RrLlN0YWNrLm9mKHRoaXMpLnBhcnRpdGlvbjtcbiAgICBjb25zdCByZWdpb24gPSBjZGsuU3RhY2sub2YodGhpcykucmVnaW9uO1xuXG4gICAgLy8gUmV0cmlldmUgdGhlIFMzIEJ1Y2tldCBhbmQga2V5IHRoYXQgY29udGFpbnMgdGhlIFRMUyBjZXJ0IGZpbGVcbiAgICBjb25zdCB0bHNCdWNrZXREYXRhID0gdXRpbGl0aWVzLmdldFRsc0J1Y2tldChyZWdpb24pO1xuXG4gICAgY29uc3QgYWRtaW5QYXNzd29yZEFybiA9IHNjb3BlLmFkbWluUGFzc3dvcmRTZWNyZXQuc2VjcmV0QXJuO1xuICAgIGNvbnN0IGFkbWluUHJpdmF0ZUtleUFybiA9IHNjb3BlLmFkbWluUHJpdmF0ZUtleVNlY3JldC5zZWNyZXRBcm47XG4gICAgY29uc3QgYWRtaW5TaWduZWRDZXJ0QXJuID0gc2NvcGUuYWRtaW5TaWduZWRDZXJ0U2VjcmV0LnNlY3JldEFybjtcbiAgICBjb25zdCBjYUVuZHBvaW50ID0gc2NvcGUuY2FFbmRwb2ludDtcbiAgICBjb25zdCBjbGllbnQgPSBzY29wZS5jbGllbnQ7XG4gICAgY29uc3QgbWVtYmVyTmFtZSA9IHNjb3BlLm1lbWJlck5hbWU7XG5cbiAgICAvLyBSb2xlIGZvciB0aGUgY3VzdG9tIHJlc291cmNlIGxhbWJkYSBmdW5jdGlvbnNcbiAgICBjb25zdCBjdXN0b21SZXNvdXJjZVJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ0N1c3RvbVJlc291cmNlUm9sZScsIHsgYXNzdW1lZEJ5OiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2xhbWJkYS5hbWF6b25hd3MuY29tJykgfSk7XG5cbiAgICAvLyBQb2xpY2llcyBmb3IgdGhlIGN1c3RvbSByZXNvdXJjZSBsYW1iZGEgdG8gZW5yb2xsIGFuZCByZWdpc3RlciB1c2Vyc1xuICAgIGN1c3RvbVJlc291cmNlUm9sZS5hZGRNYW5hZ2VkUG9saWN5KGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpKTtcbiAgICBjdXN0b21SZXNvdXJjZVJvbGUuYWRkTWFuYWdlZFBvbGljeShpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFWUENBY2Nlc3NFeGVjdXRpb25Sb2xlJykpO1xuICAgIGN1c3RvbVJlc291cmNlUm9sZS5hZGRUb1BvbGljeSggbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgYWN0aW9uczogWydzMzpHZXRPYmplY3QnLCAnc2VjcmV0c21hbmFnZXI6Q3JlYXRlU2VjcmV0JywgJ3NlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlJywgJ3NlY3JldHNtYW5hZ2VyOlB1dFNlY3JldFZhbHVlJ10sXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgYGFybjoke3BhcnRpdGlvbn06czM6Ojoke3Rsc0J1Y2tldERhdGEuYnVja2V0TmFtZX0vKmAsXG4gICAgICAgIGFkbWluUGFzc3dvcmRBcm4sXG4gICAgICAgIGFkbWluUHJpdmF0ZUtleUFybixcbiAgICAgICAgYWRtaW5TaWduZWRDZXJ0QXJuLFxuICAgICAgXSxcbiAgICB9KSk7XG5cbiAgICBjb25zdCBsYW1iZGFEaXJlY3RvcnkgPSAnLi4vbGFtYmRhcy9mYWJyaWMnO1xuXG4gICAgLy8gSGF2ZSB0byB1c2UgZG9ja2VyIGxvY2FsIGJ1bmRsaW5nIGFzIGVzYnVpbGQgZG9lc24ndCByZXNvbHZlIHRoZSBwYXRoIG9uIHRoZSBmYWJyaWMtcHJvdG8gcGFja2FnZVxuICAgIGNvbnN0IGNvZGVQcm9wID0ge1xuICAgICAgYnVuZGxpbmc6IHtcbiAgICAgICAgaW1hZ2U6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xNF9YLmJ1bmRsaW5nSW1hZ2UsXG4gICAgICAgIGNvbW1hbmQ6IFtcbiAgICAgICAgICAnYmFzaCcsICctYycsICdjcCAtYSAuIC9hc3NldC1vdXRwdXQnLFxuICAgICAgICAgICducG0gaW5zdGFsbCAtLXByZWZpeCAvYXNzZXQtb3V0cHV0JyxcbiAgICAgICAgXSxcbiAgICAgICAgbG9jYWw6IHtcbiAgICAgICAgICB0cnlCdW5kbGUob3V0cHV0RGlyOiBzdHJpbmcpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGV4ZWNTeW5jKCducG0gLS12ZXJzaW9uJyk7XG4gICAgICAgICAgICAgIGV4ZWNTeW5jKGBjcCAtYSAke3BhdGguam9pbihfX2Rpcm5hbWUsIGxhbWJkYURpcmVjdG9yeSl9Ly4gJHtvdXRwdXREaXJ9YCk7XG4gICAgICAgICAgICAgIGV4ZWNTeW5jKGBucG0gaW5zdGFsbCAtLXByZWZpeCAke291dHB1dERpcn1gKTtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgLy8gTGFtYmRhIGZ1bmN0aW9uIHRvIGVucm9sbCB0aGUgYWRtaW4gYW5kIGltcG9ydCBjcmVkZW50aWFscyB0byBzZWNyZXRzIG1hbmFnZXIuXG4gICAgY29uc3QgYWRtaW5GdW5jdGlvbiA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ0FkbWluRnVuY3Rpb24nLCB7XG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMTRfWCxcbiAgICAgIGhhbmRsZXI6ICdlbnJvbGwtYWRtaW4uaGFuZGxlcicsXG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgbGFtYmRhRGlyZWN0b3J5KSwgY29kZVByb3ApLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgQURNSU5fUEFTU1dPUkRfQVJOOiBhZG1pblBhc3N3b3JkQXJuLFxuICAgICAgICBDQV9FTkRQT0lOVDogY2FFbmRwb2ludCxcbiAgICAgICAgUFJJVkFURV9LRVlfQVJOOiBhZG1pblByaXZhdGVLZXlBcm4sXG4gICAgICAgIFNJR05FRF9DRVJUX0FSTjogYWRtaW5TaWduZWRDZXJ0QXJuLFxuICAgICAgICBUTFNfQ0VSVF9CVUNLRVQ6IHRsc0J1Y2tldERhdGEuYnVja2V0TmFtZSxcbiAgICAgICAgVExTX0NFUlRfS0VZOiB0bHNCdWNrZXREYXRhLmtleSxcbiAgICAgIH0sXG4gICAgICByb2xlOiBjdXN0b21SZXNvdXJjZVJvbGUsXG4gICAgICB2cGM6IGNsaWVudC52cGMsXG4gICAgICB2cGNTdWJuZXRzOiBjbGllbnQudnBjLnNlbGVjdFN1Ym5ldHMoKSxcbiAgICAgIHRpbWVvdXQ6IGNkay5EdXJhdGlvbi5taW51dGVzKDEpLFxuICAgIH0pO1xuXG4gICAgLy8gUG9ydCByYW5nZSB0byBhY2Nlc3MgdGhlIE5ldHdvcmtcbiAgICBjb25zdCBsZWRnZXJQb3J0UmFuZ2UgPSBlYzIuUG9ydC50Y3BSYW5nZSh1dGlsaXRpZXMuU1RBUlRJTkdfUE9SVCwgdXRpbGl0aWVzLkVORElOR19QT1JUKTtcblxuICAgIC8vIEFkZCBhY2Nlc3MgdG8gdGhlIGxhbWJkYSBmb3IgdGhlIE5ldHdvcmsgcG9ydHNcbiAgICBjbGllbnQudnBjRW5kcG9pbnQuY29ubmVjdGlvbnMuYWxsb3dGcm9tKGFkbWluRnVuY3Rpb24sIGxlZGdlclBvcnRSYW5nZSk7XG5cbiAgICAvLyBDdXN0b20gUmVzb3VyY2UgcHJvdmlkZXJcbiAgICB0aGlzLmFkbWluUHJvdmlkZXIgPSBuZXcgY3VzdG9tcmVzb3VyY2VzLlByb3ZpZGVyKHRoaXMsICdBZG1pblByb3ZpZGVyJywge1xuICAgICAgb25FdmVudEhhbmRsZXI6IGFkbWluRnVuY3Rpb24sXG4gICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfREFZLFxuICAgIH0pO1xuXG4gICAgLy8gTGFtYmRhIGZ1bmN0aW9uIHRvIHJlZ2lzdGVyIGFuZCBlbnJvbGwgdXNlcnMgYW5kXG4gICAgLy8gaW1wb3J0IGNyZWRlbnRpYWxzIHRvIHNlY3JldHMgbWFuYWdlci5cbiAgICBjb25zdCB1c2VyRnVuY3Rpb24gPSBuZXcgbGFtYmRhLkZ1bmN0aW9uKHNjb3BlLCAnVXNlckZ1bmN0aW9uJywge1xuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE0X1gsXG4gICAgICBoYW5kbGVyOiAncmVnaXN0ZXItdXNlci5oYW5kbGVyJyxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCBsYW1iZGFEaXJlY3RvcnkpLCBjb2RlUHJvcCksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBDQV9FTkRQT0lOVDogY2FFbmRwb2ludCxcbiAgICAgICAgTUVNQkVSX05BTUU6IG1lbWJlck5hbWUsXG4gICAgICAgIFBSSVZBVEVfS0VZX0FSTjogYWRtaW5Qcml2YXRlS2V5QXJuLFxuICAgICAgICBTSUdORURfQ0VSVF9BUk46IGFkbWluU2lnbmVkQ2VydEFybixcbiAgICAgICAgVExTX0NFUlRfQlVDS0VUOiB0bHNCdWNrZXREYXRhLmJ1Y2tldE5hbWUsXG4gICAgICAgIFRMU19DRVJUX0tFWTogdGxzQnVja2V0RGF0YS5rZXksXG4gICAgICB9LFxuICAgICAgcm9sZTogY3VzdG9tUmVzb3VyY2VSb2xlLFxuICAgICAgdnBjOiBjbGllbnQudnBjLFxuICAgICAgdnBjU3VibmV0czogY2xpZW50LnZwYy5zZWxlY3RTdWJuZXRzKCksXG4gICAgICB0aW1lb3V0OiBjZGsuRHVyYXRpb24ubWludXRlcygxKSxcbiAgICB9KTtcblxuICAgIC8vIEFkZCBhY2Nlc3MgdG8gdGhlIGxhbWJkYSBmb3IgdGhlIE5ldHdvcmsgcG9ydHNcbiAgICBzY29wZS5jbGllbnQudnBjRW5kcG9pbnQuY29ubmVjdGlvbnMuYWxsb3dGcm9tKHVzZXJGdW5jdGlvbiwgbGVkZ2VyUG9ydFJhbmdlKTtcblxuICAgIC8vIEN1c3RvbSBSZXNvdXJjZSBwcm92aWRlclxuICAgIEh5cGVybGVkZ2VyRmFicmljSWRlbnRpdHkudXNlclByb3ZpZGVyID0gbmV3IGN1c3RvbXJlc291cmNlcy5Qcm92aWRlcihzY29wZSwgJ1VzZXJQcm92aWRlcicsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyOiB1c2VyRnVuY3Rpb24sXG4gICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfREFZLFxuICAgIH0pO1xuXG4gICAgLy8gUG9wdWxhdGUgdGhlIGN1c3RvbSByb2xlIHN0YXRpYyB2YXJpYWJsZVxuICAgIEh5cGVybGVkZ2VyRmFicmljSWRlbnRpdHkuY3VzdG9tUm9sZSA9IGN1c3RvbVJlc291cmNlUm9sZTtcblxuICB9XG5cbn0iXX0=