@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.
- package/.jsii +4508 -0
- package/LICENSE +15 -0
- package/README.md +150 -0
- package/examples/python/hyperledger.py +90 -0
- package/examples/typescript/hyperledger.ts +106 -0
- package/lambdas/fabric/.eslintrc.js +17 -0
- package/lambdas/fabric/enroll-admin.js +33 -0
- package/lambdas/fabric/package.json +14 -0
- package/lambdas/fabric/register-user.js +62 -0
- package/lambdas/fabric/utilities.js +54 -0
- package/lib/client.d.ts +31 -0
- package/lib/client.js +40 -0
- package/lib/identity.d.ts +25 -0
- package/lib/identity.js +107 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +22 -0
- package/lib/network.d.ts +183 -0
- package/lib/network.js +225 -0
- package/lib/node.d.ts +88 -0
- package/lib/node.js +161 -0
- package/lib/user.d.ts +40 -0
- package/lib/user.js +56 -0
- package/lib/utilities.d.ts +12 -0
- package/lib/utilities.js +116 -0
- package/package.json +154 -0
package/lib/node.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as customresources from 'aws-cdk-lib/custom-resources';
|
|
2
|
+
import * as constructs from 'constructs';
|
|
3
|
+
import * as network from './network';
|
|
4
|
+
/**
|
|
5
|
+
* Supported instance types for Managed Blockchain nodes
|
|
6
|
+
*/
|
|
7
|
+
export declare enum InstanceType {
|
|
8
|
+
BURSTABLE3_SMALL = "bc.t3.small",
|
|
9
|
+
BURSTABLE3_MEDIUM = "bc.t3.medium",
|
|
10
|
+
BURSTABLE3_LARGE = "bc.t3.large",
|
|
11
|
+
BURSTABLE3_XLARGE = "bc.t3.xlarge",
|
|
12
|
+
STANDARD5_LARGE = "bc.m5.large",
|
|
13
|
+
STANDARD5_XLARGE = "bc.m5.xlarge",
|
|
14
|
+
STANDARD5_XLARGE2 = "bc.m5.2xlarge",
|
|
15
|
+
STANDARD5_XLARGE4 = "bc.m5.4xlarge",
|
|
16
|
+
COMPUTE5_LARGE = "bc.c5.large",
|
|
17
|
+
COMPUTE5_XLARGE = "bc.c5.xlarge",
|
|
18
|
+
COMPUTE5_XLARGE2 = "bc.c5.2xlarge",
|
|
19
|
+
COMPUTE5_XLARGE4 = "bc.c5.4xlarge"
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Valid instance types for starter networks
|
|
23
|
+
*/
|
|
24
|
+
export declare const STARTER_INSTANCE_TYPES: InstanceType[];
|
|
25
|
+
/**
|
|
26
|
+
* Construct properties for `HyperledgerFabricNode`
|
|
27
|
+
*/
|
|
28
|
+
export interface HyperledgerFabricNodeProps {
|
|
29
|
+
/**
|
|
30
|
+
* The Availability Zone in which the node will be created
|
|
31
|
+
* @default - The first AZ in the region
|
|
32
|
+
*/
|
|
33
|
+
readonly availabilityZone?: string;
|
|
34
|
+
/**
|
|
35
|
+
* The Amazon Managed Blockchain instance type for the node
|
|
36
|
+
* @default - BURSTABLE3_SMALL
|
|
37
|
+
*/
|
|
38
|
+
readonly instanceType?: InstanceType;
|
|
39
|
+
/**
|
|
40
|
+
* The configuration to enable or disable chaincode logging
|
|
41
|
+
* @default - true
|
|
42
|
+
*/
|
|
43
|
+
readonly enableChaincodeLogging?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The configuration to enable or disable node logging
|
|
46
|
+
* @default - true
|
|
47
|
+
*/
|
|
48
|
+
readonly enableNodeLogging?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a Hyperledger Fabric node on an Amazon Managed Blockchain network
|
|
52
|
+
*/
|
|
53
|
+
export declare class HyperledgerFabricNode extends constructs.Construct {
|
|
54
|
+
static constructNodes(scope: network.HyperledgerFabricNetwork, nodeProps?: Array<HyperledgerFabricNodeProps>): HyperledgerFabricNode[];
|
|
55
|
+
/**
|
|
56
|
+
* Managed Blockchain network identifier
|
|
57
|
+
*/
|
|
58
|
+
readonly networkId: string;
|
|
59
|
+
/**
|
|
60
|
+
* Managed Blockchain member identifier
|
|
61
|
+
*/
|
|
62
|
+
readonly memberId: string;
|
|
63
|
+
/**
|
|
64
|
+
* Managed Blockchain node identifier generated on construction
|
|
65
|
+
*/
|
|
66
|
+
readonly nodeId: string;
|
|
67
|
+
/**
|
|
68
|
+
* The Availability Zone in which the node exists
|
|
69
|
+
*/
|
|
70
|
+
readonly availabilityZone: string;
|
|
71
|
+
/**
|
|
72
|
+
* The Amazon Managed Blockchain instance type for the node
|
|
73
|
+
*/
|
|
74
|
+
readonly instanceType: InstanceType;
|
|
75
|
+
/**
|
|
76
|
+
* The configuration to enable or disable chaincode logging
|
|
77
|
+
*/
|
|
78
|
+
readonly enableChaincodeLogging: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* The configuration to enable or disable node logging
|
|
81
|
+
*/
|
|
82
|
+
readonly enableNodeLogging: boolean;
|
|
83
|
+
endpoint: string;
|
|
84
|
+
eventEndpoint: string;
|
|
85
|
+
constructor(scope: network.HyperledgerFabricNetwork, id: string, props?: HyperledgerFabricNodeProps);
|
|
86
|
+
configureLogging(sdkCallPolicy: customresources.AwsCustomResourcePolicy): void;
|
|
87
|
+
fetchData(dataSdkCallPolicy: customresources.AwsCustomResourcePolicy): void;
|
|
88
|
+
}
|
package/lib/node.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.HyperledgerFabricNode = exports.STARTER_INSTANCE_TYPES = exports.InstanceType = 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 customresources = require("aws-cdk-lib/custom-resources");
|
|
11
|
+
const constructs = require("constructs");
|
|
12
|
+
const network = require("./network");
|
|
13
|
+
const utilities = require("./utilities");
|
|
14
|
+
/**
|
|
15
|
+
* Supported instance types for Managed Blockchain nodes
|
|
16
|
+
*/
|
|
17
|
+
var InstanceType;
|
|
18
|
+
(function (InstanceType) {
|
|
19
|
+
InstanceType["BURSTABLE3_SMALL"] = "bc.t3.small";
|
|
20
|
+
InstanceType["BURSTABLE3_MEDIUM"] = "bc.t3.medium";
|
|
21
|
+
InstanceType["BURSTABLE3_LARGE"] = "bc.t3.large";
|
|
22
|
+
InstanceType["BURSTABLE3_XLARGE"] = "bc.t3.xlarge";
|
|
23
|
+
InstanceType["STANDARD5_LARGE"] = "bc.m5.large";
|
|
24
|
+
InstanceType["STANDARD5_XLARGE"] = "bc.m5.xlarge";
|
|
25
|
+
InstanceType["STANDARD5_XLARGE2"] = "bc.m5.2xlarge";
|
|
26
|
+
InstanceType["STANDARD5_XLARGE4"] = "bc.m5.4xlarge";
|
|
27
|
+
InstanceType["COMPUTE5_LARGE"] = "bc.c5.large";
|
|
28
|
+
InstanceType["COMPUTE5_XLARGE"] = "bc.c5.xlarge";
|
|
29
|
+
InstanceType["COMPUTE5_XLARGE2"] = "bc.c5.2xlarge";
|
|
30
|
+
InstanceType["COMPUTE5_XLARGE4"] = "bc.c5.4xlarge";
|
|
31
|
+
})(InstanceType = exports.InstanceType || (exports.InstanceType = {}));
|
|
32
|
+
/**
|
|
33
|
+
* Valid instance types for starter networks
|
|
34
|
+
*/
|
|
35
|
+
exports.STARTER_INSTANCE_TYPES = [
|
|
36
|
+
InstanceType.BURSTABLE3_SMALL,
|
|
37
|
+
InstanceType.BURSTABLE3_MEDIUM,
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Creates a Hyperledger Fabric node on an Amazon Managed Blockchain network
|
|
41
|
+
*/
|
|
42
|
+
class HyperledgerFabricNode extends constructs.Construct {
|
|
43
|
+
constructor(scope, id, props) {
|
|
44
|
+
super(scope, id);
|
|
45
|
+
// These cannot be readonly since they have to be set after construction
|
|
46
|
+
// due the race condition documented in https://github.com/aws/aws-cdk/issues/18237.
|
|
47
|
+
this.endpoint = '';
|
|
48
|
+
this.eventEndpoint = '';
|
|
49
|
+
// Collect metadata on the stack
|
|
50
|
+
const region = cdk.Stack.of(this).region;
|
|
51
|
+
// Populate instance variables from input properties, using defaults if values not provided
|
|
52
|
+
if (typeof props === 'undefined')
|
|
53
|
+
props = {};
|
|
54
|
+
this.availabilityZone = props.availabilityZone ?? `${region}a`;
|
|
55
|
+
this.instanceType = props.instanceType ?? InstanceType.BURSTABLE3_SMALL;
|
|
56
|
+
this.enableChaincodeLogging = props.enableChaincodeLogging ?? true;
|
|
57
|
+
this.enableNodeLogging = props.enableNodeLogging ?? true;
|
|
58
|
+
this.networkId = scope.networkId;
|
|
59
|
+
this.memberId = scope.memberId;
|
|
60
|
+
// Ensure the parameters captured above are valid, so we don't
|
|
61
|
+
// need to wait until deployment time to discover an error
|
|
62
|
+
utilities.validateRegion(region);
|
|
63
|
+
utilities.validateAvailabilityZone(region, this.availabilityZone);
|
|
64
|
+
if (scope.networkEdition === network.NetworkEdition.STARTER && !exports.STARTER_INSTANCE_TYPES.includes(this.instanceType)) {
|
|
65
|
+
const starterInstanceTypeList = exports.STARTER_INSTANCE_TYPES.join(', ');
|
|
66
|
+
throw new Error(`Instance type in a starter network must be one of the following: ${starterInstanceTypeList}.`);
|
|
67
|
+
}
|
|
68
|
+
// Build out the Cloudformation construct for the network/member
|
|
69
|
+
const node = new managedblockchain.CfnNode(this, 'Node', {
|
|
70
|
+
networkId: this.networkId,
|
|
71
|
+
memberId: this.memberId,
|
|
72
|
+
nodeConfiguration: {
|
|
73
|
+
availabilityZone: this.availabilityZone,
|
|
74
|
+
instanceType: this.instanceType,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
// Capture data included in the Cloudformation output in instance variables
|
|
78
|
+
this.nodeId = node.getAtt('NodeId').toString();
|
|
79
|
+
}
|
|
80
|
+
/*
|
|
81
|
+
* Build out a list of HyperledgerFabricNode constructs given a list of input property
|
|
82
|
+
* objects; additionally checks to ensure node count is supported given the network type
|
|
83
|
+
*/
|
|
84
|
+
static constructNodes(scope, nodeProps) {
|
|
85
|
+
// If no node configurations are provided, create one; the empty object
|
|
86
|
+
// will be populated with defaults when passed to the node constructor
|
|
87
|
+
if (typeof nodeProps === 'undefined')
|
|
88
|
+
nodeProps = [{}];
|
|
89
|
+
const starter = scope.networkEdition === network.NetworkEdition.STARTER;
|
|
90
|
+
if (starter && nodeProps.length > 2) {
|
|
91
|
+
throw new Error('A starter network can have at most 2 nodes per member.');
|
|
92
|
+
}
|
|
93
|
+
if (!starter && nodeProps.length > 3) {
|
|
94
|
+
throw new Error('A standard network can have at most 3 nodes per member.');
|
|
95
|
+
}
|
|
96
|
+
// Construct the node list, using an index value in the identifier
|
|
97
|
+
return Array.from(nodeProps.entries()).map(e => new HyperledgerFabricNode(scope, `Node${e[0]}`, e[1]));
|
|
98
|
+
}
|
|
99
|
+
/*
|
|
100
|
+
* Configure logging for the node via SDK call; this function
|
|
101
|
+
* should be merged back into the constructor once the race condition is solved
|
|
102
|
+
*/
|
|
103
|
+
configureLogging(sdkCallPolicy) {
|
|
104
|
+
// This call doesn't really need all the permissions its using in the
|
|
105
|
+
// provided policy, but since the policy must be constructed all at once
|
|
106
|
+
// this is the only way to do it effectively
|
|
107
|
+
const logPublishingConfiguration = {
|
|
108
|
+
Fabric: {
|
|
109
|
+
ChaincodeLogs: {
|
|
110
|
+
Cloudwatch: { Enabled: this.enableChaincodeLogging },
|
|
111
|
+
},
|
|
112
|
+
PeerLogs: {
|
|
113
|
+
Cloudwatch: { Enabled: this.enableNodeLogging },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
const configureNodeLogSdkCall = {
|
|
118
|
+
service: 'ManagedBlockchain',
|
|
119
|
+
action: 'updateNode',
|
|
120
|
+
parameters: {
|
|
121
|
+
NetworkId: this.networkId,
|
|
122
|
+
MemberId: this.memberId,
|
|
123
|
+
NodeId: this.nodeId,
|
|
124
|
+
LogPublishingConfiguration: logPublishingConfiguration,
|
|
125
|
+
},
|
|
126
|
+
physicalResourceId: customresources.PhysicalResourceId.of('Id'),
|
|
127
|
+
};
|
|
128
|
+
new customresources.AwsCustomResource(this, 'ConfigureNodeLogResource', {
|
|
129
|
+
policy: sdkCallPolicy,
|
|
130
|
+
onCreate: configureNodeLogSdkCall,
|
|
131
|
+
onUpdate: configureNodeLogSdkCall,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/*
|
|
135
|
+
* Populate the output properties that must be fetched via SDK call; this function
|
|
136
|
+
* should be merged back into the constructor once the race condition is solved
|
|
137
|
+
*/
|
|
138
|
+
fetchData(dataSdkCallPolicy) {
|
|
139
|
+
// This call doesn't really need all the permissions its using in the
|
|
140
|
+
// provided policy, but since the policy must be constructed all at once
|
|
141
|
+
// this is the only way to do it effectively
|
|
142
|
+
const nodeDataSdkCall = {
|
|
143
|
+
service: 'ManagedBlockchain',
|
|
144
|
+
action: 'getNode',
|
|
145
|
+
parameters: { NetworkId: this.networkId, MemberId: this.memberId, NodeId: this.nodeId },
|
|
146
|
+
physicalResourceId: customresources.PhysicalResourceId.of('Id'),
|
|
147
|
+
};
|
|
148
|
+
const nodeData = new customresources.AwsCustomResource(this, 'NodeDataResource', {
|
|
149
|
+
policy: dataSdkCallPolicy,
|
|
150
|
+
onCreate: nodeDataSdkCall,
|
|
151
|
+
onUpdate: nodeDataSdkCall,
|
|
152
|
+
});
|
|
153
|
+
// Grab items out of the above return values and stick them in output properties
|
|
154
|
+
this.endpoint = nodeData.getResponseField('Node.FrameworkAttributes.Fabric.PeerEndpoint');
|
|
155
|
+
this.eventEndpoint = nodeData.getResponseField('Node.FrameworkAttributes.Fabric.PeerEventEndpoint');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.HyperledgerFabricNode = HyperledgerFabricNode;
|
|
159
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
160
|
+
HyperledgerFabricNode[_a] = { fqn: "@cdklabs/cdk-hyperledger-fabric-network.HyperledgerFabricNode", version: "0.0.20" };
|
|
161
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLGlDQUFpQztBQUdqQyxtQ0FBbUM7QUFDbkMsdUVBQXVFO0FBQ3ZFLGdFQUFnRTtBQUNoRSx5Q0FBeUM7QUFFekMscUNBQXFDO0FBQ3JDLHlDQUF5QztBQUd6Qzs7R0FFRztBQUNILElBQVksWUFhWDtBQWJELFdBQVksWUFBWTtJQUN0QixnREFBZ0MsQ0FBQTtJQUNoQyxrREFBa0MsQ0FBQTtJQUNsQyxnREFBZ0MsQ0FBQTtJQUNoQyxrREFBa0MsQ0FBQTtJQUNsQywrQ0FBK0IsQ0FBQTtJQUMvQixpREFBaUMsQ0FBQTtJQUNqQyxtREFBbUMsQ0FBQTtJQUNuQyxtREFBbUMsQ0FBQTtJQUNuQyw4Q0FBOEIsQ0FBQTtJQUM5QixnREFBZ0MsQ0FBQTtJQUNoQyxrREFBa0MsQ0FBQTtJQUNsQyxrREFBa0MsQ0FBQTtBQUNwQyxDQUFDLEVBYlcsWUFBWSxHQUFaLG9CQUFZLEtBQVosb0JBQVksUUFhdkI7QUFHRDs7R0FFRztBQUNVLFFBQUEsc0JBQXNCLEdBQUc7SUFDcEMsWUFBWSxDQUFDLGdCQUFnQjtJQUM3QixZQUFZLENBQUMsaUJBQWlCO0NBQy9CLENBQUM7QUFtQ0Y7O0dBRUc7QUFDSCxNQUFhLHFCQUFzQixTQUFRLFVBQVUsQ0FBQyxTQUFTO0lBNkQ3RCxZQUFZLEtBQXVDLEVBQUUsRUFBVSxFQUFFLEtBQWtDO1FBRWpHLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFQbkIsd0VBQXdFO1FBQ3hFLG9GQUFvRjtRQUM3RSxhQUFRLEdBQVcsRUFBRSxDQUFDO1FBQ3RCLGtCQUFhLEdBQVcsRUFBRSxDQUFDO1FBTWhDLGdDQUFnQztRQUNoQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUM7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RSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ3ZGLGtCQUFrQixFQUFFLGVBQWUsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDO1NBQ2hFLENBQUM7UUFDRixNQUFNLFFBQVEsR0FBRyxJQUFJLGVBQWUsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsa0JBQWtCLEVBQUU7WUFDL0UsTUFBTSxFQUFFLGlCQUFpQjtZQUN6QixRQUFRLEVBQUUsZUFBZTtZQUN6QixRQUFRLEVBQUUsZUFBZTtTQUMxQixDQUFDLENBQUM7UUFFSCxnRkFBZ0Y7UUFDaEYsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsOENBQThDLENBQUMsQ0FBQztRQUMxRixJQUFJLENBQUMsYUFBYSxHQUFHLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxtREFBbUQsQ0FBQyxDQUFDO0lBRXRHLENBQUM7O0FBbktILHNEQXFLQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVC0wXG5cblxuaW1wb3J0ICogYXMgY2RrIGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIG1hbmFnZWRibG9ja2NoYWluIGZyb20gJ2F3cy1jZGstbGliL2F3cy1tYW5hZ2VkYmxvY2tjaGFpbic7XG5pbXBvcnQgKiBhcyBjdXN0b21yZXNvdXJjZXMgZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgKiBhcyBjb25zdHJ1Y3RzIGZyb20gJ2NvbnN0cnVjdHMnO1xuXG5pbXBvcnQgKiBhcyBuZXR3b3JrIGZyb20gJy4vbmV0d29yayc7XG5pbXBvcnQgKiBhcyB1dGlsaXRpZXMgZnJvbSAnLi91dGlsaXRpZXMnO1xuXG5cbi8qKlxuICogU3VwcG9ydGVkIGluc3RhbmNlIHR5cGVzIGZvciBNYW5hZ2VkIEJsb2NrY2hhaW4gbm9kZXNcbiAqL1xuZXhwb3J0IGVudW0gSW5zdGFuY2VUeXBlIHtcbiAgQlVSU1RBQkxFM19TTUFMTCA9ICdiYy50My5zbWFsbCcsXG4gIEJVUlNUQUJMRTNfTUVESVVNID0gJ2JjLnQzLm1lZGl1bScsXG4gIEJVUlNUQUJMRTNfTEFSR0UgPSAnYmMudDMubGFyZ2UnLFxuICBCVVJTVEFCTEUzX1hMQVJHRSA9ICdiYy50My54bGFyZ2UnLFxuICBTVEFOREFSRDVfTEFSR0UgPSAnYmMubTUubGFyZ2UnLFxuICBTVEFOREFSRDVfWExBUkdFID0gJ2JjLm01LnhsYXJnZScsXG4gIFNUQU5EQVJENV9YTEFSR0UyID0gJ2JjLm01LjJ4bGFyZ2UnLFxuICBTVEFOREFSRDVfWExBUkdFNCA9ICdiYy5tNS40eGxhcmdlJyxcbiAgQ09NUFVURTVfTEFSR0UgPSAnYmMuYzUubGFyZ2UnLFxuICBDT01QVVRFNV9YTEFSR0UgPSAnYmMuYzUueGxhcmdlJyxcbiAgQ09NUFVURTVfWExBUkdFMiA9ICdiYy5jNS4yeGxhcmdlJyxcbiAgQ09NUFVURTVfWExBUkdFNCA9ICdiYy5jNS40eGxhcmdlJyxcbn1cblxuXG4vKipcbiAqIFZhbGlkIGluc3RhbmNlIHR5cGVzIGZvciBzdGFydGVyIG5ldHdvcmtzXG4gKi9cbmV4cG9ydCBjb25zdCBTVEFSVEVSX0lOU1RBTkNFX1RZUEVTID0gW1xuICBJbnN0YW5jZVR5cGUuQlVSU1RBQkxFM19TTUFMTCxcbiAgSW5zdGFuY2VUeXBlLkJVUlNUQUJMRTNfTUVESVVNLFxuXTtcblxuXG4vKipcbiAqIENvbnN0cnVjdCBwcm9wZXJ0aWVzIGZvciBgSHlwZXJsZWRnZXJGYWJyaWNOb2RlYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEh5cGVybGVkZ2VyRmFicmljTm9kZVByb3BzIHtcblxuICAvKipcbiAgICogVGhlIEF2YWlsYWJpbGl0eSBab25lIGluIHdoaWNoIHRoZSBub2RlIHdpbGwgYmUgY3JlYXRlZFxuICAgKiBAZGVmYXVsdCAtIFRoZSBmaXJzdCBBWiBpbiB0aGUgcmVnaW9uXG4gICAqL1xuICByZWFkb25seSBhdmFpbGFiaWxpdHlab25lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgQW1hem9uIE1hbmFnZWQgQmxvY2tjaGFpbiBpbnN0YW5jZSB0eXBlIGZvciB0aGUgbm9kZVxuICAgKiBAZGVmYXVsdCAtIEJVUlNUQUJMRTNfU01BTExcbiAgICovXG4gIHJlYWRvbmx5IGluc3RhbmNlVHlwZT86IEluc3RhbmNlVHlwZTtcblxuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gdG8gZW5hYmxlIG9yIGRpc2FibGUgY2hhaW5jb2RlIGxvZ2dpbmdcbiAgICogQGRlZmF1bHQgLSB0cnVlXG4gICAqL1xuICByZWFkb25seSBlbmFibGVDaGFpbmNvZGVMb2dnaW5nPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gdG8gZW5hYmxlIG9yIGRpc2FibGUgbm9kZSBsb2dnaW5nXG4gICAqIEBkZWZhdWx0IC0gdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgZW5hYmxlTm9kZUxvZ2dpbmc/OiBib29sZWFuO1xuXG59XG5cblxuLyoqXG4gKiBDcmVhdGVzIGEgSHlwZXJsZWRnZXIgRmFicmljIG5vZGUgb24gYW4gQW1hem9uIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrXG4gKi9cbmV4cG9ydCBjbGFzcyBIeXBlcmxlZGdlckZhYnJpY05vZGUgZXh0ZW5kcyBjb25zdHJ1Y3RzLkNvbnN0cnVjdCB7XG5cbiAgLypcbiAgICogQnVpbGQgb3V0IGEgbGlzdCBvZiBIeXBlcmxlZGdlckZhYnJpY05vZGUgY29uc3RydWN0cyBnaXZlbiBhIGxpc3Qgb2YgaW5wdXQgcHJvcGVydHlcbiAgICogb2JqZWN0czsgYWRkaXRpb25hbGx5IGNoZWNrcyB0byBlbnN1cmUgbm9kZSBjb3VudCBpcyBzdXBwb3J0ZWQgZ2l2ZW4gdGhlIG5ldHdvcmsgdHlwZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25zdHJ1Y3ROb2RlcyhzY29wZTogbmV0d29yay5IeXBlcmxlZGdlckZhYnJpY05ldHdvcmssIG5vZGVQcm9wcz86IEFycmF5PEh5cGVybGVkZ2VyRmFicmljTm9kZVByb3BzPikge1xuICAgIC8vIElmIG5vIG5vZGUgY29uZmlndXJhdGlvbnMgYXJlIHByb3ZpZGVkLCBjcmVhdGUgb25lOyB0aGUgZW1wdHkgb2JqZWN0XG4gICAgLy8gd2lsbCBiZSBwb3B1bGF0ZWQgd2l0aCBkZWZhdWx0cyB3aGVuIHBhc3NlZCB0byB0aGUgbm9kZSBjb25zdHJ1Y3RvclxuICAgIGlmICh0eXBlb2Ygbm9kZVByb3BzID09PSAndW5kZWZpbmVkJykgbm9kZVByb3BzID0gW3t9XTtcbiAgICBjb25zdCBzdGFydGVyID0gc2NvcGUubmV0d29ya0VkaXRpb24gPT09IG5ldHdvcmsuTmV0d29ya0VkaXRpb24uU1RBUlRFUjtcbiAgICBpZiAoc3RhcnRlciAmJiBub2RlUHJvcHMubGVuZ3RoID4gMikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBIHN0YXJ0ZXIgbmV0d29yayBjYW4gaGF2ZSBhdCBtb3N0IDIgbm9kZXMgcGVyIG1lbWJlci4nKTtcbiAgICB9XG4gICAgaWYgKCFzdGFydGVyICYmIG5vZGVQcm9wcy5sZW5ndGggPiAzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Egc3RhbmRhcmQgbmV0d29yayBjYW4gaGF2ZSBhdCBtb3N0IDMgbm9kZXMgcGVyIG1lbWJlci4nKTtcbiAgICB9XG4gICAgLy8gQ29uc3RydWN0IHRoZSBub2RlIGxpc3QsIHVzaW5nIGFuIGluZGV4IHZhbHVlIGluIHRoZSBpZGVudGlmaWVyXG4gICAgcmV0dXJuIEFycmF5LmZyb20obm9kZVByb3BzLmVudHJpZXMoKSkubWFwKGUgPT4gbmV3IEh5cGVybGVkZ2VyRmFicmljTm9kZShzY29wZSwgYE5vZGUke2VbMF19YCwgZVsxXSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGlkZW50aWZpZXJcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXR3b3JrSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG1lbWJlciBpZGVudGlmaWVyXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbWVtYmVySWQ6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5vZGUgaWRlbnRpZmllciBnZW5lcmF0ZWQgb24gY29uc3RydWN0aW9uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbm9kZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBBdmFpbGFiaWxpdHkgWm9uZSBpbiB3aGljaCB0aGUgbm9kZSBleGlzdHNcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhdmFpbGFiaWxpdHlab25lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBBbWF6b24gTWFuYWdlZCBCbG9ja2NoYWluIGluc3RhbmNlIHR5cGUgZm9yIHRoZSBub2RlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaW5zdGFuY2VUeXBlOiBJbnN0YW5jZVR5cGU7XG5cbiAgLyoqXG4gICAqIFRoZSBjb25maWd1cmF0aW9uIHRvIGVuYWJsZSBvciBkaXNhYmxlIGNoYWluY29kZSBsb2dnaW5nXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZW5hYmxlQ2hhaW5jb2RlTG9nZ2luZzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gdG8gZW5hYmxlIG9yIGRpc2FibGUgbm9kZSBsb2dnaW5nXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZW5hYmxlTm9kZUxvZ2dpbmc6IGJvb2xlYW47XG5cbiAgLy8gVGhlc2UgY2Fubm90IGJlIHJlYWRvbmx5IHNpbmNlIHRoZXkgaGF2ZSB0byBiZSBzZXQgYWZ0ZXIgY29uc3RydWN0aW9uXG4gIC8vIGR1ZSB0aGUgcmFjZSBjb25kaXRpb24gZG9jdW1lbnRlZCBpbiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE4MjM3LlxuICBwdWJsaWMgZW5kcG9pbnQ6IHN0cmluZyA9ICcnO1xuICBwdWJsaWMgZXZlbnRFbmRwb2ludDogc3RyaW5nID0gJyc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IG5ldHdvcmsuSHlwZXJsZWRnZXJGYWJyaWNOZXR3b3JrLCBpZDogc3RyaW5nLCBwcm9wcz86IEh5cGVybGVkZ2VyRmFicmljTm9kZVByb3BzKSB7XG5cbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gQ29sbGVjdCBtZXRhZGF0YSBvbiB0aGUgc3RhY2tcbiAgICBjb25zdCByZWdpb24gPSBjZGsuU3RhY2sub2YodGhpcykucmVnaW9uO1xuXG4gICAgLy8gUG9wdWxhdGUgaW5zdGFuY2UgdmFyaWFibGVzIGZyb20gaW5wdXQgcHJvcGVydGllcywgdXNpbmcgZGVmYXVsdHMgaWYgdmFsdWVzIG5vdCBwcm92aWRlZFxuICAgIGlmICh0eXBlb2YgcHJvcHMgPT09ICd1bmRlZmluZWQnKSBwcm9wcyA9IHt9O1xuICAgIHRoaXMuYXZhaWxhYmlsaXR5Wm9uZSA9IHByb3BzLmF2YWlsYWJpbGl0eVpvbmUgPz8gYCR7cmVnaW9ufWFgO1xuICAgIHRoaXMuaW5zdGFuY2VUeXBlID0gcHJvcHMuaW5zdGFuY2VUeXBlID8/IEluc3RhbmNlVHlwZS5CVVJTVEFCTEUzX1NNQUxMO1xuICAgIHRoaXMuZW5hYmxlQ2hhaW5jb2RlTG9nZ2luZyA9IHByb3BzLmVuYWJsZUNoYWluY29kZUxvZ2dpbmcgPz8gdHJ1ZTtcbiAgICB0aGlzLmVuYWJsZU5vZGVMb2dnaW5nID0gcHJvcHMuZW5hYmxlTm9kZUxvZ2dpbmcgPz8gdHJ1ZTtcbiAgICB0aGlzLm5ldHdvcmtJZCA9IHNjb3BlLm5ldHdvcmtJZDtcbiAgICB0aGlzLm1lbWJlcklkID0gc2NvcGUubWVtYmVySWQ7XG5cbiAgICAvLyBFbnN1cmUgdGhlIHBhcmFtZXRlcnMgY2FwdHVyZWQgYWJvdmUgYXJlIHZhbGlkLCBzbyB3ZSBkb24ndFxuICAgIC8vIG5lZWQgdG8gd2FpdCB1bnRpbCBkZXBsb3ltZW50IHRpbWUgdG8gZGlzY292ZXIgYW4gZXJyb3JcbiAgICB1dGlsaXRpZXMudmFsaWRhdGVSZWdpb24ocmVnaW9uKTtcbiAgICB1dGlsaXRpZXMudmFsaWRhdGVBdmFpbGFiaWxpdHlab25lKHJlZ2lvbiwgdGhpcy5hdmFpbGFiaWxpdHlab25lKTtcbiAgICBpZiAoc2NvcGUubmV0d29ya0VkaXRpb24gPT09IG5ldHdvcmsuTmV0d29ya0VkaXRpb24uU1RBUlRFUiAmJiAhU1RBUlRFUl9JTlNUQU5DRV9UWVBFUy5pbmNsdWRlcyh0aGlzLmluc3RhbmNlVHlwZSkpIHtcbiAgICAgIGNvbnN0IHN0YXJ0ZXJJbnN0YW5jZVR5cGVMaXN0ID0gU1RBUlRFUl9JTlNUQU5DRV9UWVBFUy5qb2luKCcsICcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnN0YW5jZSB0eXBlIGluIGEgc3RhcnRlciBuZXR3b3JrIG11c3QgYmUgb25lIG9mIHRoZSBmb2xsb3dpbmc6ICR7c3RhcnRlckluc3RhbmNlVHlwZUxpc3R9LmApO1xuICAgIH1cblxuICAgIC8vIEJ1aWxkIG91dCB0aGUgQ2xvdWRmb3JtYXRpb24gY29uc3RydWN0IGZvciB0aGUgbmV0d29yay9tZW1iZXJcbiAgICBjb25zdCBub2RlID0gbmV3IG1hbmFnZWRibG9ja2NoYWluLkNmbk5vZGUodGhpcywgJ05vZGUnLCB7XG4gICAgICBuZXR3b3JrSWQ6IHRoaXMubmV0d29ya0lkLFxuICAgICAgbWVtYmVySWQ6IHRoaXMubWVtYmVySWQsXG4gICAgICBub2RlQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBhdmFpbGFiaWxpdHlab25lOiB0aGlzLmF2YWlsYWJpbGl0eVpvbmUsXG4gICAgICAgIGluc3RhbmNlVHlwZTogdGhpcy5pbnN0YW5jZVR5cGUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQ2FwdHVyZSBkYXRhIGluY2x1ZGVkIGluIHRoZSBDbG91ZGZvcm1hdGlvbiBvdXRwdXQgaW4gaW5zdGFuY2UgdmFyaWFibGVzXG4gICAgdGhpcy5ub2RlSWQgPSBub2RlLmdldEF0dCgnTm9kZUlkJykudG9TdHJpbmcoKTtcblxuICB9XG5cbiAgLypcbiAgICogQ29uZmlndXJlIGxvZ2dpbmcgZm9yIHRoZSBub2RlIHZpYSBTREsgY2FsbDsgdGhpcyBmdW5jdGlvblxuICAgKiBzaG91bGQgYmUgbWVyZ2VkIGJhY2sgaW50byB0aGUgY29uc3RydWN0b3Igb25jZSB0aGUgcmFjZSBjb25kaXRpb24gaXMgc29sdmVkXG4gICAqL1xuICBwdWJsaWMgY29uZmlndXJlTG9nZ2luZyhzZGtDYWxsUG9saWN5OiBjdXN0b21yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kpIHtcblxuICAgIC8vIFRoaXMgY2FsbCBkb2Vzbid0IHJlYWxseSBuZWVkIGFsbCB0aGUgcGVybWlzc2lvbnMgaXRzIHVzaW5nIGluIHRoZVxuICAgIC8vIHByb3ZpZGVkIHBvbGljeSwgYnV0IHNpbmNlIHRoZSBwb2xpY3kgbXVzdCBiZSBjb25zdHJ1Y3RlZCBhbGwgYXQgb25jZVxuICAgIC8vIHRoaXMgaXMgdGhlIG9ubHkgd2F5IHRvIGRvIGl0IGVmZmVjdGl2ZWx5XG4gICAgY29uc3QgbG9nUHVibGlzaGluZ0NvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBGYWJyaWM6IHtcbiAgICAgICAgQ2hhaW5jb2RlTG9nczoge1xuICAgICAgICAgIENsb3Vkd2F0Y2g6IHsgRW5hYmxlZDogdGhpcy5lbmFibGVDaGFpbmNvZGVMb2dnaW5nIH0sXG4gICAgICAgIH0sXG4gICAgICAgIFBlZXJMb2dzOiB7XG4gICAgICAgICAgQ2xvdWR3YXRjaDogeyBFbmFibGVkOiB0aGlzLmVuYWJsZU5vZGVMb2dnaW5nIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH07XG4gICAgY29uc3QgY29uZmlndXJlTm9kZUxvZ1Nka0NhbGwgPSB7XG4gICAgICBzZXJ2aWNlOiAnTWFuYWdlZEJsb2NrY2hhaW4nLFxuICAgICAgYWN0aW9uOiAndXBkYXRlTm9kZScsXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIE5ldHdvcmtJZDogdGhpcy5uZXR3b3JrSWQsXG4gICAgICAgIE1lbWJlcklkOiB0aGlzLm1lbWJlcklkLFxuICAgICAgICBOb2RlSWQ6IHRoaXMubm9kZUlkLFxuICAgICAgICBMb2dQdWJsaXNoaW5nQ29uZmlndXJhdGlvbjogbG9nUHVibGlzaGluZ0NvbmZpZ3VyYXRpb24sXG4gICAgICB9LFxuICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBjdXN0b21yZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKCdJZCcpLFxuICAgIH07XG4gICAgbmV3IGN1c3RvbXJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZSh0aGlzLCAnQ29uZmlndXJlTm9kZUxvZ1Jlc291cmNlJywge1xuICAgICAgcG9saWN5OiBzZGtDYWxsUG9saWN5LFxuICAgICAgb25DcmVhdGU6IGNvbmZpZ3VyZU5vZGVMb2dTZGtDYWxsLFxuICAgICAgb25VcGRhdGU6IGNvbmZpZ3VyZU5vZGVMb2dTZGtDYWxsLFxuICAgIH0pO1xuICB9XG5cbiAgLypcbiAgICogUG9wdWxhdGUgdGhlIG91dHB1dCBwcm9wZXJ0aWVzIHRoYXQgbXVzdCBiZSBmZXRjaGVkIHZpYSBTREsgY2FsbDsgdGhpcyBmdW5jdGlvblxuICAgKiBzaG91bGQgYmUgbWVyZ2VkIGJhY2sgaW50byB0aGUgY29uc3RydWN0b3Igb25jZSB0aGUgcmFjZSBjb25kaXRpb24gaXMgc29sdmVkXG4gICAqL1xuICBwdWJsaWMgZmV0Y2hEYXRhKGRhdGFTZGtDYWxsUG9saWN5OiBjdXN0b21yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kpIHtcblxuICAgIC8vIFRoaXMgY2FsbCBkb2Vzbid0IHJlYWxseSBuZWVkIGFsbCB0aGUgcGVybWlzc2lvbnMgaXRzIHVzaW5nIGluIHRoZVxuICAgIC8vIHByb3ZpZGVkIHBvbGljeSwgYnV0IHNpbmNlIHRoZSBwb2xpY3kgbXVzdCBiZSBjb25zdHJ1Y3RlZCBhbGwgYXQgb25jZVxuICAgIC8vIHRoaXMgaXMgdGhlIG9ubHkgd2F5IHRvIGRvIGl0IGVmZmVjdGl2ZWx5XG4gICAgY29uc3Qgbm9kZURhdGFTZGtDYWxsID0ge1xuICAgICAgc2VydmljZTogJ01hbmFnZWRCbG9ja2NoYWluJyxcbiAgICAgIGFjdGlvbjogJ2dldE5vZGUnLFxuICAgICAgcGFyYW1ldGVyczogeyBOZXR3b3JrSWQ6IHRoaXMubmV0d29ya0lkLCBNZW1iZXJJZDogdGhpcy5tZW1iZXJJZCwgTm9kZUlkOiB0aGlzLm5vZGVJZCB9LFxuICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBjdXN0b21yZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKCdJZCcpLFxuICAgIH07XG4gICAgY29uc3Qgbm9kZURhdGEgPSBuZXcgY3VzdG9tcmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlKHRoaXMsICdOb2RlRGF0YVJlc291cmNlJywge1xuICAgICAgcG9saWN5OiBkYXRhU2RrQ2FsbFBvbGljeSxcbiAgICAgIG9uQ3JlYXRlOiBub2RlRGF0YVNka0NhbGwsXG4gICAgICBvblVwZGF0ZTogbm9kZURhdGFTZGtDYWxsLFxuICAgIH0pO1xuXG4gICAgLy8gR3JhYiBpdGVtcyBvdXQgb2YgdGhlIGFib3ZlIHJldHVybiB2YWx1ZXMgYW5kIHN0aWNrIHRoZW0gaW4gb3V0cHV0IHByb3BlcnRpZXNcbiAgICB0aGlzLmVuZHBvaW50ID0gbm9kZURhdGEuZ2V0UmVzcG9uc2VGaWVsZCgnTm9kZS5GcmFtZXdvcmtBdHRyaWJ1dGVzLkZhYnJpYy5QZWVyRW5kcG9pbnQnKTtcbiAgICB0aGlzLmV2ZW50RW5kcG9pbnQgPSBub2RlRGF0YS5nZXRSZXNwb25zZUZpZWxkKCdOb2RlLkZyYW1ld29ya0F0dHJpYnV0ZXMuRmFicmljLlBlZXJFdmVudEVuZHBvaW50Jyk7XG5cbiAgfVxuXG59XG4iXX0=
|
package/lib/user.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
2
|
+
import * as constructs from 'constructs';
|
|
3
|
+
import * as network from './network';
|
|
4
|
+
/**
|
|
5
|
+
* Construct properties for `HyperledgerFabricUser`
|
|
6
|
+
*/
|
|
7
|
+
export interface HyperledgerFabricUserProps {
|
|
8
|
+
/**
|
|
9
|
+
* User's affiliation to the member.
|
|
10
|
+
* Should be hierarchical with member name as root(`MemberName.Dept1`).
|
|
11
|
+
*/
|
|
12
|
+
readonly affilitation: string;
|
|
13
|
+
/**
|
|
14
|
+
* User ID to register with CA
|
|
15
|
+
*/
|
|
16
|
+
readonly userId: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates custom resources to register and enroll users identities
|
|
20
|
+
* with the CA using the fabric-ca-client SDK
|
|
21
|
+
*/
|
|
22
|
+
export declare class HyperledgerFabricUser extends constructs.Construct {
|
|
23
|
+
/**
|
|
24
|
+
* User ID registered with CA
|
|
25
|
+
*/
|
|
26
|
+
readonly userId: string;
|
|
27
|
+
/**
|
|
28
|
+
* User's affiliation to the member
|
|
29
|
+
*/
|
|
30
|
+
readonly affiliation: string;
|
|
31
|
+
/**
|
|
32
|
+
* Secret for user signed certificate
|
|
33
|
+
*/
|
|
34
|
+
readonly userSignedCertSecret: secretsmanager.Secret;
|
|
35
|
+
/**
|
|
36
|
+
* Secret for user private key
|
|
37
|
+
*/
|
|
38
|
+
readonly userPrivateKeySecret: secretsmanager.Secret;
|
|
39
|
+
constructor(scope: network.HyperledgerFabricNetwork, id: string, props: HyperledgerFabricUserProps);
|
|
40
|
+
}
|
package/lib/user.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.HyperledgerFabricUser = 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 iam = require("aws-cdk-lib/aws-iam");
|
|
10
|
+
const secretsmanager = require("aws-cdk-lib/aws-secretsmanager");
|
|
11
|
+
const constructs = require("constructs");
|
|
12
|
+
const identity = require("./identity");
|
|
13
|
+
/**
|
|
14
|
+
* Creates custom resources to register and enroll users identities
|
|
15
|
+
* with the CA using the fabric-ca-client SDK
|
|
16
|
+
*/
|
|
17
|
+
class HyperledgerFabricUser extends constructs.Construct {
|
|
18
|
+
constructor(scope, id, props) {
|
|
19
|
+
super(scope, id);
|
|
20
|
+
// Populate instance variables from input properties
|
|
21
|
+
this.userId = props.userId;
|
|
22
|
+
this.affiliation = props.affilitation;
|
|
23
|
+
// Get the custom resources from Identity Resources class
|
|
24
|
+
const customResourceRole = identity.HyperledgerFabricIdentity.customRole;
|
|
25
|
+
const registerProvider = identity.HyperledgerFabricIdentity.userProvider;
|
|
26
|
+
// Ensure the user affiliation includes the member name
|
|
27
|
+
if (!this.affiliation.startsWith(scope.memberName))
|
|
28
|
+
throw new Error('User affiliation is invalid. Affiliation should start with Member name');
|
|
29
|
+
// The user credentials will be stored in these secrets
|
|
30
|
+
const userPasswordSecret = new secretsmanager.Secret(this, `${this.userId}-Password`);
|
|
31
|
+
this.userPrivateKeySecret = new secretsmanager.Secret(this, `${this.userId}-PrivateKey`);
|
|
32
|
+
this.userSignedCertSecret = new secretsmanager.Secret(this, `${this.userId}-SignedCert`);
|
|
33
|
+
// Add secrets arn to the custom role
|
|
34
|
+
customResourceRole.addToPolicy(new iam.PolicyStatement({
|
|
35
|
+
actions: ['secretsmanager:PutSecretValue'],
|
|
36
|
+
resources: [
|
|
37
|
+
userPasswordSecret.secretArn,
|
|
38
|
+
this.userPrivateKeySecret.secretArn,
|
|
39
|
+
this.userSignedCertSecret.secretArn,
|
|
40
|
+
],
|
|
41
|
+
}));
|
|
42
|
+
const userProp = {
|
|
43
|
+
userId: this.userId,
|
|
44
|
+
affiliation: this.affiliation,
|
|
45
|
+
passwordArn: userPasswordSecret.secretArn,
|
|
46
|
+
privateKeyArn: this.userPrivateKeySecret.secretArn,
|
|
47
|
+
signedCertArn: this.userSignedCertSecret.secretArn,
|
|
48
|
+
};
|
|
49
|
+
// Custom resource to enroll the admin identity using fabric client SDK
|
|
50
|
+
new cdk.CustomResource(this, `${this.userId}Resource`, { serviceToken: registerProvider.serviceToken, properties: userProp });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.HyperledgerFabricUser = HyperledgerFabricUser;
|
|
54
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
55
|
+
HyperledgerFabricUser[_a] = { fqn: "@cdklabs/cdk-hyperledger-fabric-network.HyperledgerFabricUser", version: "0.0.20" };
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy91c2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLGlDQUFpQztBQUVqQyxtQ0FBbUM7QUFDbkMsMkNBQTJDO0FBQzNDLGlFQUFpRTtBQUNqRSx5Q0FBeUM7QUFFekMsdUNBQXVDO0FBcUJ2Qzs7O0dBR0c7QUFDSCxNQUFhLHFCQUFzQixTQUFRLFVBQVUsQ0FBQyxTQUFTO0lBdUI3RCxZQUFZLEtBQXVDLEVBQUUsRUFBVSxFQUFFLEtBQWlDO1FBQ2hHLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsb0RBQW9EO1FBQ3BELElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUMzQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUM7UUFFdEMseURBQXlEO1FBQ3pELE1BQU0sa0JBQWtCLEdBQUcsUUFBUSxDQUFDLHlCQUF5QixDQUFDLFVBQVUsQ0FBQztRQUN6RSxNQUFNLGdCQUFnQixHQUFHLFFBQVEsQ0FBQyx5QkFBeUIsQ0FBQyxZQUFZLENBQUM7UUFFekUsdURBQXVEO1FBQ3ZELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx3RUFBd0UsQ0FBQyxDQUFDO1FBRTlJLHVEQUF1RDtRQUN2RCxNQUFNLGtCQUFrQixHQUFHLElBQUksY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxXQUFXLENBQUMsQ0FBQztRQUN0RixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLGFBQWEsQ0FBQyxDQUFDO1FBQ3pGLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sYUFBYSxDQUFDLENBQUM7UUFFekYscUNBQXFDO1FBQ3JDLGtCQUFrQixDQUFDLFdBQVcsQ0FBRSxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7WUFDdEQsT0FBTyxFQUFFLENBQUMsK0JBQStCLENBQUM7WUFDMUMsU0FBUyxFQUFFO2dCQUNULGtCQUFrQixDQUFDLFNBQVM7Z0JBQzVCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTO2dCQUNuQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUzthQUNwQztTQUNGLENBQUMsQ0FBQyxDQUFDO1FBRUosTUFBTSxRQUFRLEdBQUc7WUFDZixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxTQUFTO1lBQ3pDLGFBQWEsRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUztZQUNsRCxhQUFhLEVBQUUsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVM7U0FDbkQsQ0FBQztRQUVGLHVFQUF1RTtRQUN2RSxJQUFJLEdBQUcsQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sVUFBVSxFQUFFLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixDQUFDLFlBQVksRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUVoSSxDQUFDOztBQS9ESCxzREFpRUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVQtMFxuXG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgc2VjcmV0c21hbmFnZXIgZnJvbSAnYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyJztcbmltcG9ydCAqIGFzIGNvbnN0cnVjdHMgZnJvbSAnY29uc3RydWN0cyc7XG5cbmltcG9ydCAqIGFzIGlkZW50aXR5IGZyb20gJy4vaWRlbnRpdHknO1xuaW1wb3J0ICogYXMgbmV0d29yayBmcm9tICcuL25ldHdvcmsnO1xuXG4vKipcbiAqIENvbnN0cnVjdCBwcm9wZXJ0aWVzIGZvciBgSHlwZXJsZWRnZXJGYWJyaWNVc2VyYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEh5cGVybGVkZ2VyRmFicmljVXNlclByb3BzIHtcblxuICAvKipcbiAgICogVXNlcidzIGFmZmlsaWF0aW9uIHRvIHRoZSBtZW1iZXIuXG4gICAqIFNob3VsZCBiZSBoaWVyYXJjaGljYWwgd2l0aCBtZW1iZXIgbmFtZSBhcyByb290KGBNZW1iZXJOYW1lLkRlcHQxYCkuXG4gICAqL1xuICByZWFkb25seSBhZmZpbGl0YXRpb246IHN0cmluZztcblxuICAvKipcbiAgICogVXNlciBJRCB0byByZWdpc3RlciB3aXRoIENBXG4gICAqL1xuICByZWFkb25seSB1c2VySWQ6IHN0cmluZztcblxufVxuXG4vKipcbiAqIENyZWF0ZXMgY3VzdG9tIHJlc291cmNlcyB0byByZWdpc3RlciBhbmQgZW5yb2xsIHVzZXJzIGlkZW50aXRpZXNcbiAqIHdpdGggdGhlIENBIHVzaW5nIHRoZSBmYWJyaWMtY2EtY2xpZW50IFNES1xuICovXG5leHBvcnQgY2xhc3MgSHlwZXJsZWRnZXJGYWJyaWNVc2VyIGV4dGVuZHMgY29uc3RydWN0cy5Db25zdHJ1Y3Qge1xuXG4gIC8qKlxuICAgKiBVc2VyIElEIHJlZ2lzdGVyZWQgd2l0aCBDQVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHVzZXJJZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBVc2VyJ3MgYWZmaWxpYXRpb24gdG8gdGhlIG1lbWJlclxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFmZmlsaWF0aW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFNlY3JldCBmb3IgdXNlciBzaWduZWQgY2VydGlmaWNhdGVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB1c2VyU2lnbmVkQ2VydFNlY3JldDogc2VjcmV0c21hbmFnZXIuU2VjcmV0O1xuXG4gIC8qKlxuICAgKiBTZWNyZXQgZm9yIHVzZXIgcHJpdmF0ZSBrZXlcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB1c2VyUHJpdmF0ZUtleVNlY3JldDogc2VjcmV0c21hbmFnZXIuU2VjcmV0O1xuXG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IG5ldHdvcmsuSHlwZXJsZWRnZXJGYWJyaWNOZXR3b3JrLCBpZDogc3RyaW5nLCBwcm9wczogSHlwZXJsZWRnZXJGYWJyaWNVc2VyUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gUG9wdWxhdGUgaW5zdGFuY2UgdmFyaWFibGVzIGZyb20gaW5wdXQgcHJvcGVydGllc1xuICAgIHRoaXMudXNlcklkID0gcHJvcHMudXNlcklkO1xuICAgIHRoaXMuYWZmaWxpYXRpb24gPSBwcm9wcy5hZmZpbGl0YXRpb247XG5cbiAgICAvLyBHZXQgdGhlIGN1c3RvbSByZXNvdXJjZXMgZnJvbSBJZGVudGl0eSBSZXNvdXJjZXMgY2xhc3NcbiAgICBjb25zdCBjdXN0b21SZXNvdXJjZVJvbGUgPSBpZGVudGl0eS5IeXBlcmxlZGdlckZhYnJpY0lkZW50aXR5LmN1c3RvbVJvbGU7XG4gICAgY29uc3QgcmVnaXN0ZXJQcm92aWRlciA9IGlkZW50aXR5Lkh5cGVybGVkZ2VyRmFicmljSWRlbnRpdHkudXNlclByb3ZpZGVyO1xuXG4gICAgLy8gRW5zdXJlIHRoZSB1c2VyIGFmZmlsaWF0aW9uIGluY2x1ZGVzIHRoZSBtZW1iZXIgbmFtZVxuICAgIGlmICghdGhpcy5hZmZpbGlhdGlvbi5zdGFydHNXaXRoKHNjb3BlLm1lbWJlck5hbWUpKSB0aHJvdyBuZXcgRXJyb3IoJ1VzZXIgYWZmaWxpYXRpb24gaXMgaW52YWxpZC4gQWZmaWxpYXRpb24gc2hvdWxkIHN0YXJ0IHdpdGggTWVtYmVyIG5hbWUnKTtcblxuICAgIC8vIFRoZSB1c2VyIGNyZWRlbnRpYWxzIHdpbGwgYmUgc3RvcmVkIGluIHRoZXNlIHNlY3JldHNcbiAgICBjb25zdCB1c2VyUGFzc3dvcmRTZWNyZXQgPSBuZXcgc2VjcmV0c21hbmFnZXIuU2VjcmV0KHRoaXMsIGAke3RoaXMudXNlcklkfS1QYXNzd29yZGApO1xuICAgIHRoaXMudXNlclByaXZhdGVLZXlTZWNyZXQgPSBuZXcgc2VjcmV0c21hbmFnZXIuU2VjcmV0KHRoaXMsIGAke3RoaXMudXNlcklkfS1Qcml2YXRlS2V5YCk7XG4gICAgdGhpcy51c2VyU2lnbmVkQ2VydFNlY3JldCA9IG5ldyBzZWNyZXRzbWFuYWdlci5TZWNyZXQodGhpcywgYCR7dGhpcy51c2VySWR9LVNpZ25lZENlcnRgKTtcblxuICAgIC8vIEFkZCBzZWNyZXRzIGFybiB0byB0aGUgY3VzdG9tIHJvbGVcbiAgICBjdXN0b21SZXNvdXJjZVJvbGUuYWRkVG9Qb2xpY3koIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFsnc2VjcmV0c21hbmFnZXI6UHV0U2VjcmV0VmFsdWUnXSxcbiAgICAgIHJlc291cmNlczogW1xuICAgICAgICB1c2VyUGFzc3dvcmRTZWNyZXQuc2VjcmV0QXJuLFxuICAgICAgICB0aGlzLnVzZXJQcml2YXRlS2V5U2VjcmV0LnNlY3JldEFybixcbiAgICAgICAgdGhpcy51c2VyU2lnbmVkQ2VydFNlY3JldC5zZWNyZXRBcm4sXG4gICAgICBdLFxuICAgIH0pKTtcblxuICAgIGNvbnN0IHVzZXJQcm9wID0ge1xuICAgICAgdXNlcklkOiB0aGlzLnVzZXJJZCxcbiAgICAgIGFmZmlsaWF0aW9uOiB0aGlzLmFmZmlsaWF0aW9uLFxuICAgICAgcGFzc3dvcmRBcm46IHVzZXJQYXNzd29yZFNlY3JldC5zZWNyZXRBcm4sXG4gICAgICBwcml2YXRlS2V5QXJuOiB0aGlzLnVzZXJQcml2YXRlS2V5U2VjcmV0LnNlY3JldEFybixcbiAgICAgIHNpZ25lZENlcnRBcm46IHRoaXMudXNlclNpZ25lZENlcnRTZWNyZXQuc2VjcmV0QXJuLFxuICAgIH07XG5cbiAgICAvLyBDdXN0b20gcmVzb3VyY2UgdG8gZW5yb2xsIHRoZSBhZG1pbiBpZGVudGl0eSB1c2luZyBmYWJyaWMgY2xpZW50IFNES1xuICAgIG5ldyBjZGsuQ3VzdG9tUmVzb3VyY2UodGhpcywgYCR7dGhpcy51c2VySWR9UmVzb3VyY2VgLCB7IHNlcnZpY2VUb2tlbjogcmVnaXN0ZXJQcm92aWRlci5zZXJ2aWNlVG9rZW4sIHByb3BlcnRpZXM6IHVzZXJQcm9wIH0pO1xuXG4gIH1cblxufSJdfQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const SUPPORTED_REGIONS: string[];
|
|
2
|
+
export declare const SUPPORTED_AVAILABILITY_ZONES: Record<string, Array<string>>;
|
|
3
|
+
export declare const STARTING_PORT = 30001;
|
|
4
|
+
export declare const ENDING_PORT = 30004;
|
|
5
|
+
export declare function getTlsBucket(region: string): {
|
|
6
|
+
bucketName: string;
|
|
7
|
+
key: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function validateRegion(region: string): void;
|
|
10
|
+
export declare function validateAvailabilityZone(region: string, availabilityZone?: string): void;
|
|
11
|
+
export declare function validateInteger(value: number, min: number, max: number): boolean;
|
|
12
|
+
export declare function validateString(value: string, min: number, max: number, regexp?: RegExp | undefined): boolean;
|
package/lib/utilities.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
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.validateString = exports.validateInteger = exports.validateAvailabilityZone = exports.validateRegion = exports.getTlsBucket = exports.ENDING_PORT = exports.STARTING_PORT = exports.SUPPORTED_AVAILABILITY_ZONES = exports.SUPPORTED_REGIONS = void 0;
|
|
6
|
+
/*
|
|
7
|
+
* Regions where Managed Blockchain is supported, for details see
|
|
8
|
+
* https://aws.amazon.com/managed-blockchain/pricing/hyperledger/
|
|
9
|
+
*/
|
|
10
|
+
exports.SUPPORTED_REGIONS = [
|
|
11
|
+
'ap-northeast-1',
|
|
12
|
+
'ap-northeast-2',
|
|
13
|
+
'ap-southeast-1',
|
|
14
|
+
'eu-west-1',
|
|
15
|
+
'eu-west-2',
|
|
16
|
+
'us-east-1',
|
|
17
|
+
];
|
|
18
|
+
/*
|
|
19
|
+
* Map of supported regions to their availability zones
|
|
20
|
+
*/
|
|
21
|
+
exports.SUPPORTED_AVAILABILITY_ZONES = {
|
|
22
|
+
'ap-northeast-1': [
|
|
23
|
+
'ap-northeast-1a',
|
|
24
|
+
'ap-northeast-1b',
|
|
25
|
+
'ap-northeast-1c',
|
|
26
|
+
],
|
|
27
|
+
'ap-northeast-2': [
|
|
28
|
+
'ap-northeast-2a',
|
|
29
|
+
'ap-northeast-2b',
|
|
30
|
+
'ap-northeast-2c',
|
|
31
|
+
'ap-northeast-2d',
|
|
32
|
+
],
|
|
33
|
+
'ap-southeast-1': [
|
|
34
|
+
'ap-southeast-1a',
|
|
35
|
+
'ap-southeast-1b',
|
|
36
|
+
'ap-southeast-1c',
|
|
37
|
+
],
|
|
38
|
+
'eu-west-1': [
|
|
39
|
+
'eu-west-1a',
|
|
40
|
+
'eu-west-1b',
|
|
41
|
+
'eu-west-1c',
|
|
42
|
+
],
|
|
43
|
+
'eu-west-2': [
|
|
44
|
+
'eu-west-2a',
|
|
45
|
+
'eu-west-2b',
|
|
46
|
+
'eu-west-2c',
|
|
47
|
+
],
|
|
48
|
+
'us-east-1': [
|
|
49
|
+
'us-east-1a',
|
|
50
|
+
'us-east-1b',
|
|
51
|
+
'us-east-1c',
|
|
52
|
+
'us-east-1d',
|
|
53
|
+
'us-east-1e',
|
|
54
|
+
'us-east-1f',
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
/*
|
|
58
|
+
* Starting port of the Network port range
|
|
59
|
+
*/
|
|
60
|
+
exports.STARTING_PORT = 30001;
|
|
61
|
+
/*
|
|
62
|
+
* Ending port of the Network port range
|
|
63
|
+
*/
|
|
64
|
+
exports.ENDING_PORT = 30004;
|
|
65
|
+
/*
|
|
66
|
+
* Returns the S3 Bucket and key that contains the TLS cert file
|
|
67
|
+
*/
|
|
68
|
+
function getTlsBucket(region) {
|
|
69
|
+
return { bucketName: `${region}.managedblockchain`, key: 'etc/managedblockchain-tls-chain.pem' };
|
|
70
|
+
}
|
|
71
|
+
exports.getTlsBucket = getTlsBucket;
|
|
72
|
+
/*
|
|
73
|
+
* Throw an error if provided region is not in the supported list
|
|
74
|
+
*/
|
|
75
|
+
function validateRegion(region) {
|
|
76
|
+
if (!exports.SUPPORTED_REGIONS.includes(region)) {
|
|
77
|
+
const regionList = exports.SUPPORTED_REGIONS.join(', ');
|
|
78
|
+
throw new Error(`Managed Blockchain is only available in the following regions: ${regionList}.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.validateRegion = validateRegion;
|
|
82
|
+
/*
|
|
83
|
+
* Throw an error if provided availability is not in the supported list
|
|
84
|
+
*/
|
|
85
|
+
function validateAvailabilityZone(region, availabilityZone) {
|
|
86
|
+
const availabililtyZonesForRegion = exports.SUPPORTED_AVAILABILITY_ZONES[region];
|
|
87
|
+
if (typeof availabilityZone === 'undefined' || !availabililtyZonesForRegion.includes(availabilityZone)) {
|
|
88
|
+
const availabilityZoneList = availabililtyZonesForRegion.join(', ');
|
|
89
|
+
throw new Error(`Managed Blockchain in ${region} is only available in the following availability zones: ${availabilityZoneList}.`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.validateAvailabilityZone = validateAvailabilityZone;
|
|
93
|
+
/*
|
|
94
|
+
* Throw an error if provided number is not an integer, or not with the given range (inclusive)
|
|
95
|
+
*/
|
|
96
|
+
function validateInteger(value, min, max) {
|
|
97
|
+
if (!Number.isInteger(value))
|
|
98
|
+
return false;
|
|
99
|
+
if (value < min || value > max)
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
exports.validateInteger = validateInteger;
|
|
104
|
+
/*
|
|
105
|
+
* Throw an error if provided string has length with a given range (inclusive),
|
|
106
|
+
* and optionally matches a provided regular expression pattern
|
|
107
|
+
*/
|
|
108
|
+
function validateString(value, min, max, regexp) {
|
|
109
|
+
if (value.length < min || value.length > max)
|
|
110
|
+
return false;
|
|
111
|
+
if (typeof regexp !== 'undefined' && !value.match(regexp))
|
|
112
|
+
return false;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
exports.validateString = validateString;
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbGl0aWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3V0aWxpdGllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEscUVBQXFFO0FBQ3JFLGlDQUFpQzs7O0FBR2pDOzs7R0FHRztBQUNVLFFBQUEsaUJBQWlCLEdBQUc7SUFDL0IsZ0JBQWdCO0lBQ2hCLGdCQUFnQjtJQUNoQixnQkFBZ0I7SUFDaEIsV0FBVztJQUNYLFdBQVc7SUFDWCxXQUFXO0NBQ1osQ0FBQztBQUVGOztHQUVHO0FBQ1UsUUFBQSw0QkFBNEIsR0FBa0M7SUFDekUsZ0JBQWdCLEVBQUU7UUFDaEIsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixpQkFBaUI7S0FDbEI7SUFDRCxnQkFBZ0IsRUFBRTtRQUNoQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixpQkFBaUI7S0FDbEI7SUFDRCxnQkFBZ0IsRUFBRTtRQUNoQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGlCQUFpQjtLQUNsQjtJQUNELFdBQVcsRUFBRTtRQUNYLFlBQVk7UUFDWixZQUFZO1FBQ1osWUFBWTtLQUNiO0lBQ0QsV0FBVyxFQUFFO1FBQ1gsWUFBWTtRQUNaLFlBQVk7UUFDWixZQUFZO0tBQ2I7SUFDRCxXQUFXLEVBQUU7UUFDWCxZQUFZO1FBQ1osWUFBWTtRQUNaLFlBQVk7UUFDWixZQUFZO1FBQ1osWUFBWTtRQUNaLFlBQVk7S0FDYjtDQUNGLENBQUM7QUFFRjs7R0FFRztBQUNVLFFBQUEsYUFBYSxHQUFHLEtBQUssQ0FBQztBQUVuQzs7R0FFRztBQUNVLFFBQUEsV0FBVyxHQUFHLEtBQUssQ0FBQztBQUVqQzs7R0FFRztBQUNILFNBQWdCLFlBQVksQ0FBQyxNQUFjO0lBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsR0FBRyxNQUFNLG9CQUFvQixFQUFFLEdBQUcsRUFBRSxxQ0FBcUMsRUFBRSxDQUFDO0FBQ25HLENBQUM7QUFGRCxvQ0FFQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLE1BQWM7SUFDM0MsSUFBSSxDQUFDLHlCQUFpQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRTtRQUN2QyxNQUFNLFVBQVUsR0FBRyx5QkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxrRUFBa0UsVUFBVSxHQUFHLENBQUMsQ0FBQztLQUNsRztBQUNILENBQUM7QUFMRCx3Q0FLQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0Isd0JBQXdCLENBQUMsTUFBYyxFQUFFLGdCQUF5QjtJQUNoRixNQUFNLDJCQUEyQixHQUFHLG9DQUE0QixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pFLElBQUksT0FBTyxnQkFBZ0IsS0FBSyxXQUFXLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtRQUN0RyxNQUFNLG9CQUFvQixHQUFHLDJCQUEyQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRSxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixNQUFNLDJEQUEyRCxvQkFBb0IsR0FBRyxDQUFDLENBQUM7S0FDcEk7QUFDSCxDQUFDO0FBTkQsNERBTUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxLQUFhLEVBQUUsR0FBVyxFQUFFLEdBQVc7SUFDckUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDM0MsSUFBSSxLQUFLLEdBQUcsR0FBRyxJQUFJLEtBQUssR0FBRyxHQUFHO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDN0MsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBSkQsMENBSUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixjQUFjLENBQUMsS0FBYSxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsTUFBMkI7SUFDakcsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUc7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUMzRCxJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDeEUsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBSkQsd0NBSUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVQtMFxuXG5cbi8qXG4gKiBSZWdpb25zIHdoZXJlIE1hbmFnZWQgQmxvY2tjaGFpbiBpcyBzdXBwb3J0ZWQsIGZvciBkZXRhaWxzIHNlZVxuICogaHR0cHM6Ly9hd3MuYW1hem9uLmNvbS9tYW5hZ2VkLWJsb2NrY2hhaW4vcHJpY2luZy9oeXBlcmxlZGdlci9cbiAqL1xuZXhwb3J0IGNvbnN0IFNVUFBPUlRFRF9SRUdJT05TID0gW1xuICAnYXAtbm9ydGhlYXN0LTEnLFxuICAnYXAtbm9ydGhlYXN0LTInLFxuICAnYXAtc291dGhlYXN0LTEnLFxuICAnZXUtd2VzdC0xJyxcbiAgJ2V1LXdlc3QtMicsXG4gICd1cy1lYXN0LTEnLFxuXTtcblxuLypcbiAqIE1hcCBvZiBzdXBwb3J0ZWQgcmVnaW9ucyB0byB0aGVpciBhdmFpbGFiaWxpdHkgem9uZXNcbiAqL1xuZXhwb3J0IGNvbnN0IFNVUFBPUlRFRF9BVkFJTEFCSUxJVFlfWk9ORVM6IFJlY29yZDxzdHJpbmcsIEFycmF5PHN0cmluZz4+ID0ge1xuICAnYXAtbm9ydGhlYXN0LTEnOiBbXG4gICAgJ2FwLW5vcnRoZWFzdC0xYScsXG4gICAgJ2FwLW5vcnRoZWFzdC0xYicsXG4gICAgJ2FwLW5vcnRoZWFzdC0xYycsXG4gIF0sXG4gICdhcC1ub3J0aGVhc3QtMic6IFtcbiAgICAnYXAtbm9ydGhlYXN0LTJhJyxcbiAgICAnYXAtbm9ydGhlYXN0LTJiJyxcbiAgICAnYXAtbm9ydGhlYXN0LTJjJyxcbiAgICAnYXAtbm9ydGhlYXN0LTJkJyxcbiAgXSxcbiAgJ2FwLXNvdXRoZWFzdC0xJzogW1xuICAgICdhcC1zb3V0aGVhc3QtMWEnLFxuICAgICdhcC1zb3V0aGVhc3QtMWInLFxuICAgICdhcC1zb3V0aGVhc3QtMWMnLFxuICBdLFxuICAnZXUtd2VzdC0xJzogW1xuICAgICdldS13ZXN0LTFhJyxcbiAgICAnZXUtd2VzdC0xYicsXG4gICAgJ2V1LXdlc3QtMWMnLFxuICBdLFxuICAnZXUtd2VzdC0yJzogW1xuICAgICdldS13ZXN0LTJhJyxcbiAgICAnZXUtd2VzdC0yYicsXG4gICAgJ2V1LXdlc3QtMmMnLFxuICBdLFxuICAndXMtZWFzdC0xJzogW1xuICAgICd1cy1lYXN0LTFhJyxcbiAgICAndXMtZWFzdC0xYicsXG4gICAgJ3VzLWVhc3QtMWMnLFxuICAgICd1cy1lYXN0LTFkJyxcbiAgICAndXMtZWFzdC0xZScsXG4gICAgJ3VzLWVhc3QtMWYnLFxuICBdLFxufTtcblxuLypcbiAqIFN0YXJ0aW5nIHBvcnQgb2YgdGhlIE5ldHdvcmsgcG9ydCByYW5nZVxuICovXG5leHBvcnQgY29uc3QgU1RBUlRJTkdfUE9SVCA9IDMwMDAxO1xuXG4vKlxuICogRW5kaW5nIHBvcnQgb2YgdGhlIE5ldHdvcmsgcG9ydCByYW5nZVxuICovXG5leHBvcnQgY29uc3QgRU5ESU5HX1BPUlQgPSAzMDAwNDtcblxuLypcbiAqIFJldHVybnMgdGhlIFMzIEJ1Y2tldCBhbmQga2V5IHRoYXQgY29udGFpbnMgdGhlIFRMUyBjZXJ0IGZpbGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRsc0J1Y2tldChyZWdpb246IHN0cmluZykge1xuICByZXR1cm4geyBidWNrZXROYW1lOiBgJHtyZWdpb259Lm1hbmFnZWRibG9ja2NoYWluYCwga2V5OiAnZXRjL21hbmFnZWRibG9ja2NoYWluLXRscy1jaGFpbi5wZW0nIH07XG59XG5cbi8qXG4gKiBUaHJvdyBhbiBlcnJvciBpZiBwcm92aWRlZCByZWdpb24gaXMgbm90IGluIHRoZSBzdXBwb3J0ZWQgbGlzdFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVSZWdpb24ocmVnaW9uOiBzdHJpbmcpIHtcbiAgaWYgKCFTVVBQT1JURURfUkVHSU9OUy5pbmNsdWRlcyhyZWdpb24pKSB7XG4gICAgY29uc3QgcmVnaW9uTGlzdCA9IFNVUFBPUlRFRF9SRUdJT05TLmpvaW4oJywgJyk7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBNYW5hZ2VkIEJsb2NrY2hhaW4gaXMgb25seSBhdmFpbGFibGUgaW4gdGhlIGZvbGxvd2luZyByZWdpb25zOiAke3JlZ2lvbkxpc3R9LmApO1xuICB9XG59XG5cbi8qXG4gKiBUaHJvdyBhbiBlcnJvciBpZiBwcm92aWRlZCBhdmFpbGFiaWxpdHkgaXMgbm90IGluIHRoZSBzdXBwb3J0ZWQgbGlzdFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVBdmFpbGFiaWxpdHlab25lKHJlZ2lvbjogc3RyaW5nLCBhdmFpbGFiaWxpdHlab25lPzogc3RyaW5nKSB7XG4gIGNvbnN0IGF2YWlsYWJpbGlsdHlab25lc0ZvclJlZ2lvbiA9IFNVUFBPUlRFRF9BVkFJTEFCSUxJVFlfWk9ORVNbcmVnaW9uXTtcbiAgaWYgKHR5cGVvZiBhdmFpbGFiaWxpdHlab25lID09PSAndW5kZWZpbmVkJyB8fCAhYXZhaWxhYmlsaWx0eVpvbmVzRm9yUmVnaW9uLmluY2x1ZGVzKGF2YWlsYWJpbGl0eVpvbmUpKSB7XG4gICAgY29uc3QgYXZhaWxhYmlsaXR5Wm9uZUxpc3QgPSBhdmFpbGFiaWxpbHR5Wm9uZXNGb3JSZWdpb24uam9pbignLCAnKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYE1hbmFnZWQgQmxvY2tjaGFpbiBpbiAke3JlZ2lvbn0gaXMgb25seSBhdmFpbGFibGUgaW4gdGhlIGZvbGxvd2luZyBhdmFpbGFiaWxpdHkgem9uZXM6ICR7YXZhaWxhYmlsaXR5Wm9uZUxpc3R9LmApO1xuICB9XG59XG5cbi8qXG4gKiBUaHJvdyBhbiBlcnJvciBpZiBwcm92aWRlZCBudW1iZXIgaXMgbm90IGFuIGludGVnZXIsIG9yIG5vdCB3aXRoIHRoZSBnaXZlbiByYW5nZSAoaW5jbHVzaXZlKVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVJbnRlZ2VyKHZhbHVlOiBudW1iZXIsIG1pbjogbnVtYmVyLCBtYXg6IG51bWJlcikge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIodmFsdWUpKSByZXR1cm4gZmFsc2U7XG4gIGlmICh2YWx1ZSA8IG1pbiB8fCB2YWx1ZSA+IG1heCkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLypcbiAqIFRocm93IGFuIGVycm9yIGlmIHByb3ZpZGVkIHN0cmluZyBoYXMgbGVuZ3RoIHdpdGggYSBnaXZlbiByYW5nZSAoaW5jbHVzaXZlKSxcbiAqIGFuZCBvcHRpb25hbGx5IG1hdGNoZXMgYSBwcm92aWRlZCByZWd1bGFyIGV4cHJlc3Npb24gcGF0dGVyblxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVTdHJpbmcodmFsdWU6IHN0cmluZywgbWluOiBudW1iZXIsIG1heDogbnVtYmVyLCByZWdleHA/OiBSZWdFeHAgfCB1bmRlZmluZWQpIHtcbiAgaWYgKHZhbHVlLmxlbmd0aCA8IG1pbiB8fCB2YWx1ZS5sZW5ndGggPiBtYXgpIHJldHVybiBmYWxzZTtcbiAgaWYgKHR5cGVvZiByZWdleHAgIT09ICd1bmRlZmluZWQnICYmICF2YWx1ZS5tYXRjaChyZWdleHApKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0cnVlO1xufVxuIl19
|