@cdklabs/cdk-hyperledger-fabric-network 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ // SPDX-License-Identifier: MIT-0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.HyperledgerFabricIdentity = void 0;
6
+ const path = require("path");
7
+ const cdk = require("aws-cdk-lib");
8
+ const ec2 = require("aws-cdk-lib/aws-ec2");
9
+ const iam = require("aws-cdk-lib/aws-iam");
10
+ const lambda = require("aws-cdk-lib/aws-lambda");
11
+ const logs = require("aws-cdk-lib/aws-logs");
12
+ const customresources = require("aws-cdk-lib/custom-resources");
13
+ const constructs = require("constructs");
14
+ const utilities = require("./utilities");
15
+ /**
16
+ * Creates custom resources to enroll admin and register user
17
+ * identities with the CA using the fabric-ca-client SDK.
18
+ * Admin identity is enrolled by default. User identities are
19
+ * registered and enrolled, if provided.
20
+ */
21
+ class HyperledgerFabricIdentity extends constructs.Construct {
22
+ constructor(scope, id) {
23
+ super(scope, id);
24
+ // Collect metadata on the stack
25
+ const partition = cdk.Stack.of(this).partition;
26
+ const region = cdk.Stack.of(this).region;
27
+ // Retrieve the S3 Bucket and key that contains the TLS cert file
28
+ const tlsBucketData = utilities.getTlsBucket(region);
29
+ const adminPasswordArn = scope.adminPasswordSecret.secretArn;
30
+ const adminPrivateKeyArn = scope.adminPrivateKeySecret.secretArn;
31
+ const adminSignedCertArn = scope.adminSignedCertSecret.secretArn;
32
+ const caEndpoint = scope.caEndpoint;
33
+ const client = scope.client;
34
+ const memberName = scope.memberName;
35
+ // Role for the custom resource lambda functions
36
+ const customResourceRole = new iam.Role(this, 'CustomResourceRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com') });
37
+ // Policies for the custom resource lambda to enroll and register users
38
+ customResourceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'));
39
+ customResourceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole'));
40
+ customResourceRole.addToPolicy(new iam.PolicyStatement({
41
+ actions: ['s3:GetObject', 'secretsmanager:CreateSecret', 'secretsmanager:GetSecretValue', 'secretsmanager:PutSecretValue'],
42
+ resources: [
43
+ `arn:${partition}:s3:::${tlsBucketData.bucketName}/*`,
44
+ adminPasswordArn,
45
+ adminPrivateKeyArn,
46
+ adminSignedCertArn,
47
+ ],
48
+ }));
49
+ // Lambda function to enroll the admin and import credentials to secrets manager
50
+ const adminFunction = new lambda.Function(this, 'AdminFunction', {
51
+ runtime: lambda.Runtime.NODEJS_14_X,
52
+ handler: 'enroll-admin.handler',
53
+ code: lambda.Code.fromAsset(path.join(__dirname, '../lambdas/fabric')),
54
+ environment: {
55
+ ADMIN_PASSWORD_ARN: adminPasswordArn,
56
+ CA_ENDPOINT: caEndpoint,
57
+ PRIVATE_KEY_ARN: adminPrivateKeyArn,
58
+ SIGNED_CERT_ARN: adminSignedCertArn,
59
+ TLS_CERT_BUCKET: tlsBucketData.bucketName,
60
+ TLS_CERT_KEY: tlsBucketData.key,
61
+ },
62
+ role: customResourceRole,
63
+ vpc: client.vpc,
64
+ vpcSubnets: client.vpc.selectSubnets(),
65
+ timeout: cdk.Duration.minutes(1),
66
+ });
67
+ // Port range to access the Network
68
+ const ledgerPortRange = ec2.Port.tcpRange(utilities.STARTING_PORT, utilities.ENDING_PORT);
69
+ // Add access to the lambda for the Network ports
70
+ client.vpcEndpoint.connections.allowFrom(adminFunction, ledgerPortRange);
71
+ // Custom Resource provider
72
+ this.adminProvider = new customresources.Provider(this, 'AdminProvider', {
73
+ onEventHandler: adminFunction,
74
+ logRetention: logs.RetentionDays.ONE_DAY,
75
+ });
76
+ // Lambda function to register and enroll users and
77
+ // import credentials to secrets manager
78
+ const userFunction = new lambda.Function(scope, 'UserFunction', {
79
+ runtime: lambda.Runtime.NODEJS_14_X,
80
+ handler: 'register-user.handler',
81
+ code: lambda.Code.fromAsset(path.join(__dirname, '../lambdas/fabric')),
82
+ environment: {
83
+ CA_ENDPOINT: caEndpoint,
84
+ MEMBER_NAME: memberName,
85
+ PRIVATE_KEY_ARN: adminPrivateKeyArn,
86
+ SIGNED_CERT_ARN: adminSignedCertArn,
87
+ TLS_CERT_BUCKET: tlsBucketData.bucketName,
88
+ TLS_CERT_KEY: tlsBucketData.key,
89
+ },
90
+ role: customResourceRole,
91
+ vpc: client.vpc,
92
+ vpcSubnets: client.vpc.selectSubnets(),
93
+ timeout: cdk.Duration.minutes(1),
94
+ });
95
+ // Add access to the lambda for the Network ports
96
+ scope.client.vpcEndpoint.connections.allowFrom(userFunction, ledgerPortRange);
97
+ // Custom Resource provider
98
+ HyperledgerFabricIdentity.userProvider = new customresources.Provider(scope, 'UserProvider', {
99
+ onEventHandler: userFunction,
100
+ logRetention: logs.RetentionDays.ONE_DAY,
101
+ });
102
+ // Populate the custom role static variable
103
+ HyperledgerFabricIdentity.customRole = customResourceRole;
104
+ }
105
+ }
106
+ exports.HyperledgerFabricIdentity = HyperledgerFabricIdentity;
107
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRlbnRpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaWRlbnRpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHFFQUFxRTtBQUNyRSxpQ0FBaUM7OztBQUVqQyw2QkFBNkI7QUFDN0IsbUNBQW1DO0FBQ25DLDJDQUEyQztBQUMzQywyQ0FBMkM7QUFDM0MsaURBQWlEO0FBQ2pELDZDQUE2QztBQUM3QyxnRUFBZ0U7QUFDaEUseUNBQXlDO0FBR3pDLHlDQUF5QztBQUV6Qzs7Ozs7R0FLRztBQUNILE1BQWEseUJBQTBCLFNBQVEsVUFBVSxDQUFDLFNBQVM7SUFrQmpFLFlBQVksS0FBdUMsRUFBRSxFQUFVO1FBQzdELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsZ0NBQWdDO1FBQ2hDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUMvQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUM7UUFFekMsaUVBQWlFO1FBQ2pFLE1BQU0sYUFBYSxHQUFHLFNBQVMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFckQsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDO1FBQzdELE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQztRQUNqRSxNQUFNLGtCQUFrQixHQUFHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUM7UUFDakUsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQztRQUNwQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQzVCLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUM7UUFFcEMs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Q3ZCLFdBQVcsRUFBRSxVQUFVO2dCQUN2QixlQUFlLEVBQUUsa0JBQWtCO2dCQUNuQyxlQUFlLEVBQUUsa0JBQWtCO2dCQUNuQyxlQUFlLEVBQUUsYUFBYSxDQUFDLFVBQVU7Z0JBQ3pDLFlBQVksRUFBRSxhQUFhLENBQUMsR0FBRzthQUNoQztZQUNELElBQUksRUFBRSxrQkFBa0I7WUFDeEIsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHO1lBQ2YsVUFBVSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFO1lBQ3RDLE9BQU8sRUFBRSxHQUFHLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7U0FDakMsQ0FBQyxDQUFDO1FBRUgsaURBQWlEO1FBQ2pELEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsWUFBWSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBRTlFLDJCQUEyQjtRQUMzQix5QkFBeUIsQ0FBQyxZQUFZLEdBQUcsSUFBSSxlQUFlLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxjQUFjLEVBQUU7WUFDM0YsY0FBYyxFQUFFLFlBQVk7WUFDNUIsWUFBWSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTztTQUN6QyxDQUFDLENBQUM7UUFFSCwyQ0FBMkM7UUFDM0MseUJBQXlCLENBQUMsVUFBVSxHQUFHLGtCQUFrQixDQUFDO0lBRTVELENBQUM7Q0FFRjtBQXBIRCw4REFvSEMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVQtMFxuXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgY2RrIGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIGVjMiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGxvZ3MgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0ICogYXMgY3VzdG9tcmVzb3VyY2VzIGZyb20gJ2F3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXMnO1xuaW1wb3J0ICogYXMgY29uc3RydWN0cyBmcm9tICdjb25zdHJ1Y3RzJztcblxuaW1wb3J0ICogYXMgbmV0d29yayBmcm9tICcuL25ldHdvcmsnO1xuaW1wb3J0ICogYXMgdXRpbGl0aWVzIGZyb20gJy4vdXRpbGl0aWVzJztcblxuLyoqXG4gKiBDcmVhdGVzIGN1c3RvbSByZXNvdXJjZXMgdG8gZW5yb2xsIGFkbWluIGFuZCByZWdpc3RlciB1c2VyXG4gKiBpZGVudGl0aWVzIHdpdGggdGhlIENBIHVzaW5nIHRoZSBmYWJyaWMtY2EtY2xpZW50IFNESy5cbiAqIEFkbWluIGlkZW50aXR5IGlzIGVucm9sbGVkIGJ5IGRlZmF1bHQuIFVzZXIgaWRlbnRpdGllcyBhcmVcbiAqIHJlZ2lzdGVyZWQgYW5kIGVucm9sbGVkLCBpZiBwcm92aWRlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIEh5cGVybGVkZ2VyRmFicmljSWRlbnRpdHkgZXh0ZW5kcyBjb25zdHJ1Y3RzLkNvbnN0cnVjdCB7XG5cbiAgLyoqXG4gICAqIFJvbGUgZm9yIGN1c3RvbSByZXNvdXJjZSBsYW1iZGEgdG8gYXNzdW1lXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGN1c3RvbVJvbGU6IGlhbS5Sb2xlO1xuXG4gIC8qKlxuICAgKiBDdXN0b20gcHJvdmlkZXIgdG8gcmVnaXN0ZXIgdXNlciBpZGVudGl0eVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyB1c2VyUHJvdmlkZXI6IGN1c3RvbXJlc291cmNlcy5Qcm92aWRlcjtcblxuICAvKipcbiAgICogQ3VzdG9tIHByb3ZpZGVyIHRvIGVucm9sbCBhZG1pbiBpZGVudGl0eVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFkbWluUHJvdmlkZXI6IGN1c3RvbXJlc291cmNlcy5Qcm92aWRlcjtcblxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBuZXR3b3JrLkh5cGVybGVkZ2VyRmFicmljTmV0d29yaywgaWQ6IHN0cmluZykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICAvLyBDb2xsZWN0IG1ldGFkYXRhIG9uIHRoZSBzdGFja1xuICAgIGNvbnN0IHBhcnRpdGlvbiA9IGNkay5TdGFjay5vZih0aGlzKS5wYXJ0aXRpb247XG4gICAgY29uc3QgcmVnaW9uID0gY2RrLlN0YWNrLm9mKHRoaXMpLnJlZ2lvbjtcblxuICAgIC8vIFJldHJpZXZlIHRoZSBTMyBCdWNrZXQgYW5kIGtleSB0aGF0IGNvbnRhaW5zIHRoZSBUTFMgY2VydCBmaWxlXG4gICAgY29uc3QgdGxzQnVja2V0RGF0YSA9IHV0aWxpdGllcy5nZXRUbHNCdWNrZXQocmVnaW9uKTtcblxuICAgIGNvbnN0IGFkbWluUGFzc3dvcmRBcm4gPSBzY29wZS5hZG1pblBhc3N3b3JkU2VjcmV0LnNlY3JldEFybjtcbiAgICBjb25zdCBhZG1pblByaXZhdGVLZXlBcm4gPSBzY29wZS5hZG1pblByaXZhdGVLZXlTZWNyZXQuc2VjcmV0QXJuO1xuICAgIGNvbnN0IGFkbWluU2lnbmVkQ2VydEFybiA9IHNjb3BlLmFkbWluU2lnbmVkQ2VydFNlY3JldC5zZWNyZXRBcm47XG4gICAgY29uc3QgY2FFbmRwb2ludCA9IHNjb3BlLmNhRW5kcG9pbnQ7XG4gICAgY29uc3QgY2xpZW50ID0gc2NvcGUuY2xpZW50O1xuICAgIGNvbnN0IG1lbWJlck5hbWUgPSBzY29wZS5tZW1iZXJOYW1lO1xuXG4gICAgLy8gUm9sZSBmb3IgdGhlIGN1c3RvbSByZXNvdXJjZSBsYW1iZGEgZnVuY3Rpb25zXG4gICAgY29uc3QgY3VzdG9tUmVzb3VyY2VSb2xlID0gbmV3IGlhbS5Sb2xlKHRoaXMsICdDdXN0b21SZXNvdXJjZVJvbGUnLCB7IGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpIH0pO1xuXG4gICAgLy8gUG9saWNpZXMgZm9yIHRoZSBjdXN0b20gcmVzb3VyY2UgbGFtYmRhIHRvIGVucm9sbCBhbmQgcmVnaXN0ZXIgdXNlcnNcbiAgICBjdXN0b21SZXNvdXJjZVJvbGUuYWRkTWFuYWdlZFBvbGljeShpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUnKSk7XG4gICAgY3VzdG9tUmVzb3VyY2VSb2xlLmFkZE1hbmFnZWRQb2xpY3koaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdzZXJ2aWNlLXJvbGUvQVdTTGFtYmRhVlBDQWNjZXNzRXhlY3V0aW9uUm9sZScpKTtcbiAgICBjdXN0b21SZXNvdXJjZVJvbGUuYWRkVG9Qb2xpY3koIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0JywgJ3NlY3JldHNtYW5hZ2VyOkNyZWF0ZVNlY3JldCcsICdzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZScsICdzZWNyZXRzbWFuYWdlcjpQdXRTZWNyZXRWYWx1ZSddLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIGBhcm46JHtwYXJ0aXRpb259OnMzOjo6JHt0bHNCdWNrZXREYXRhLmJ1Y2tldE5hbWV9LypgLFxuICAgICAgICBhZG1pblBhc3N3b3JkQXJuLFxuICAgICAgICBhZG1pblByaXZhdGVLZXlBcm4sXG4gICAgICAgIGFkbWluU2lnbmVkQ2VydEFybixcbiAgICAgIF0sXG4gICAgfSkpO1xuXG4gICAgLy8gTGFtYmRhIGZ1bmN0aW9uIHRvIGVucm9sbCB0aGUgYWRtaW4gYW5kIGltcG9ydCBjcmVkZW50aWFscyB0byBzZWNyZXRzIG1hbmFnZXJcbiAgICBjb25zdCBhZG1pbkZ1bmN0aW9uID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCAnQWRtaW5GdW5jdGlvbicsIHtcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xNF9YLFxuICAgICAgaGFuZGxlcjogJ2Vucm9sbC1hZG1pbi5oYW5kbGVyJyxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vbGFtYmRhcy9mYWJyaWMnKSksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBBRE1JTl9QQVNTV09SRF9BUk46IGFkbWluUGFzc3dvcmRBcm4sXG4gICAgICAgIENBX0VORFBPSU5UOiBjYUVuZHBvaW50LFxuICAgICAgICBQUklWQVRFX0tFWV9BUk46IGFkbWluUHJpdmF0ZUtleUFybixcbiAgICAgICAgU0lHTkVEX0NFUlRfQVJOOiBhZG1pblNpZ25lZENlcnRBcm4sXG4gICAgICAgIFRMU19DRVJUX0JVQ0tFVDogdGxzQnVja2V0RGF0YS5idWNrZXROYW1lLFxuICAgICAgICBUTFNfQ0VSVF9LRVk6IHRsc0J1Y2tldERhdGEua2V5LFxuICAgICAgfSxcbiAgICAgIHJvbGU6IGN1c3RvbVJlc291cmNlUm9sZSxcbiAgICAgIHZwYzogY2xpZW50LnZwYyxcbiAgICAgIHZwY1N1Ym5ldHM6IGNsaWVudC52cGMuc2VsZWN0U3VibmV0cygpLFxuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLm1pbnV0ZXMoMSksXG4gICAgfSk7XG5cbiAgICAvLyBQb3J0IHJhbmdlIHRvIGFjY2VzcyB0aGUgTmV0d29ya1xuICAgIGNvbnN0IGxlZGdlclBvcnRSYW5nZSA9IGVjMi5Qb3J0LnRjcFJhbmdlKHV0aWxpdGllcy5TVEFSVElOR19QT1JULCB1dGlsaXRpZXMuRU5ESU5HX1BPUlQpO1xuXG4gICAgLy8gQWRkIGFjY2VzcyB0byB0aGUgbGFtYmRhIGZvciB0aGUgTmV0d29yayBwb3J0c1xuICAgIGNsaWVudC52cGNFbmRwb2ludC5jb25uZWN0aW9ucy5hbGxvd0Zyb20oYWRtaW5GdW5jdGlvbiwgbGVkZ2VyUG9ydFJhbmdlKTtcblxuICAgIC8vIEN1c3RvbSBSZXNvdXJjZSBwcm92aWRlclxuICAgIHRoaXMuYWRtaW5Qcm92aWRlciA9IG5ldyBjdXN0b21yZXNvdXJjZXMuUHJvdmlkZXIodGhpcywgJ0FkbWluUHJvdmlkZXInLCB7XG4gICAgICBvbkV2ZW50SGFuZGxlcjogYWRtaW5GdW5jdGlvbixcbiAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9EQVksXG4gICAgfSk7XG5cbiAgICAvLyBMYW1iZGEgZnVuY3Rpb24gdG8gcmVnaXN0ZXIgYW5kIGVucm9sbCB1c2VycyBhbmRcbiAgICAvLyBpbXBvcnQgY3JlZGVudGlhbHMgdG8gc2VjcmV0cyBtYW5hZ2VyXG4gICAgY29uc3QgdXNlckZ1bmN0aW9uID0gbmV3IGxhbWJkYS5GdW5jdGlvbihzY29wZSwgJ1VzZXJGdW5jdGlvbicsIHtcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xNF9YLFxuICAgICAgaGFuZGxlcjogJ3JlZ2lzdGVyLXVzZXIuaGFuZGxlcicsXG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgJy4uL2xhbWJkYXMvZmFicmljJykpLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgQ0FfRU5EUE9JTlQ6IGNhRW5kcG9pbnQsXG4gICAgICAgIE1FTUJFUl9OQU1FOiBtZW1iZXJOYW1lLFxuICAgICAgICBQUklWQVRFX0tFWV9BUk46IGFkbWluUHJpdmF0ZUtleUFybixcbiAgICAgICAgU0lHTkVEX0NFUlRfQVJOOiBhZG1pblNpZ25lZENlcnRBcm4sXG4gICAgICAgIFRMU19DRVJUX0JVQ0tFVDogdGxzQnVja2V0RGF0YS5idWNrZXROYW1lLFxuICAgICAgICBUTFNfQ0VSVF9LRVk6IHRsc0J1Y2tldERhdGEua2V5LFxuICAgICAgfSxcbiAgICAgIHJvbGU6IGN1c3RvbVJlc291cmNlUm9sZSxcbiAgICAgIHZwYzogY2xpZW50LnZwYyxcbiAgICAgIHZwY1N1Ym5ldHM6IGNsaWVudC52cGMuc2VsZWN0U3VibmV0cygpLFxuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLm1pbnV0ZXMoMSksXG4gICAgfSk7XG5cbiAgICAvLyBBZGQgYWNjZXNzIHRvIHRoZSBsYW1iZGEgZm9yIHRoZSBOZXR3b3JrIHBvcnRzXG4gICAgc2NvcGUuY2xpZW50LnZwY0VuZHBvaW50LmNvbm5lY3Rpb25zLmFsbG93RnJvbSh1c2VyRnVuY3Rpb24sIGxlZGdlclBvcnRSYW5nZSk7XG5cbiAgICAvLyBDdXN0b20gUmVzb3VyY2UgcHJvdmlkZXJcbiAgICBIeXBlcmxlZGdlckZhYnJpY0lkZW50aXR5LnVzZXJQcm92aWRlciA9IG5ldyBjdXN0b21yZXNvdXJjZXMuUHJvdmlkZXIoc2NvcGUsICdVc2VyUHJvdmlkZXInLCB7XG4gICAgICBvbkV2ZW50SGFuZGxlcjogdXNlckZ1bmN0aW9uLFxuICAgICAgbG9nUmV0ZW50aW9uOiBsb2dzLlJldGVudGlvbkRheXMuT05FX0RBWSxcbiAgICB9KTtcblxuICAgIC8vIFBvcHVsYXRlIHRoZSBjdXN0b20gcm9sZSBzdGF0aWMgdmFyaWFibGVcbiAgICBIeXBlcmxlZGdlckZhYnJpY0lkZW50aXR5LmN1c3RvbVJvbGUgPSBjdXN0b21SZXNvdXJjZVJvbGU7XG5cbiAgfVxuXG59Il19
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './network';
2
+ export * from './node';
3
+ export * from './client';
4
+ export * from './user';
5
+ export { SUPPORTED_REGIONS, SUPPORTED_AVAILABILITY_ZONES } from './utilities';
package/lib/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ // SPDX-License-Identifier: MIT-0
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
7
+ }) : (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ o[k2] = m[k];
10
+ }));
11
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
12
+ for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ __exportStar(require("./network"), exports);
16
+ __exportStar(require("./node"), exports);
17
+ __exportStar(require("./client"), exports);
18
+ __exportStar(require("./user"), exports);
19
+ var utilities_1 = require("./utilities");
20
+ Object.defineProperty(exports, "SUPPORTED_REGIONS", { enumerable: true, get: function () { return utilities_1.SUPPORTED_REGIONS; } });
21
+ Object.defineProperty(exports, "SUPPORTED_AVAILABILITY_ZONES", { enumerable: true, get: function () { return utilities_1.SUPPORTED_AVAILABILITY_ZONES; } });
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHFFQUFxRTtBQUNyRSxpQ0FBaUM7Ozs7Ozs7Ozs7OztBQUdqQyw0Q0FBMEI7QUFDMUIseUNBQXVCO0FBQ3ZCLDJDQUF5QjtBQUN6Qix5Q0FBdUI7QUFFdkIseUNBQThFO0FBQXJFLDhHQUFBLGlCQUFpQixPQUFBO0FBQUUseUhBQUEsNEJBQTRCLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVQtMFxuXG5cbmV4cG9ydCAqIGZyb20gJy4vbmV0d29yayc7XG5leHBvcnQgKiBmcm9tICcuL25vZGUnO1xuZXhwb3J0ICogZnJvbSAnLi9jbGllbnQnO1xuZXhwb3J0ICogZnJvbSAnLi91c2VyJztcblxuZXhwb3J0IHsgU1VQUE9SVEVEX1JFR0lPTlMsIFNVUFBPUlRFRF9BVkFJTEFCSUxJVFlfWk9ORVMgfSBmcm9tICcuL3V0aWxpdGllcyc7XG4iXX0=
@@ -0,0 +1,183 @@
1
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
2
+ import * as constructs from 'constructs';
3
+ import * as client from './client';
4
+ import * as node from './node';
5
+ import * as user from './user';
6
+ export declare enum FrameworkVersion {
7
+ VERSION_1_2 = "1.2",
8
+ VERSION_1_4 = "1.4",
9
+ VERSION_2_2 = "2.2"
10
+ }
11
+ export declare enum NetworkEdition {
12
+ STARTER = "STARTER",
13
+ STANDARD = "STANDARD"
14
+ }
15
+ export declare enum ThresholdComparator {
16
+ GREATER_THAN = "GREATER_THAN",
17
+ GREATER_THAN_OR_EQUAL_TO = "GREATER_THAN_OR_EQUAL_TO"
18
+ }
19
+ /**
20
+ * Construct properties for `HyperledgerFabricNetwork`
21
+ */
22
+ export interface HyperledgerFabricNetworkProps {
23
+ /**
24
+ * Managed Blockchain network name
25
+ */
26
+ readonly networkName: string;
27
+ /**
28
+ * Managed Blockchain network description
29
+ *
30
+ * @default - Set to match network name
31
+ */
32
+ readonly networkDescription?: string;
33
+ /**
34
+ * Managed Blockchain member name
35
+ */
36
+ readonly memberName: string;
37
+ /**
38
+ * Managed Blockchain member description
39
+ *
40
+ * @default - Set to match member name
41
+ */
42
+ readonly memberDescription?: string;
43
+ /**
44
+ * Hyperledger Fabric framework version
45
+ *
46
+ * @default - FrameworkVersion.VERSION_1_4
47
+ */
48
+ readonly frameworkVersion?: FrameworkVersion;
49
+ /**
50
+ * Managed Blockchain network edition
51
+ *
52
+ * @default - NetworkEdition.STANDARD
53
+ */
54
+ readonly networkEdition?: NetworkEdition;
55
+ /**
56
+ * The duration from the time that a proposal is created until it expires
57
+ * @default - 24 hours
58
+ */
59
+ readonly proposalDurationInHours?: number;
60
+ /**
61
+ * The percentage of votes among all members that must be yes for a proposal to be approved
62
+ * @default - 50 percent
63
+ */
64
+ readonly thresholdPercentage?: number;
65
+ /**
66
+ * Determines whether the yes votes must be greater than the threshold percentage
67
+ * or must be greater than or equal to the threhold percentage to be approved
68
+ * @default - GREATER_THAN
69
+ */
70
+ readonly thresholdComparator?: ThresholdComparator;
71
+ /**
72
+ * The configuration to enable or disable certificate authority logging
73
+ * @default - true
74
+ */
75
+ readonly enableCaLogging?: boolean;
76
+ /**
77
+ * List of nodes to create on the network
78
+ *
79
+ * @default - One node with default configuration
80
+ */
81
+ readonly nodes?: Array<node.HyperledgerFabricNodeProps>;
82
+ /**
83
+ * The Client network to interact with the Hyperledger Fabric network
84
+ * @default - Client network with Default properties
85
+ * (CIDR-`10.0.0.0/16` and subnets of type `PRIVATE_ISOLATED`)
86
+ */
87
+ readonly client?: client.HyperledgerFabricClientProps;
88
+ /**
89
+ * List of users to register with Fabric CA
90
+ */
91
+ readonly users?: Array<user.HyperledgerFabricUserProps>;
92
+ }
93
+ /**
94
+ * Creates a Hyperledger Fabric network on Amazon Managed Blockchain
95
+ */
96
+ export declare class HyperledgerFabricNetwork extends constructs.Construct {
97
+ /**
98
+ * Managed Blockchain network name
99
+ */
100
+ readonly networkName: string;
101
+ /**
102
+ * Managed Blockchain network description
103
+ */
104
+ readonly networkDescription: string;
105
+ /**
106
+ * Managed Blockchain network identifier generated on construction
107
+ */
108
+ readonly networkId: string;
109
+ /**
110
+ * Managed Blockchain member name
111
+ */
112
+ readonly memberName: string;
113
+ /**
114
+ * Managed Blockchain member description
115
+ */
116
+ readonly memberDescription: string;
117
+ /**
118
+ * Managed Blockchain member identifier generated on construction
119
+ */
120
+ readonly memberId: string;
121
+ /**
122
+ * Hyperledger Fabric framework version
123
+ */
124
+ readonly frameworkVersion: FrameworkVersion;
125
+ /**
126
+ * Managed Blockchain network edition
127
+ */
128
+ readonly networkEdition: NetworkEdition;
129
+ /**
130
+ * The duration from the time that a proposal is created until it expires
131
+ */
132
+ readonly proposalDurationInHours: number;
133
+ /**
134
+ * The percentage of votes among all members that must be yes for a proposal to be approved
135
+ */
136
+ readonly thresholdPercentage: number;
137
+ /**
138
+ * Determines whether the yes votes must be greater than the threshold percentage
139
+ * or must be greater than or equal to the threhold percentage to be approved
140
+ */
141
+ readonly thresholdComparator: ThresholdComparator;
142
+ /**
143
+ * The configuration to enable or disable certificate authority logging
144
+ */
145
+ readonly enableCaLogging: boolean;
146
+ /**
147
+ * Managed Blockchain network VPC endpoint service name
148
+ */
149
+ readonly vpcEndpointServiceName: string;
150
+ /**
151
+ * Managed Blockchain network ordering service endpoint
152
+ */
153
+ readonly ordererEndpoint: string;
154
+ /**
155
+ * Managed Blockchain member CA endpoint
156
+ */
157
+ readonly caEndpoint: string;
158
+ /**
159
+ * Secret ARN for the Hyperledger Fabric admin password
160
+ */
161
+ readonly adminPasswordSecret: secretsmanager.Secret;
162
+ /**
163
+ * Secret for Hyperledger Fabric admin private key
164
+ */
165
+ readonly adminPrivateKeySecret: secretsmanager.Secret;
166
+ /**
167
+ * Secret for Hyperledger Fabric admin signed certificate
168
+ */
169
+ readonly adminSignedCertSecret: secretsmanager.Secret;
170
+ /**
171
+ * List of nodes created in the network
172
+ */
173
+ readonly nodes: Array<node.HyperledgerFabricNode>;
174
+ /**
175
+ * The client network to interact with the Hyperledger Fabric network
176
+ */
177
+ readonly client: client.HyperledgerFabricClient;
178
+ /**
179
+ * List of users registered with CA
180
+ */
181
+ readonly users: Array<user.HyperledgerFabricUser>;
182
+ constructor(scope: constructs.Construct, id: string, props: HyperledgerFabricNetworkProps);
183
+ }
package/lib/network.js ADDED
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.HyperledgerFabricNetwork = exports.ThresholdComparator = exports.NetworkEdition = exports.FrameworkVersion = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
7
+ // SPDX-License-Identifier: MIT-0
8
+ const cdk = require("aws-cdk-lib");
9
+ const managedblockchain = require("aws-cdk-lib/aws-managedblockchain");
10
+ const secretsmanager = require("aws-cdk-lib/aws-secretsmanager");
11
+ const customresources = require("aws-cdk-lib/custom-resources");
12
+ const constructs = require("constructs");
13
+ const client = require("./client");
14
+ const identity = require("./identity");
15
+ const node = require("./node");
16
+ const user = require("./user");
17
+ const utilities = require("./utilities");
18
+ /*
19
+ * Define which Hyperledger Fabric framework to use
20
+ */
21
+ var FrameworkVersion;
22
+ (function (FrameworkVersion) {
23
+ FrameworkVersion["VERSION_1_2"] = "1.2";
24
+ FrameworkVersion["VERSION_1_4"] = "1.4";
25
+ FrameworkVersion["VERSION_2_2"] = "2.2";
26
+ })(FrameworkVersion = exports.FrameworkVersion || (exports.FrameworkVersion = {}));
27
+ /*
28
+ * Starter networks are cheaper, but are limited to 2 nodes that
29
+ * can only be from a subset of types (see node.ts for the list)
30
+ */
31
+ var NetworkEdition;
32
+ (function (NetworkEdition) {
33
+ NetworkEdition["STARTER"] = "STARTER";
34
+ NetworkEdition["STANDARD"] = "STANDARD";
35
+ })(NetworkEdition = exports.NetworkEdition || (exports.NetworkEdition = {}));
36
+ /*
37
+ * Constants to define ties in voting for new members
38
+ */
39
+ var ThresholdComparator;
40
+ (function (ThresholdComparator) {
41
+ ThresholdComparator["GREATER_THAN"] = "GREATER_THAN";
42
+ ThresholdComparator["GREATER_THAN_OR_EQUAL_TO"] = "GREATER_THAN_OR_EQUAL_TO";
43
+ })(ThresholdComparator = exports.ThresholdComparator || (exports.ThresholdComparator = {}));
44
+ /**
45
+ * Creates a Hyperledger Fabric network on Amazon Managed Blockchain
46
+ */
47
+ class HyperledgerFabricNetwork extends constructs.Construct {
48
+ constructor(scope, id, props) {
49
+ super(scope, id);
50
+ // Collect metadata on the stack
51
+ const partition = cdk.Stack.of(this).partition;
52
+ const region = cdk.Stack.of(this).region;
53
+ const account = cdk.Stack.of(this).account;
54
+ // Populate instance variables from input properties, using defaults if values not provided
55
+ this.networkName = props.networkName;
56
+ this.networkDescription = props.networkDescription ?? props.networkName;
57
+ this.memberName = props.memberName;
58
+ this.memberDescription = props.memberDescription ?? props.memberName;
59
+ this.frameworkVersion = props.frameworkVersion ?? FrameworkVersion.VERSION_1_4;
60
+ this.networkEdition = props.networkEdition ?? NetworkEdition.STANDARD;
61
+ this.proposalDurationInHours = props.proposalDurationInHours ?? 24;
62
+ this.thresholdPercentage = props.thresholdPercentage ?? 50;
63
+ this.thresholdComparator = props.thresholdComparator ?? ThresholdComparator.GREATER_THAN;
64
+ this.enableCaLogging = props.enableCaLogging ?? true;
65
+ this.users = [];
66
+ // Ensure the parameters captured above are valid, so we don't
67
+ // need to wait until deployment time to discover an error
68
+ utilities.validateRegion(region);
69
+ if (!utilities.validateString(this.networkName, 1, 64)) {
70
+ throw new Error('Network name is invalid or not provided. It can be up to 64 characters long.');
71
+ }
72
+ if (!utilities.validateString(this.networkDescription, 0, 128)) {
73
+ throw new Error('Network description is invalid. It can be up to 128 characters long.');
74
+ }
75
+ if (!utilities.validateString(this.memberName, 1, 64, /^(?!-|[0-9])(?!.*-$)(?!.*?--)[a-zA-Z0-9-]+$/)) {
76
+ throw new Error('Member name is invalid or not provided. It can be up to 64 characters long, and can have alphanumeric characters and hyphen(s). It cannot start with a number, or start and end with a hyphen (-), or have two consecutive hyphens. The member name must also be unique across the network.');
77
+ }
78
+ if (!utilities.validateString(this.memberDescription, 0, 128)) {
79
+ throw new Error('Member description is invalid. It can be up to 128 characters long.');
80
+ }
81
+ if (!utilities.validateInteger(this.proposalDurationInHours, 1, 168)) {
82
+ throw new Error('Voting policy proposal duration must be between 1 and 168 hours.');
83
+ }
84
+ if (!utilities.validateInteger(this.thresholdPercentage, 0, 100)) {
85
+ throw new Error('Voting policy threshold percentage must be between 0 and 100.');
86
+ }
87
+ // Ensure the user affiliation includes the member name,
88
+ // if the user list for registration is provided
89
+ if (props.users) {
90
+ props.users.forEach(e => {
91
+ if (!e.affilitation.startsWith(this.memberName))
92
+ throw new Error('User affiliation is invalid. Affiliation should start with Member name');
93
+ });
94
+ }
95
+ // Per the Managed Blockchain documentation, the admin password must be at least eight
96
+ // characters long and no more than 32 characters. It must contain at least one uppercase
97
+ // letter, one lowercase letter, and one digit. It cannot have a single quotation mark (‘),
98
+ // a double quotation marks (“), a forward slash(/), a backward slash(\), @, or a space;
99
+ // several other characters are exluded here to make the password easier to use in scripts
100
+ const passwordRequirements = {
101
+ passwordLength: 32,
102
+ requireEachIncludedType: true,
103
+ excludeCharacters: '\'"/\\@ &{}<>*|',
104
+ };
105
+ this.adminPasswordSecret = new secretsmanager.Secret(this, 'AdminPassword', { generateSecretString: passwordRequirements });
106
+ // The initially enrolled admin user credentials will be stored in these secrets
107
+ this.adminPrivateKeySecret = new secretsmanager.Secret(this, 'AdminPrivateKey');
108
+ this.adminSignedCertSecret = new secretsmanager.Secret(this, 'AdminSignedCert');
109
+ // Build out the Cloudformation construct for the network/member
110
+ const networkConfiguration = {
111
+ name: this.networkName,
112
+ description: this.networkDescription,
113
+ framework: 'HYPERLEDGER_FABRIC',
114
+ frameworkVersion: this.frameworkVersion,
115
+ networkFrameworkConfiguration: {
116
+ networkFabricConfiguration: {
117
+ edition: this.networkEdition,
118
+ },
119
+ },
120
+ votingPolicy: {
121
+ approvalThresholdPolicy: {
122
+ proposalDurationInHours: this.proposalDurationInHours,
123
+ thresholdPercentage: this.thresholdPercentage,
124
+ thresholdComparator: this.thresholdComparator,
125
+ },
126
+ },
127
+ };
128
+ // Note the use of the unwrap below is the only possible way to get
129
+ // the secret value into the CloudFormation; it will still not directly
130
+ // be included in the synthesized template so usage here is still safe
131
+ const memberConfiguration = {
132
+ name: this.memberName,
133
+ description: this.memberDescription,
134
+ memberFrameworkConfiguration: {
135
+ memberFabricConfiguration: {
136
+ adminUsername: 'admin',
137
+ adminPassword: this.adminPasswordSecret.secretValue.unsafeUnwrap(),
138
+ },
139
+ },
140
+ };
141
+ const network = new managedblockchain.CfnMember(this, 'Network', { networkConfiguration, memberConfiguration });
142
+ // Capture data included in the Cloudformation output in instance variables
143
+ this.networkId = network.getAtt('NetworkId').toString();
144
+ this.memberId = network.getAtt('MemberId').toString();
145
+ // Build out the associated node constructs
146
+ this.nodes = node.HyperledgerFabricNode.constructNodes(this, props.nodes);
147
+ // Due to a race condition in CDK custom resources (https://github.com/aws/aws-cdk/issues/18237),
148
+ // the necessary permissions for all SDK calls in the stack need to be added here, even though
149
+ // the calls in this construct don't need access to the nodes; this also means node constructs
150
+ // can't populate their outputs fully until later, which is annoying
151
+ const nodeIds = this.nodes.map(n => n.nodeId);
152
+ const nodeArns = nodeIds.map(i => `arn:${partition}:managedblockchain:${region}:${account}:nodes/${i}`);
153
+ const sdkCallPolicy = customresources.AwsCustomResourcePolicy.fromSdkCalls({
154
+ resources: [
155
+ `arn:${partition}:managedblockchain:${region}::networks/${this.networkId}`,
156
+ `arn:${partition}:managedblockchain:${region}:${account}:members/${this.memberId}`,
157
+ ...nodeArns,
158
+ ],
159
+ });
160
+ // Cloudformation doesn't include all the network and member attributes
161
+ // needed to use Hyperledger Fabric, so use SDK calls to fetch said data
162
+ const networkDataSdkCall = {
163
+ service: 'ManagedBlockchain',
164
+ action: 'getNetwork',
165
+ parameters: { NetworkId: this.networkId },
166
+ physicalResourceId: customresources.PhysicalResourceId.of('Id'),
167
+ };
168
+ const memberDataSdkCall = {
169
+ service: 'ManagedBlockchain',
170
+ action: 'getMember',
171
+ parameters: { NetworkId: this.networkId, MemberId: this.memberId },
172
+ physicalResourceId: customresources.PhysicalResourceId.of('Id'),
173
+ };
174
+ // Data items need fetching on creation and updating; nothing needs doing on deletion
175
+ const networkData = new customresources.AwsCustomResource(this, 'NetworkDataResource', {
176
+ policy: sdkCallPolicy,
177
+ onCreate: networkDataSdkCall,
178
+ onUpdate: networkDataSdkCall,
179
+ });
180
+ const memberData = new customresources.AwsCustomResource(this, 'MemberDataResource', {
181
+ policy: sdkCallPolicy,
182
+ onCreate: memberDataSdkCall,
183
+ onUpdate: memberDataSdkCall,
184
+ });
185
+ // Cloudformation doesn't include logging configuration so use SDK call to do so
186
+ const logConfiguration = {
187
+ Fabric: { CaLogs: { Cloudwatch: { Enabled: this.enableCaLogging } } },
188
+ };
189
+ const configureCaLogSdkCall = {
190
+ service: 'ManagedBlockchain',
191
+ action: 'updateMember',
192
+ parameters: { NetworkId: this.networkId, MemberId: this.memberId, LogPublishingConfiguration: logConfiguration },
193
+ physicalResourceId: customresources.PhysicalResourceId.of('Id'),
194
+ };
195
+ new customresources.AwsCustomResource(this, 'ConfigureCaLogResource', {
196
+ policy: sdkCallPolicy,
197
+ onCreate: configureCaLogSdkCall,
198
+ onUpdate: configureCaLogSdkCall,
199
+ });
200
+ // Grab items out of the above return values and stick them in output properties
201
+ this.vpcEndpointServiceName = networkData.getResponseField('Network.VpcEndpointServiceName');
202
+ this.ordererEndpoint = networkData.getResponseField('Network.FrameworkAttributes.Fabric.OrderingServiceEndpoint');
203
+ this.caEndpoint = memberData.getResponseField('Member.FrameworkAttributes.Fabric.CaEndpoint');
204
+ // As stated earlier, node constructs can't populate all their properties
205
+ // until after the above network and member SDK calls succeed; thus the
206
+ // function calls below where fetches are split out and logging is configured
207
+ for (const n of this.nodes) {
208
+ n.configureLogging(sdkCallPolicy);
209
+ n.fetchData(sdkCallPolicy);
210
+ }
211
+ // Build out the client VPC construct
212
+ this.client = new client.HyperledgerFabricClient(this, 'NetworkClient', props.client);
213
+ // Build out all the custom resources to register and enroll identities to CA
214
+ const identityResources = new identity.HyperledgerFabricIdentity(this, 'Identity');
215
+ // Enroll the administrator and store its credentials on Secrets Manager
216
+ new cdk.CustomResource(this, 'AdminCustomResource', { serviceToken: identityResources.adminProvider.serviceToken });
217
+ // Register and enroll users, if provided
218
+ if (props.users)
219
+ this.users = Array.from(props.users.entries()).map(e => new user.HyperledgerFabricUser(this, `User${e[0]}`, e[1]));
220
+ }
221
+ }
222
+ exports.HyperledgerFabricNetwork = HyperledgerFabricNetwork;
223
+ _a = JSII_RTTI_SYMBOL_1;
224
+ HyperledgerFabricNetwork[_a] = { fqn: "@cdklabs/cdk-hyperledger-fabric-network.HyperledgerFabricNetwork", version: "0.0.20" };
225
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29yay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXR3b3JrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLGlDQUFpQztBQUdqQyxtQ0FBbUM7QUFDbkMsdUVBQXVFO0FBQ3ZFLGlFQUFpRTtBQUNqRSxnRUFBZ0U7QUFDaEUseUNBQXlDO0FBRXpDLG1DQUFtQztBQUNuQyx1Q0FBdUM7QUFDdkMsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQix5Q0FBeUM7QUFHekM7O0dBRUc7QUFDSCxJQUFZLGdCQUlYO0FBSkQsV0FBWSxnQkFBZ0I7SUFDMUIsdUNBQW1CLENBQUE7SUFDbkIsdUNBQW1CLENBQUE7SUFDbkIsdUNBQW1CLENBQUE7QUFDckIsQ0FBQyxFQUpXLGdCQUFnQixHQUFoQix3QkFBZ0IsS0FBaEIsd0JBQWdCLFFBSTNCO0FBRUQ7OztHQUdHO0FBQ0gsSUFBWSxjQUdYO0FBSEQsV0FBWSxjQUFjO0lBQ3hCLHFDQUFtQixDQUFBO0lBQ25CLHVDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFIVyxjQUFjLEdBQWQsc0JBQWMsS0FBZCxzQkFBYyxRQUd6QjtBQUVEOztHQUVHO0FBQ0gsSUFBWSxtQkFHWDtBQUhELFdBQVksbUJBQW1CO0lBQzdCLG9EQUE2QixDQUFBO0lBQzdCLDRFQUFxRCxDQUFBO0FBQ3ZELENBQUMsRUFIVyxtQkFBbUIsR0FBbkIsMkJBQW1CLEtBQW5CLDJCQUFtQixRQUc5QjtBQTZGRDs7R0FFRztBQUNILE1BQWEsd0JBQXlCLFNBQVEsVUFBVSxDQUFDLFNBQVM7SUE2R2hFLFlBQVksS0FBMkIsRUFBRSxFQUFVLEVBQUUsS0FBb0M7UUFFdkYsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixnQ0FBZ0M7UUFDaEMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDO1FB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QUF1RTtRQUN2RSw2RUFBNkU7UUFDN0UsS0FBSyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFO1lBQzFCLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNsQyxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQzVCO1FBRUQscUNBQXFDO1FBQ3JDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsdUJBQXVCLENBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFdEYsNkVBQTZFO1FBQzdFLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxRQUFRLENBQUMseUJBQXlCLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRW5GLHdFQUF3RTtRQUN4RSxJQUFJLEdBQUcsQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLHFCQUFxQixFQUFFLEVBQUUsWUFBWSxFQUFFLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBRXBILHlDQUF5QztRQUN6QyxJQUFJLEtBQUssQ0FBQyxLQUFLO1lBQUUsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RJLENBQUM7O0FBNVNILDREQThTQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVC0wXG5cblxuaW1wb3J0ICogYXMgY2RrIGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIG1hbmFnZWRibG9ja2NoYWluIGZyb20gJ2F3cy1jZGstbGliL2F3cy1tYW5hZ2VkYmxvY2tjaGFpbic7XG5pbXBvcnQgKiBhcyBzZWNyZXRzbWFuYWdlciBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXInO1xuaW1wb3J0ICogYXMgY3VzdG9tcmVzb3VyY2VzIGZyb20gJ2F3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXMnO1xuaW1wb3J0ICogYXMgY29uc3RydWN0cyBmcm9tICdjb25zdHJ1Y3RzJztcblxuaW1wb3J0ICogYXMgY2xpZW50IGZyb20gJy4vY2xpZW50JztcbmltcG9ydCAqIGFzIGlkZW50aXR5IGZyb20gJy4vaWRlbnRpdHknO1xuaW1wb3J0ICogYXMgbm9kZSBmcm9tICcuL25vZGUnO1xuaW1wb3J0ICogYXMgdXNlciBmcm9tICcuL3VzZXInO1xuaW1wb3J0ICogYXMgdXRpbGl0aWVzIGZyb20gJy4vdXRpbGl0aWVzJztcblxuXG4vKlxuICogRGVmaW5lIHdoaWNoIEh5cGVybGVkZ2VyIEZhYnJpYyBmcmFtZXdvcmsgdG8gdXNlXG4gKi9cbmV4cG9ydCBlbnVtIEZyYW1ld29ya1ZlcnNpb24ge1xuICBWRVJTSU9OXzFfMiA9ICcxLjInLFxuICBWRVJTSU9OXzFfNCA9ICcxLjQnLFxuICBWRVJTSU9OXzJfMiA9ICcyLjInLFxufVxuXG4vKlxuICogU3RhcnRlciBuZXR3b3JrcyBhcmUgY2hlYXBlciwgYnV0IGFyZSBsaW1pdGVkIHRvIDIgbm9kZXMgdGhhdFxuICogY2FuIG9ubHkgYmUgZnJvbSBhIHN1YnNldCBvZiB0eXBlcyAoc2VlIG5vZGUudHMgZm9yIHRoZSBsaXN0KVxuICovXG5leHBvcnQgZW51bSBOZXR3b3JrRWRpdGlvbiB7XG4gIFNUQVJURVIgPSAnU1RBUlRFUicsXG4gIFNUQU5EQVJEID0gJ1NUQU5EQVJEJyxcbn1cblxuLypcbiAqIENvbnN0YW50cyB0byBkZWZpbmUgdGllcyBpbiB2b3RpbmcgZm9yIG5ldyBtZW1iZXJzXG4gKi9cbmV4cG9ydCBlbnVtIFRocmVzaG9sZENvbXBhcmF0b3Ige1xuICBHUkVBVEVSX1RIQU4gPSAnR1JFQVRFUl9USEFOJyxcbiAgR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPID0gJ0dSRUFURVJfVEhBTl9PUl9FUVVBTF9UTycsXG59XG5cblxuLyoqXG4gKiBDb25zdHJ1Y3QgcHJvcGVydGllcyBmb3IgYEh5cGVybGVkZ2VyRmFicmljTmV0d29ya2BcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIeXBlcmxlZGdlckZhYnJpY05ldHdvcmtQcm9wcyB7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IG5ldHdvcmtOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGRlc2NyaXB0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU2V0IHRvIG1hdGNoIG5ldHdvcmsgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbmV0d29ya0Rlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IG1lbWJlck5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG1lbWJlciBkZXNjcmlwdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFNldCB0byBtYXRjaCBtZW1iZXIgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbWVtYmVyRGVzY3JpcHRpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEh5cGVybGVkZ2VyIEZhYnJpYyBmcmFtZXdvcmsgdmVyc2lvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEZyYW1ld29ya1ZlcnNpb24uVkVSU0lPTl8xXzRcbiAgICovXG4gIHJlYWRvbmx5IGZyYW1ld29ya1ZlcnNpb24/OiBGcmFtZXdvcmtWZXJzaW9uO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbmV0d29yayBlZGl0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTmV0d29ya0VkaXRpb24uU1RBTkRBUkRcbiAgICovXG4gIHJlYWRvbmx5IG5ldHdvcmtFZGl0aW9uPzogTmV0d29ya0VkaXRpb247XG5cbiAgLyoqXG4gICAqIFRoZSBkdXJhdGlvbiBmcm9tIHRoZSB0aW1lIHRoYXQgYSBwcm9wb3NhbCBpcyBjcmVhdGVkIHVudGlsIGl0IGV4cGlyZXNcbiAgICogQGRlZmF1bHQgLSAyNCBob3Vyc1xuICAgKi9cbiAgcmVhZG9ubHkgcHJvcG9zYWxEdXJhdGlvbkluSG91cnM/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBwZXJjZW50YWdlIG9mIHZvdGVzIGFtb25nIGFsbCBtZW1iZXJzIHRoYXQgbXVzdCBiZSB5ZXMgZm9yIGEgcHJvcG9zYWwgdG8gYmUgYXBwcm92ZWRcbiAgICogQGRlZmF1bHQgLSA1MCBwZXJjZW50XG4gICAqL1xuICByZWFkb25seSB0aHJlc2hvbGRQZXJjZW50YWdlPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgdGhlIHllcyB2b3RlcyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB0aGUgdGhyZXNob2xkIHBlcmNlbnRhZ2VcbiAgICogb3IgbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHRocmVob2xkIHBlcmNlbnRhZ2UgdG8gYmUgYXBwcm92ZWRcbiAgICogQGRlZmF1bHQgLSBHUkVBVEVSX1RIQU5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZENvbXBhcmF0b3I/OiBUaHJlc2hvbGRDb21wYXJhdG9yO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uZmlndXJhdGlvbiB0byBlbmFibGUgb3IgZGlzYWJsZSBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkgbG9nZ2luZ1xuICAgKiBAZGVmYXVsdCAtIHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGVuYWJsZUNhTG9nZ2luZz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIExpc3Qgb2Ygbm9kZXMgdG8gY3JlYXRlIG9uIHRoZSBuZXR3b3JrXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gT25lIG5vZGUgd2l0aCBkZWZhdWx0IGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHJlYWRvbmx5IG5vZGVzPzogQXJyYXk8bm9kZS5IeXBlcmxlZGdlckZhYnJpY05vZGVQcm9wcz47XG5cbiAgLyoqXG4gICAqIFRoZSBDbGllbnQgbmV0d29yayB0byBpbnRlcmFjdCB3aXRoIHRoZSBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29ya1xuICAgKiBAZGVmYXVsdCAtIENsaWVudCBuZXR3b3JrIHdpdGggRGVmYXVsdCBwcm9wZXJ0aWVzXG4gICAqIChDSURSLWAxMC4wLjAuMC8xNmAgYW5kIHN1Ym5ldHMgb2YgdHlwZSBgUFJJVkFURV9JU09MQVRFRGApXG4gICAqL1xuICByZWFkb25seSBjbGllbnQ/OiBjbGllbnQuSHlwZXJsZWRnZXJGYWJyaWNDbGllbnRQcm9wcztcblxuICAvKipcbiAgICogTGlzdCBvZiB1c2VycyB0byByZWdpc3RlciB3aXRoIEZhYnJpYyBDQVxuICAgKi9cbiAgcmVhZG9ubHkgdXNlcnM/OiBBcnJheTx1c2VyLkh5cGVybGVkZ2VyRmFicmljVXNlclByb3BzPjtcblxufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3JrIG9uIEFtYXpvbiBNYW5hZ2VkIEJsb2NrY2hhaW5cbiAqL1xuZXhwb3J0IGNsYXNzIEh5cGVybGVkZ2VyRmFicmljTmV0d29yayBleHRlbmRzIGNvbnN0cnVjdHMuQ29uc3RydWN0IHtcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5ldHdvcmsgbmFtZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG5ldHdvcmtOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGRlc2NyaXB0aW9uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmV0d29ya0Rlc2NyaXB0aW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGlkZW50aWZpZXIgZ2VuZXJhdGVkIG9uIGNvbnN0cnVjdGlvblxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG5ldHdvcmtJZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIG5hbWVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBtZW1iZXJOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBtZW1iZXIgZGVzY3JpcHRpb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBtZW1iZXJEZXNjcmlwdGlvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIGlkZW50aWZpZXIgZ2VuZXJhdGVkIG9uIGNvbnN0cnVjdGlvblxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG1lbWJlcklkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEh5cGVybGVkZ2VyIEZhYnJpYyBmcmFtZXdvcmsgdmVyc2lvblxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGZyYW1ld29ya1ZlcnNpb246IEZyYW1ld29ya1ZlcnNpb247XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGVkaXRpb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXR3b3JrRWRpdGlvbjogTmV0d29ya0VkaXRpb247XG5cbiAgLyoqXG4gICAqIFRoZSBkdXJhdGlvbiBmcm9tIHRoZSB0aW1lIHRoYXQgYSBwcm9wb3NhbCBpcyBjcmVhdGVkIHVudGlsIGl0IGV4cGlyZXNcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwcm9wb3NhbER1cmF0aW9uSW5Ib3VyczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgcGVyY2VudGFnZSBvZiB2b3RlcyBhbW9uZyBhbGwgbWVtYmVycyB0aGF0IG11c3QgYmUgeWVzIGZvciBhIHByb3Bvc2FsIHRvIGJlIGFwcHJvdmVkXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdGhyZXNob2xkUGVyY2VudGFnZTogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgdGhlIHllcyB2b3RlcyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB0aGUgdGhyZXNob2xkIHBlcmNlbnRhZ2VcbiAgICogb3IgbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHRocmVob2xkIHBlcmNlbnRhZ2UgdG8gYmUgYXBwcm92ZWRcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0aHJlc2hvbGRDb21wYXJhdG9yOiBUaHJlc2hvbGRDb21wYXJhdG9yO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uZmlndXJhdGlvbiB0byBlbmFibGUgb3IgZGlzYWJsZSBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkgbG9nZ2luZ1xuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGVuYWJsZUNhTG9nZ2luZzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5ldHdvcmsgVlBDIGVuZHBvaW50IHNlcnZpY2UgbmFtZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZwY0VuZHBvaW50U2VydmljZU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5ldHdvcmsgb3JkZXJpbmcgc2VydmljZSBlbmRwb2ludFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG9yZGVyZXJFbmRwb2ludDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIENBIGVuZHBvaW50XG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2FFbmRwb2ludDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTZWNyZXQgQVJOIGZvciB0aGUgSHlwZXJsZWRnZXIgRmFicmljIGFkbWluIHBhc3N3b3JkXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYWRtaW5QYXNzd29yZFNlY3JldDogc2VjcmV0c21hbmFnZXIuU2VjcmV0O1xuXG4gIC8qKlxuICAgKiBTZWNyZXQgZm9yIEh5cGVybGVkZ2VyIEZhYnJpYyBhZG1pbiBwcml2YXRlIGtleVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFkbWluUHJpdmF0ZUtleVNlY3JldDogc2VjcmV0c21hbmFnZXIuU2VjcmV0O1xuXG4gIC8qKlxuICAgKiBTZWNyZXQgZm9yIEh5cGVybGVkZ2VyIEZhYnJpYyBhZG1pbiBzaWduZWQgY2VydGlmaWNhdGVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhZG1pblNpZ25lZENlcnRTZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLlNlY3JldDtcblxuICAvKipcbiAgICogTGlzdCBvZiBub2RlcyBjcmVhdGVkIGluIHRoZSBuZXR3b3JrXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbm9kZXM6IEFycmF5PG5vZGUuSHlwZXJsZWRnZXJGYWJyaWNOb2RlPjtcblxuICAvKipcbiAgICogVGhlIGNsaWVudCBuZXR3b3JrIHRvIGludGVyYWN0IHdpdGggdGhlIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3JrXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2xpZW50OiBjbGllbnQuSHlwZXJsZWRnZXJGYWJyaWNDbGllbnQ7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2YgdXNlcnMgcmVnaXN0ZXJlZCB3aXRoIENBXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdXNlcnM6IEFycmF5PHVzZXIuSHlwZXJsZWRnZXJGYWJyaWNVc2VyPjtcblxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBjb25zdHJ1Y3RzLkNvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEh5cGVybGVkZ2VyRmFicmljTmV0d29ya1Byb3BzKSB7XG5cbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gQ29sbGVjdCBtZXRhZGF0YSBvbiB0aGUgc3RhY2tcbiAgICBjb25zdCBwYXJ0aXRpb24gPSBjZGsuU3RhY2sub2YodGhpcykucGFydGl0aW9uO1xuICAgIGNvbnN0IHJlZ2lvbiA9IGNkay5TdGFjay5vZih0aGlzKS5yZWdpb247XG4gICAgY29uc3QgYWNjb3VudCA9IGNkay5TdGFjay5vZih0aGlzKS5hY2NvdW50O1xuXG4gICAgLy8gUG9wdWxhdGUgaW5zdGFuY2UgdmFyaWFibGVzIGZyb20gaW5wdXQgcHJvcGVydGllcywgdXNpbmcgZGVmYXVsdHMgaWYgdmFsdWVzIG5vdCBwcm92aWRlZFxuICAgIHRoaXMubmV0d29ya05hbWUgPSBwcm9wcy5uZXR3b3JrTmFtZTtcbiAgICB0aGlzLm5ldHdvcmtEZXNjcmlwdGlvbiA9IHByb3BzLm5ldHdvcmtEZXNjcmlwdGlvbiA/PyBwcm9wcy5uZXR3b3JrTmFtZTtcbiAgICB0aGlzLm1lbWJlck5hbWUgPSBwcm9wcy5tZW1iZXJOYW1lO1xuICAgIHRoaXMubWVtYmVyRGVzY3JpcHRpb24gPSBwcm9wcy5tZW1iZXJEZXNjcmlwdGlvbiA/PyBwcm9wcy5tZW1iZXJOYW1lO1xuICAgIHRoaXMuZnJhbWV3b3JrVmVyc2lvbiA9IHByb3BzLmZyYW1ld29ya1ZlcnNpb24gPz8gRnJhbWV3b3JrVmVyc2lvbi5WRVJTSU9OXzFfNDtcbiAgICB0aGlzLm5ldHdvcmtFZGl0aW9uID0gcHJvcHMubmV0d29ya0VkaXRpb24gPz8gTmV0d29ya0VkaXRpb24uU1RBTkRBUkQ7XG4gICAgdGhpcy5wcm9wb3NhbER1cmF0aW9uSW5Ib3VycyA9IHByb3BzLnByb3Bvc2FsRHVyYXRpb25JbkhvdXJzID8/IDI0O1xuICAgIHRoaXMudGhyZXNob2xkUGVyY2VudGFnZSA9IHByb3BzLnRocmVzaG9sZFBlcmNlbnRhZ2UgPz8gNTA7XG4gICAgdGhpcy50aHJlc2hvbGRDb21wYXJhdG9yID0gcHJvcHMudGhyZXNob2xkQ29tcGFyYXRvciA/PyBUaHJlc2hvbGRDb21wYXJhdG9yLkdSRUFURVJfVEhBTjtcbiAgICB0aGlzLmVuYWJsZUNhTG9nZ2luZyA9IHByb3BzLmVuYWJsZUNhTG9nZ2luZyA/PyB0cnVlO1xuICAgIHRoaXMudXNlcnMgPSBbXTtcblxuICAgIC8vIEVuc3VyZSB0aGUgcGFyYW1ldGVycyBjYXB0dXJlZCBhYm92ZSBhcmUgdmFsaWQsIHNvIHdlIGRvbid0XG4gICAgLy8gbmVlZCB0byB3YWl0IHVudGlsIGRlcGxveW1lbnQgdGltZSB0byBkaXNjb3ZlciBhbiBlcnJvclxuICAgIHV0aWxpdGllcy52YWxpZGF0ZVJlZ2lvbihyZWdpb24pO1xuICAgIGlmICghdXRpbGl0aWVzLnZhbGlkYXRlU3RyaW5nKHRoaXMubmV0d29ya05hbWUsIDEsIDY0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOZXR3b3JrIG5hbWUgaXMgaW52YWxpZCBvciBub3QgcHJvdmlkZWQuIEl0IGNhbiBiZSB1cCB0byA2NCBjaGFyYWN0ZXJzIGxvbmcuJyk7XG4gICAgfVxuICAgIGlmICghdXRpbGl0aWVzLnZhbGlkYXRlU3RyaW5nKHRoaXMubmV0d29ya0Rlc2NyaXB0aW9uLCAwLCAxMjgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05ldHdvcmsgZGVzY3JpcHRpb24gaXMgaW52YWxpZC4gSXQgY2FuIGJlIHVwIHRvIDEyOCBjaGFyYWN0ZXJzIGxvbmcuJyk7XG4gICAgfVxuICAgIGlmICghdXRpbGl0aWVzLnZhbGlkYXRlU3RyaW5nKHRoaXMubWVtYmVyTmFtZSwgMSwgNjQsIC9eKD8hLXxbMC05XSkoPyEuKi0kKSg/IS4qPy0tKVthLXpBLVowLTktXSskLykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWVtYmVyIG5hbWUgaXMgaW52YWxpZCBvciBub3QgcHJvdmlkZWQuIEl0IGNhbiBiZSB1cCB0byA2NCBjaGFyYWN0ZXJzIGxvbmcsIGFuZCBjYW4gaGF2ZSBhbHBoYW51bWVyaWMgY2hhcmFjdGVycyBhbmQgaHlwaGVuKHMpLiBJdCBjYW5ub3Qgc3RhcnQgd2l0aCBhIG51bWJlciwgb3Igc3RhcnQgYW5kIGVuZCB3aXRoIGEgaHlwaGVuICgtKSwgb3IgaGF2ZSB0d28gY29uc2VjdXRpdmUgaHlwaGVucy4gVGhlIG1lbWJlciBuYW1lIG11c3QgYWxzbyBiZSB1bmlxdWUgYWNyb3NzIHRoZSBuZXR3b3JrLicpO1xuICAgIH1cbiAgICBpZiAoIXV0aWxpdGllcy52YWxpZGF0ZVN0cmluZyh0aGlzLm1lbWJlckRlc2NyaXB0aW9uLCAwLCAxMjgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01lbWJlciBkZXNjcmlwdGlvbiBpcyBpbnZhbGlkLiBJdCBjYW4gYmUgdXAgdG8gMTI4IGNoYXJhY3RlcnMgbG9uZy4nKTtcbiAgICB9XG4gICAgaWYgKCF1dGlsaXRpZXMudmFsaWRhdGVJbnRlZ2VyKHRoaXMucHJvcG9zYWxEdXJhdGlvbkluSG91cnMsIDEsIDE2OCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVm90aW5nIHBvbGljeSBwcm9wb3NhbCBkdXJhdGlvbiBtdXN0IGJlIGJldHdlZW4gMSBhbmQgMTY4IGhvdXJzLicpO1xuICAgIH1cbiAgICBpZiAoIXV0aWxpdGllcy52YWxpZGF0ZUludGVnZXIodGhpcy50aHJlc2hvbGRQZXJjZW50YWdlLCAwLCAxMDApKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1ZvdGluZyBwb2xpY3kgdGhyZXNob2xkIHBlcmNlbnRhZ2UgbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIDEwMC4nKTtcbiAgICB9XG5cbiAgICAvLyBFbnN1cmUgdGhlIHVzZXIgYWZmaWxpYXRpb24gaW5jbHVkZXMgdGhlIG1lbWJlciBuYW1lLFxuICAgIC8vIGlmIHRoZSB1c2VyIGxpc3QgZm9yIHJlZ2lzdHJhdGlvbiBpcyBwcm92aWRlZFxuICAgIGlmIChwcm9wcy51c2Vycykge1xuICAgICAgcHJvcHMudXNlcnMuZm9yRWFjaChlID0+IHtcbiAgICAgICAgaWYgKCFlLmFmZmlsaXRhdGlvbi5zdGFydHNXaXRoKHRoaXMubWVtYmVyTmFtZSkpIHRocm93IG5ldyBFcnJvcignVXNlciBhZmZpbGlhdGlvbiBpcyBpbnZhbGlkLiBBZmZpbGlhdGlvbiBzaG91bGQgc3RhcnQgd2l0aCBNZW1iZXIgbmFtZScpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gUGVyIHRoZSBNYW5hZ2VkIEJsb2NrY2hhaW4gZG9jdW1lbnRhdGlvbiwgdGhlIGFkbWluIHBhc3N3b3JkIG11c3QgYmUgYXQgbGVhc3QgZWlnaHRcbiAgICAvLyBjaGFyYWN0ZXJzIGxvbmcgYW5kIG5vIG1vcmUgdGhhbiAzMiBjaGFyYWN0ZXJzLiBJdCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIHVwcGVyY2FzZVxuICAgIC8vIGxldHRlciwgb25lIGxvd2VyY2FzZSBsZXR0ZXIsIGFuZCBvbmUgZGlnaXQuIEl0IGNhbm5vdCBoYXZlIGEgc2luZ2xlIHF1b3RhdGlvbiBtYXJrICjigJgpLFxuICAgIC8vIGEgZG91YmxlIHF1b3RhdGlvbiBtYXJrcyAo4oCcKSwgYSBmb3J3YXJkIHNsYXNoKC8pLCBhIGJhY2t3YXJkIHNsYXNoKFxcKSwgQCwgb3IgYSBzcGFjZTtcbiAgICAvLyBzZXZlcmFsIG90aGVyIGNoYXJhY3RlcnMgYXJlIGV4bHVkZWQgaGVyZSB0byBtYWtlIHRoZSBwYXNzd29yZCBlYXNpZXIgdG8gdXNlIGluIHNjcmlwdHNcbiAgICBjb25zdCBwYXNzd29yZFJlcXVpcmVtZW50cyA9IHtcbiAgICAgIHBhc3N3b3JkTGVuZ3RoOiAzMixcbiAgICAgIHJlcXVpcmVFYWNoSW5jbHVkZWRUeXBlOiB0cnVlLFxuICAgICAgZXhjbHVkZUNoYXJhY3RlcnM6ICdcXCdcIi9cXFxcQCAme308Pip8JyxcbiAgICB9O1xuICAgIHRoaXMuYWRtaW5QYXNzd29yZFNlY3JldCA9IG5ldyBzZWNyZXRzbWFuYWdlci5TZWNyZXQodGhpcywgJ0FkbWluUGFzc3dvcmQnLCB7IGdlbmVyYXRlU2VjcmV0U3RyaW5nOiBwYXNzd29yZFJlcXVpcmVtZW50cyB9KTtcblxuICAgIC8vIFRoZSBpbml0aWFsbHkgZW5yb2xsZWQgYWRtaW4gdXNlciBjcmVkZW50aWFscyB3aWxsIGJlIHN0b3JlZCBpbiB0aGVzZSBzZWNyZXRzXG4gICAgdGhpcy5hZG1pblByaXZhdGVLZXlTZWNyZXQgPSBuZXcgc2VjcmV0c21hbmFnZXIuU2VjcmV0KHRoaXMsICdBZG1pblByaXZhdGVLZXknKTtcbiAgICB0aGlzLmFkbWluU2lnbmVkQ2VydFNlY3JldCA9IG5ldyBzZWNyZXRzbWFuYWdlci5TZWNyZXQodGhpcywgJ0FkbWluU2lnbmVkQ2VydCcpO1xuXG4gICAgLy8gQnVpbGQgb3V0IHRoZSBDbG91ZGZvcm1hdGlvbiBjb25zdHJ1Y3QgZm9yIHRoZSBuZXR3b3JrL21lbWJlclxuICAgIGNvbnN0IG5ldHdvcmtDb25maWd1cmF0aW9uID0ge1xuICAgICAgbmFtZTogdGhpcy5uZXR3b3JrTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiB0aGlzLm5ldHdvcmtEZXNjcmlwdGlvbixcbiAgICAgIGZyYW1ld29yazogJ0hZUEVSTEVER0VSX0ZBQlJJQycsXG4gICAgICBmcmFtZXdvcmtWZXJzaW9uOiB0aGlzLmZyYW1ld29ya1ZlcnNpb24sXG4gICAgICBuZXR3b3JrRnJhbWV3b3JrQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBuZXR3b3JrRmFicmljQ29uZmlndXJhdGlvbjoge1xuICAgICAgICAgIGVkaXRpb246IHRoaXMubmV0d29ya0VkaXRpb24sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgdm90aW5nUG9saWN5OiB7XG4gICAgICAgIGFwcHJvdmFsVGhyZXNob2xkUG9saWN5OiB7XG4gICAgICAgICAgcHJvcG9zYWxEdXJhdGlvbkluSG91cnM6IHRoaXMucHJvcG9zYWxEdXJhdGlvbkluSG91cnMsXG4gICAgICAgICAgdGhyZXNob2xkUGVyY2VudGFnZTogdGhpcy50aHJlc2hvbGRQZXJjZW50YWdlLFxuICAgICAgICAgIHRocmVzaG9sZENvbXBhcmF0b3I6IHRoaXMudGhyZXNob2xkQ29tcGFyYXRvcixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIC8vIE5vdGUgdGhlIHVzZSBvZiB0aGUgdW53cmFwIGJlbG93IGlzIHRoZSBvbmx5IHBvc3NpYmxlIHdheSB0byBnZXRcbiAgICAvLyB0aGUgc2VjcmV0IHZhbHVlIGludG8gdGhlIENsb3VkRm9ybWF0aW9uOyBpdCB3aWxsIHN0aWxsIG5vdCBkaXJlY3RseVxuICAgIC8vIGJlIGluY2x1ZGVkIGluIHRoZSBzeW50aGVzaXplZCB0ZW1wbGF0ZSBzbyB1c2FnZSBoZXJlIGlzIHN0aWxsIHNhZmVcbiAgICBjb25zdCBtZW1iZXJDb25maWd1cmF0aW9uID0ge1xuICAgICAgbmFtZTogdGhpcy5tZW1iZXJOYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHRoaXMubWVtYmVyRGVzY3JpcHRpb24sXG4gICAgICBtZW1iZXJGcmFtZXdvcmtDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIG1lbWJlckZhYnJpY0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgICBhZG1pblVzZXJuYW1lOiAnYWRtaW4nLFxuICAgICAgICAgIGFkbWluUGFzc3dvcmQ6IHRoaXMuYWRtaW5QYXNzd29yZFNlY3JldC5zZWNyZXRWYWx1ZS51bnNhZmVVbndyYXAoKSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcbiAgICBjb25zdCBuZXR3b3JrID0gbmV3IG1hbmFnZWRibG9ja2NoYWluLkNmbk1lbWJlcih0aGlzLCAnTmV0d29yaycsIHsgbmV0d29ya0NvbmZpZ3VyYXRpb24sIG1lbWJlckNvbmZpZ3VyYXRpb24gfSk7XG5cbiAgICAvLyBDYXB0dXJlIGRhdGEgaW5jbHVkZWQgaW4gdGhlIENsb3VkZm9ybWF0aW9uIG91dHB1dCBpbiBpbnN0YW5jZSB2YXJpYWJsZXNcbiAgICB0aGlzLm5ldHdvcmtJZCA9IG5ldHdvcmsuZ2V0QXR0KCdOZXR3b3JrSWQnKS50b1N0cmluZygpO1xuICAgIHRoaXMubWVtYmVySWQgPSBuZXR3b3JrLmdldEF0dCgnTWVtYmVySWQnKS50b1N0cmluZygpO1xuXG4gICAgLy8gQnVpbGQgb3V0IHRoZSBhc3NvY2lhdGVkIG5vZGUgY29uc3RydWN0c1xuICAgIHRoaXMubm9kZXMgPSBub2RlLkh5cGVybGVkZ2VyRmFicmljTm9kZS5jb25zdHJ1Y3ROb2Rlcyh0aGlzLCBwcm9wcy5ub2Rlcyk7XG5cbiAgICAvLyBEdWUgdG8gYSByYWNlIGNvbmRpdGlvbiBpbiBDREsgY3VzdG9tIHJlc291cmNlcyAoaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3MtY2RrL2lzc3Vlcy8xODIzNyksXG4gICAgLy8gdGhlIG5lY2Vzc2FyeSBwZXJtaXNzaW9ucyBmb3IgYWxsIFNESyBjYWxscyBpbiB0aGUgc3RhY2sgbmVlZCB0byBiZSBhZGRlZCBoZXJlLCBldmVuIHRob3VnaFxuICAgIC8vIHRoZSBjYWxscyBpbiB0aGlzIGNvbnN0cnVjdCBkb24ndCBuZWVkIGFjY2VzcyB0byB0aGUgbm9kZXM7IHRoaXMgYWxzbyBtZWFucyBub2RlIGNvbnN0cnVjdHNcbiAgICAvLyBjYW4ndCBwb3B1bGF0ZSB0aGVpciBvdXRwdXRzIGZ1bGx5IHVudGlsIGxhdGVyLCB3aGljaCBpcyBhbm5veWluZ1xuICAgIGNvbnN0IG5vZGVJZHMgPSB0aGlzLm5vZGVzLm1hcChuID0+IG4ubm9kZUlkKTtcbiAgICBjb25zdCBub2RlQXJucyA9IG5vZGVJZHMubWFwKGkgPT4gYGFybjoke3BhcnRpdGlvbn06bWFuYWdlZGJsb2NrY2hhaW46JHtyZWdpb259OiR7YWNjb3VudH06bm9kZXMvJHtpfWApO1xuICAgIGNvbnN0IHNka0NhbGxQb2xpY3kgPSBjdXN0b21yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVNka0NhbGxzKHtcbiAgICAgIHJlc291cmNlczogW1xuICAgICAgICBgYXJuOiR7cGFydGl0aW9ufTptYW5hZ2VkYmxvY2tjaGFpbjoke3JlZ2lvbn06Om5ldHdvcmtzLyR7dGhpcy5uZXR3b3JrSWR9YCxcbiAgICAgICAgYGFybjoke3BhcnRpdGlvbn06bWFuYWdlZGJsb2NrY2hhaW46JHtyZWdpb259OiR7YWNjb3VudH06bWVtYmVycy8ke3RoaXMubWVtYmVySWR9YCxcbiAgICAgICAgLi4ubm9kZUFybnMsXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgLy8gQ2xvdWRmb3JtYXRpb24gZG9lc24ndCBpbmNsdWRlIGFsbCB0aGUgbmV0d29yayBhbmQgbWVtYmVyIGF0dHJpYnV0ZXNcbiAgICAvLyBuZWVkZWQgdG8gdXNlIEh5cGVybGVkZ2VyIEZhYnJpYywgc28gdXNlIFNESyBjYWxscyB0byBmZXRjaCBzYWlkIGRhdGFcbiAgICBjb25zdCBuZXR3b3JrRGF0YVNka0NhbGwgPSB7XG4gICAgICBzZXJ2aWNlOiAnTWFuYWdlZEJsb2NrY2hhaW4nLFxuICAgICAgYWN0aW9uOiAnZ2V0TmV0d29yaycsXG4gICAgICBwYXJhbWV0ZXJzOiB7IE5ldHdvcmtJZDogdGhpcy5uZXR3b3JrSWQgfSxcbiAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tcmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZignSWQnKSxcbiAgICB9O1xuICAgIGNvbnN0IG1lbWJlckRhdGFTZGtDYWxsID0ge1xuICAgICAgc2VydmljZTogJ01hbmFnZWRCbG9ja2NoYWluJyxcbiAgICAgIGFjdGlvbjogJ2dldE1lbWJlcicsXG4gICAgICBwYXJhbWV0ZXJzOiB7IE5ldHdvcmtJZDogdGhpcy5uZXR3b3JrSWQsIE1lbWJlcklkOiB0aGlzLm1lbWJlcklkIH0sXG4gICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IGN1c3RvbXJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoJ0lkJyksXG4gICAgfTtcblxuICAgIC8vIERhdGEgaXRlbXMgbmVlZCBmZXRjaGluZyBvbiBjcmVhdGlvbiBhbmQgdXBkYXRpbmc7IG5vdGhpbmcgbmVlZHMgZG9pbmcgb24gZGVsZXRpb25cbiAgICBjb25zdCBuZXR3b3JrRGF0YSA9IG5ldyBjdXN0b21yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgJ05ldHdvcmtEYXRhUmVzb3VyY2UnLCB7XG4gICAgICBwb2xpY3k6IHNka0NhbGxQb2xpY3ksXG4gICAgICBvbkNyZWF0ZTogbmV0d29ya0RhdGFTZGtDYWxsLFxuICAgICAgb25VcGRhdGU6IG5ldHdvcmtEYXRhU2RrQ2FsbCxcbiAgICB9KTtcbiAgICBjb25zdCBtZW1iZXJEYXRhID0gbmV3IGN1c3RvbXJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZSh0aGlzLCAnTWVtYmVyRGF0YVJlc291cmNlJywge1xuICAgICAgcG9saWN5OiBzZGtDYWxsUG9saWN5LFxuICAgICAgb25DcmVhdGU6IG1lbWJlckRhdGFTZGtDYWxsLFxuICAgICAgb25VcGRhdGU6IG1lbWJlckRhdGFTZGtDYWxsLFxuICAgIH0pO1xuXG4gICAgLy8gQ2xvdWRmb3JtYXRpb24gZG9lc24ndCBpbmNsdWRlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBzbyB1c2UgU0RLIGNhbGwgdG8gZG8gc29cbiAgICBjb25zdCBsb2dDb25maWd1cmF0aW9uID0ge1xuICAgICAgRmFicmljOiB7IENhTG9nczogeyBDbG91ZHdhdGNoOiB7IEVuYWJsZWQ6IHRoaXMuZW5hYmxlQ2FMb2dnaW5nIH0gfSB9LFxuICAgIH07XG4gICAgY29uc3QgY29uZmlndXJlQ2FMb2dTZGtDYWxsID0ge1xuICAgICAgc2VydmljZTogJ01hbmFnZWRCbG9ja2NoYWluJyxcbiAgICAgIGFjdGlvbjogJ3VwZGF0ZU1lbWJlcicsXG4gICAgICBwYXJhbWV0ZXJzOiB7IE5ldHdvcmtJZDogdGhpcy5uZXR3b3JrSWQsIE1lbWJlcklkOiB0aGlzLm1lbWJlcklkLCBMb2dQdWJsaXNoaW5nQ29uZmlndXJhdGlvbjogbG9nQ29uZmlndXJhdGlvbiB9LFxuICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBjdXN0b21yZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKCdJZCcpLFxuICAgIH07XG4gICAgbmV3IGN1c3RvbXJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZSh0aGlzLCAnQ29uZmlndXJlQ2FMb2dSZXNvdXJjZScsIHtcbiAgICAgIHBvbGljeTogc2RrQ2FsbFBvbGljeSxcbiAgICAgIG9uQ3JlYXRlOiBjb25maWd1cmVDYUxvZ1Nka0NhbGwsXG4gICAgICBvblVwZGF0ZTogY29uZmlndXJlQ2FMb2dTZGtDYWxsLFxuICAgIH0pO1xuXG4gICAgLy8gR3JhYiBpdGVtcyBvdXQgb2YgdGhlIGFib3ZlIHJldHVybiB2YWx1ZXMgYW5kIHN0aWNrIHRoZW0gaW4gb3V0cHV0IHByb3BlcnRpZXNcbiAgICB0aGlzLnZwY0VuZHBvaW50U2VydmljZU5hbWUgPSBuZXR3b3JrRGF0YS5nZXRSZXNwb25zZUZpZWxkKCdOZXR3b3JrLlZwY0VuZHBvaW50U2VydmljZU5hbWUnKTtcbiAgICB0aGlzLm9yZGVyZXJFbmRwb2ludCA9IG5ldHdvcmtEYXRhLmdldFJlc3BvbnNlRmllbGQoJ05ldHdvcmsuRnJhbWV3b3JrQXR0cmlidXRlcy5GYWJyaWMuT3JkZXJpbmdTZXJ2aWNlRW5kcG9pbnQnKTtcbiAgICB0aGlzLmNhRW5kcG9pbnQgPSBtZW1iZXJEYXRhLmdldFJlc3BvbnNlRmllbGQoJ01lbWJlci5GcmFtZXdvcmtBdHRyaWJ1dGVzLkZhYnJpYy5DYUVuZHBvaW50Jyk7XG5cbiAgICAvLyBBcyBzdGF0ZWQgZWFybGllciwgbm9kZSBjb25zdHJ1Y3RzIGNhbid0IHBvcHVsYXRlIGFsbCB0aGVpciBwcm9wZXJ0aWVzXG4gICAgLy8gdW50aWwgYWZ0ZXIgdGhlIGFib3ZlIG5ldHdvcmsgYW5kIG1lbWJlciBTREsgY2FsbHMgc3VjY2VlZDsgdGh1cyB0aGVcbiAgICAvLyBmdW5jdGlvbiBjYWxscyBiZWxvdyB3aGVyZSBmZXRjaGVzIGFyZSBzcGxpdCBvdXQgYW5kIGxvZ2dpbmcgaXMgY29uZmlndXJlZFxuICAgIGZvciAoY29uc3QgbiBvZiB0aGlzLm5vZGVzKSB7XG4gICAgICBuLmNvbmZpZ3VyZUxvZ2dpbmcoc2RrQ2FsbFBvbGljeSk7XG4gICAgICBuLmZldGNoRGF0YShzZGtDYWxsUG9saWN5KTtcbiAgICB9XG5cbiAgICAvLyBCdWlsZCBvdXQgdGhlIGNsaWVudCBWUEMgY29uc3RydWN0XG4gICAgdGhpcy5jbGllbnQgPSBuZXcgY2xpZW50Lkh5cGVybGVkZ2VyRmFicmljQ2xpZW50KHRoaXMsICdOZXR3b3JrQ2xpZW50JywgcHJvcHMuY2xpZW50KTtcblxuICAgIC8vIEJ1aWxkIG91dCBhbGwgdGhlIGN1c3RvbSByZXNvdXJjZXMgdG8gcmVnaXN0ZXIgYW5kIGVucm9sbCBpZGVudGl0aWVzIHRvIENBXG4gICAgY29uc3QgaWRlbnRpdHlSZXNvdXJjZXMgPSBuZXcgaWRlbnRpdHkuSHlwZXJsZWRnZXJGYWJyaWNJZGVudGl0eSh0aGlzLCAnSWRlbnRpdHknKTtcblxuICAgIC8vIEVucm9sbCB0aGUgYWRtaW5pc3RyYXRvciBhbmQgc3RvcmUgaXRzIGNyZWRlbnRpYWxzIG9uIFNlY3JldHMgTWFuYWdlclxuICAgIG5ldyBjZGsuQ3VzdG9tUmVzb3VyY2UodGhpcywgJ0FkbWluQ3VzdG9tUmVzb3VyY2UnLCB7IHNlcnZpY2VUb2tlbjogaWRlbnRpdHlSZXNvdXJjZXMuYWRtaW5Qcm92aWRlci5zZXJ2aWNlVG9rZW4gfSk7XG5cbiAgICAvLyBSZWdpc3RlciBhbmQgZW5yb2xsIHVzZXJzLCBpZiBwcm92aWRlZFxuICAgIGlmIChwcm9wcy51c2VycykgdGhpcy51c2VycyA9IEFycmF5LmZyb20ocHJvcHMudXNlcnMuZW50cmllcygpKS5tYXAoZSA9PiBuZXcgdXNlci5IeXBlcmxlZGdlckZhYnJpY1VzZXIodGhpcywgYFVzZXIke2VbMF19YCwgZVsxXSkpO1xuICB9XG5cbn1cbiJdfQ==