@aws-solutions-constructs/aws-cloudfront-oai-s3 2.79.0
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 +4403 -0
- package/README.md +109 -0
- package/architecture.png +0 -0
- package/integ.config.json +7 -0
- package/lib/index.d.ts +118 -0
- package/lib/index.js +106 -0
- package/package.json +95 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.d.ts +13 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js +56 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.assets.json +32 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.template.json +1061 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/cftoais3bucketencryptedwithmanagedkeyprovidedasexistingbucketIntegDefaultTestDeployAssert105E804F.assets.json +19 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/cftoais3bucketencryptedwithmanagedkeyprovidedasexistingbucketIntegDefaultTestDeployAssert105E804F.template.json +36 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/manifest.json +215 -0
- package/test/integ.cftoais3-bucket-encrypted-with-managed-key-provided-as-existingbucket.js.snapshot/tree.json +1105 -0
- package/test/integ.cftoais3-custom-headers.d.ts +13 -0
- package/test/integ.cftoais3-custom-headers.js +71 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/cftoais3-custom-headers.assets.json +32 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/cftoais3-custom-headers.template.json +1116 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/cftoais3customheadersIntegDefaultTestDeployAssert5AA11BA9.assets.json +19 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/cftoais3customheadersIntegDefaultTestDeployAssert5AA11BA9.template.json +36 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/manifest.json +227 -0
- package/test/integ.cftoais3-custom-headers.js.snapshot/tree.json +1196 -0
- package/test/integ.cftoais3-custom-originPath.d.ts +13 -0
- package/test/integ.cftoais3-custom-originPath.js +48 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/cftoais3-custom-originPath.assets.json +32 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/cftoais3-custom-originPath.template.json +1085 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/cftoais3customoriginPathIntegDefaultTestDeployAssert1C351914.assets.json +19 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/cftoais3customoriginPathIntegDefaultTestDeployAssert1C351914.template.json +36 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/manifest.json +221 -0
- package/test/integ.cftoais3-custom-originPath.js.snapshot/tree.json +1147 -0
- package/test/integ.cftoais3-customLoggingBuckets.d.ts +13 -0
- package/test/integ.cftoais3-customLoggingBuckets.js +64 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/cftoais3-customLoggingBuckets.assets.json +32 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/cftoais3-customLoggingBuckets.template.json +1109 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/cftoais3customLoggingBucketsIntegDefaultTestDeployAssert8F33EF2A.assets.json +19 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/cftoais3customLoggingBucketsIntegDefaultTestDeployAssert8F33EF2A.template.json +36 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/manifest.json +221 -0
- package/test/integ.cftoais3-customLoggingBuckets.js.snapshot/tree.json +1172 -0
- package/test/integ.cftoais3-existing-bucket.d.ts +13 -0
- package/test/integ.cftoais3-existing-bucket.js +59 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/cftoais3-existing-bucket.assets.json +32 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/cftoais3-existing-bucket.template.json +1131 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/cftoais3existingbucketIntegDefaultTestDeployAssertB7627F26.assets.json +19 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/cftoais3existingbucketIntegDefaultTestDeployAssertB7627F26.template.json +36 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/manifest.json +233 -0
- package/test/integ.cftoais3-existing-bucket.js.snapshot/tree.json +1240 -0
- package/test/integ.cftoais3-no-arguments.d.ts +13 -0
- package/test/integ.cftoais3-no-arguments.js +53 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/cftoais3-no-arguments.assets.json +32 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/cftoais3-no-arguments.template.json +1094 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/cftoais3noargumentsIntegDefaultTestDeployAssert5CF03E3D.assets.json +19 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/cftoais3noargumentsIntegDefaultTestDeployAssert5CF03E3D.template.json +36 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/manifest.json +356 -0
- package/test/integ.cftoais3-no-arguments.js.snapshot/tree.json +1146 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.d.ts +13 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js +60 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/cftoais3-no-cloudfront-s3-access-logs.assets.json +32 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/cftoais3-no-cloudfront-s3-access-logs.template.json +743 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/cftoais3nocloudfronts3accesslogsIntegDefaultTestDeployAssert6D810275.assets.json +19 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/cftoais3nocloudfronts3accesslogsIntegDefaultTestDeployAssert6D810275.template.json +36 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/manifest.json +185 -0
- package/test/integ.cftoais3-no-cloudfront-s3-access-logs.js.snapshot/tree.json +726 -0
- package/test/integ.cftoais3-no-logging.d.ts +13 -0
- package/test/integ.cftoais3-no-logging.js +56 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/cftoais3-no-logging.assets.json +32 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/cftoais3-no-logging.template.json +576 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/cftoais3nologgingIntegDefaultTestDeployAssertCED06EE4.assets.json +19 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/cftoais3nologgingIntegDefaultTestDeployAssertCED06EE4.template.json +36 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/manifest.json +167 -0
- package/test/integ.cftoais3-no-logging.js.snapshot/tree.json +542 -0
- package/test/integ.cftoais3-no-security-headers.d.ts +13 -0
- package/test/integ.cftoais3-no-security-headers.js +50 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6/index.js +1 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/cdk.out +1 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/cftoais3-no-security-headers.assets.json +32 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/cftoais3-no-security-headers.template.json +1061 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/cftoais3nosecurityheadersIntegDefaultTestDeployAssertAB4B2F28.assets.json +19 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/cftoais3nosecurityheadersIntegDefaultTestDeployAssertAB4B2F28.template.json +36 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/integ.json +12 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/manifest.json +215 -0
- package/test/integ.cftoais3-no-security-headers.js.snapshot/tree.json +1105 -0
- package/test/test.cloudfront-oai-s3.test.d.ts +13 -0
- package/test/test.cloudfront-oai-s3.test.js +702 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
|
|
6
|
+
* with the License. A copy of the License is located at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
|
|
11
|
+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
|
|
12
|
+
* and limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const assertions_1 = require("aws-cdk-lib/assertions");
|
|
16
|
+
const s3 = require("aws-cdk-lib/aws-s3");
|
|
17
|
+
const cdk = require("aws-cdk-lib");
|
|
18
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
19
|
+
const lib_1 = require("../lib");
|
|
20
|
+
const acm = require("aws-cdk-lib/aws-certificatemanager");
|
|
21
|
+
const defaults = require("@aws-solutions-constructs/core");
|
|
22
|
+
const aws_kms_1 = require("aws-cdk-lib/aws-kms");
|
|
23
|
+
function deploy(stack, props) {
|
|
24
|
+
return new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
25
|
+
bucketProps: {
|
|
26
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
27
|
+
},
|
|
28
|
+
...props
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
test('construct defaults set properties correctly', () => {
|
|
32
|
+
const stack = new cdk.Stack();
|
|
33
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {});
|
|
34
|
+
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
35
|
+
expect(construct.cloudFrontFunction).toBeDefined();
|
|
36
|
+
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
37
|
+
expect(construct.s3Bucket).toBeDefined();
|
|
38
|
+
expect(construct.s3LoggingBucket).toBeDefined();
|
|
39
|
+
expect(construct.s3BucketInterface).toBeDefined();
|
|
40
|
+
expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
|
|
41
|
+
});
|
|
42
|
+
test('check s3Bucket default encryption', () => {
|
|
43
|
+
const stack = new cdk.Stack();
|
|
44
|
+
deploy(stack);
|
|
45
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
46
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
47
|
+
BucketEncryption: {
|
|
48
|
+
ServerSideEncryptionConfiguration: [{
|
|
49
|
+
ServerSideEncryptionByDefault: {
|
|
50
|
+
SSEAlgorithm: "AES256"
|
|
51
|
+
}
|
|
52
|
+
}]
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
test('check that an OAI is created', () => {
|
|
57
|
+
const stack = new cdk.Stack();
|
|
58
|
+
deploy(stack);
|
|
59
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
60
|
+
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
61
|
+
DistributionConfig: {
|
|
62
|
+
Origins: [
|
|
63
|
+
{
|
|
64
|
+
S3OriginConfig: {
|
|
65
|
+
OriginAccessIdentity: assertions_1.Match.anyValue()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
test('confirm NO OAC is created', () => {
|
|
73
|
+
const stack = new cdk.Stack();
|
|
74
|
+
deploy(stack);
|
|
75
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
76
|
+
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
|
|
77
|
+
DistributionConfig: {
|
|
78
|
+
Origins: [
|
|
79
|
+
{
|
|
80
|
+
OriginAccessControlId: assertions_1.Match.anyValue(),
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}, 0);
|
|
85
|
+
});
|
|
86
|
+
test('check s3Bucket public access block configuration', () => {
|
|
87
|
+
const stack = new cdk.Stack();
|
|
88
|
+
deploy(stack);
|
|
89
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
90
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
91
|
+
PublicAccessBlockConfiguration: {
|
|
92
|
+
BlockPublicAcls: true,
|
|
93
|
+
BlockPublicPolicy: true,
|
|
94
|
+
IgnorePublicAcls: true,
|
|
95
|
+
RestrictPublicBuckets: true
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
test('test s3Bucket override publicAccessBlockConfiguration', () => {
|
|
100
|
+
const stack = new cdk.Stack();
|
|
101
|
+
const props = {
|
|
102
|
+
bucketProps: {
|
|
103
|
+
blockPublicAccess: {
|
|
104
|
+
blockPublicAcls: false,
|
|
105
|
+
blockPublicPolicy: true,
|
|
106
|
+
ignorePublicAcls: false,
|
|
107
|
+
restrictPublicBuckets: true
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
112
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
113
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
114
|
+
PublicAccessBlockConfiguration: {
|
|
115
|
+
BlockPublicAcls: false,
|
|
116
|
+
BlockPublicPolicy: true,
|
|
117
|
+
IgnorePublicAcls: false,
|
|
118
|
+
RestrictPublicBuckets: true
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
test('check existing bucket', () => {
|
|
123
|
+
const bucketName = "my-bucket";
|
|
124
|
+
const stack = new cdk.Stack();
|
|
125
|
+
const existingBucket = new s3.Bucket(stack, bucketName, {
|
|
126
|
+
bucketName: 'my-bucket'
|
|
127
|
+
});
|
|
128
|
+
const props = {
|
|
129
|
+
existingBucketObj: existingBucket
|
|
130
|
+
};
|
|
131
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
132
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
133
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
134
|
+
BucketName: bucketName
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
test('check properties', () => {
|
|
138
|
+
const stack = new cdk.Stack();
|
|
139
|
+
const construct = deploy(stack);
|
|
140
|
+
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
141
|
+
expect(construct.s3Bucket).toBeDefined();
|
|
142
|
+
});
|
|
143
|
+
test("Confirm CheckS3Props is called", () => {
|
|
144
|
+
// Stack
|
|
145
|
+
const stack = new cdk.Stack();
|
|
146
|
+
const testBucket = new s3.Bucket(stack, 'test-bucket', {});
|
|
147
|
+
const app = () => {
|
|
148
|
+
// Helper declaration
|
|
149
|
+
new lib_1.CloudFrontToOaiToS3(stack, "bad-s3-args", {
|
|
150
|
+
existingBucketObj: testBucket,
|
|
151
|
+
bucketProps: {
|
|
152
|
+
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
// Assertion
|
|
157
|
+
expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n');
|
|
158
|
+
});
|
|
159
|
+
test("Test existingBucketObj", () => {
|
|
160
|
+
// Stack
|
|
161
|
+
const stack = new cdk.Stack();
|
|
162
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
163
|
+
existingBucketObj: s3.Bucket.fromBucketName(stack, 'mybucket', 'mybucket')
|
|
164
|
+
});
|
|
165
|
+
// Assertion
|
|
166
|
+
expect(construct.cloudFrontWebDistribution).toBeDefined();
|
|
167
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
168
|
+
template.resourceCountIs("AWS::S3::Bucket", 2);
|
|
169
|
+
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
170
|
+
DistributionConfig: {
|
|
171
|
+
Origins: [
|
|
172
|
+
{
|
|
173
|
+
DomainName: {
|
|
174
|
+
"Fn::Join": [
|
|
175
|
+
"",
|
|
176
|
+
[
|
|
177
|
+
"mybucket.s3.",
|
|
178
|
+
{
|
|
179
|
+
Ref: "AWS::Region"
|
|
180
|
+
},
|
|
181
|
+
".",
|
|
182
|
+
{
|
|
183
|
+
Ref: "AWS::URLSuffix"
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
Id: "existingIBucketCloudFrontDistributionOrigin1D5849125",
|
|
189
|
+
S3OriginConfig: {
|
|
190
|
+
OriginAccessIdentity: assertions_1.Match.anyValue()
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
test('test cloudfront with custom domain names', () => {
|
|
198
|
+
const stack = new cdk.Stack();
|
|
199
|
+
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:${Aws.PARTITION}:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012');
|
|
200
|
+
const props = {
|
|
201
|
+
cloudFrontDistributionProps: {
|
|
202
|
+
domainNames: ['mydomains'],
|
|
203
|
+
certificate
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', props);
|
|
207
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
208
|
+
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
209
|
+
DistributionConfig: {
|
|
210
|
+
Aliases: [
|
|
211
|
+
"mydomains"
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
test("Test that a CMK on the bucket throws an error", () => {
|
|
217
|
+
// Stack
|
|
218
|
+
const stack = new cdk.Stack();
|
|
219
|
+
const existingBucket = defaults.CreateScrapBucket(stack, "encrypted", {
|
|
220
|
+
encryption: s3.BucketEncryption.KMS,
|
|
221
|
+
encryptionKey: new aws_kms_1.Key(stack, 'Key', {
|
|
222
|
+
enableKeyRotation: true
|
|
223
|
+
})
|
|
224
|
+
});
|
|
225
|
+
const app = () => {
|
|
226
|
+
new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
227
|
+
existingBucketObj: existingBucket
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
expect(app).toThrowError(/Error - buckets cannot use CMKs with OAIs\n/);
|
|
231
|
+
});
|
|
232
|
+
test("Test that a CMK in the props throws an error", () => {
|
|
233
|
+
// Stack
|
|
234
|
+
const stack = new cdk.Stack();
|
|
235
|
+
const encryptionKey = new aws_kms_1.Key(stack, 'cmkKey', {
|
|
236
|
+
enableKeyRotation: true,
|
|
237
|
+
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY
|
|
238
|
+
});
|
|
239
|
+
const app = () => {
|
|
240
|
+
new lib_1.CloudFrontToOaiToS3(stack, "existingIBucket", {
|
|
241
|
+
bucketProps: {
|
|
242
|
+
enforceSSL: true,
|
|
243
|
+
encryption: s3.BucketEncryption.KMS,
|
|
244
|
+
encryptionKey
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
expect(app).toThrowError(/Error - buckets cannot use CMKs with OAIs\n/);
|
|
249
|
+
});
|
|
250
|
+
test('Cloudfront logging bucket with destroy removal policy and auto delete objects', () => {
|
|
251
|
+
const stack = new cdk.Stack();
|
|
252
|
+
const cloudfrontLogBucketName = 'cf-log-bucket';
|
|
253
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
254
|
+
cloudFrontLoggingBucketProps: {
|
|
255
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
256
|
+
autoDeleteObjects: true,
|
|
257
|
+
bucketName: cloudfrontLogBucketName
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
261
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
262
|
+
OwnershipControls: { Rules: [{ ObjectOwnership: "ObjectWriter" }] },
|
|
263
|
+
BucketName: cloudfrontLogBucketName,
|
|
264
|
+
});
|
|
265
|
+
template.hasResourceProperties("Custom::S3AutoDeleteObjects", {
|
|
266
|
+
ServiceToken: {
|
|
267
|
+
"Fn::GetAtt": [
|
|
268
|
+
"CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F",
|
|
269
|
+
"Arn"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
BucketName: {
|
|
273
|
+
Ref: assertions_1.Match.stringLikeRegexp("cloudfrontoais3CloudfrontLoggingBucket")
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
test('s3 bucket with one content bucket and no access logging of CONTENT bucket', () => {
|
|
278
|
+
const stack = new cdk.Stack();
|
|
279
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
280
|
+
bucketProps: {
|
|
281
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
282
|
+
},
|
|
283
|
+
logS3AccessLogs: false
|
|
284
|
+
});
|
|
285
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
286
|
+
// Content bucket+Cloudfront Logs bucket+
|
|
287
|
+
// Access Log bucket for Cloudfront Logs bucket = 3 buckets
|
|
288
|
+
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
289
|
+
expect(construct.s3LoggingBucket).toEqual(undefined);
|
|
290
|
+
});
|
|
291
|
+
test('CloudFront origin path present when provided', () => {
|
|
292
|
+
const stack = new cdk.Stack();
|
|
293
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
294
|
+
originPath: '/testPath'
|
|
295
|
+
});
|
|
296
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
297
|
+
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
298
|
+
DistributionConfig: {
|
|
299
|
+
Origins: [
|
|
300
|
+
{
|
|
301
|
+
OriginPath: "/testPath",
|
|
302
|
+
}
|
|
303
|
+
]
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
test('CloudFront origin path should not be present if not provided', () => {
|
|
308
|
+
const stack = new cdk.Stack();
|
|
309
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {});
|
|
310
|
+
defaults.expectNonexistence(stack, "AWS::CloudFront::Distribution", {
|
|
311
|
+
DistributionConfig: {
|
|
312
|
+
Origins: [
|
|
313
|
+
{
|
|
314
|
+
OriginPath: assertions_1.Match.anyValue(),
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
test('Test the deployment with securityHeadersBehavior instead of HTTP security headers', () => {
|
|
321
|
+
// Initial setup
|
|
322
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
323
|
+
const testConstruct = new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
324
|
+
insertHttpSecurityHeaders: false,
|
|
325
|
+
responseHeadersPolicyProps: {
|
|
326
|
+
securityHeadersBehavior: {
|
|
327
|
+
strictTransportSecurity: {
|
|
328
|
+
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
329
|
+
includeSubdomains: true,
|
|
330
|
+
override: true,
|
|
331
|
+
preload: true
|
|
332
|
+
},
|
|
333
|
+
contentSecurityPolicy: {
|
|
334
|
+
contentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
|
|
335
|
+
override: true
|
|
336
|
+
},
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
// Assertion
|
|
341
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
342
|
+
template.hasResourceProperties("AWS::CloudFront::ResponseHeadersPolicy", {
|
|
343
|
+
ResponseHeadersPolicyConfig: {
|
|
344
|
+
SecurityHeadersConfig: {
|
|
345
|
+
ContentSecurityPolicy: {
|
|
346
|
+
ContentSecurityPolicy: "upgrade-insecure-requests; default-src 'none';",
|
|
347
|
+
Override: true
|
|
348
|
+
},
|
|
349
|
+
StrictTransportSecurity: {
|
|
350
|
+
AccessControlMaxAgeSec: 63072,
|
|
351
|
+
IncludeSubdomains: true,
|
|
352
|
+
Override: true,
|
|
353
|
+
Preload: true
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
expect(testConstruct.cloudFrontFunction).toEqual(undefined);
|
|
359
|
+
});
|
|
360
|
+
test("throw exception if insertHttpSecurityHeaders and responseHeadersPolicyProps are provided", () => {
|
|
361
|
+
const stack = new cdk.Stack();
|
|
362
|
+
expect(() => {
|
|
363
|
+
new lib_1.CloudFrontToOaiToS3(stack, "test-cloudfront-oai-s3", {
|
|
364
|
+
insertHttpSecurityHeaders: true,
|
|
365
|
+
responseHeadersPolicyProps: {
|
|
366
|
+
securityHeadersBehavior: {
|
|
367
|
+
strictTransportSecurity: {
|
|
368
|
+
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
369
|
+
includeSubdomains: true,
|
|
370
|
+
override: false,
|
|
371
|
+
preload: true
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}).toThrowError();
|
|
377
|
+
});
|
|
378
|
+
test("Confirm CheckCloudFrontProps is being called", () => {
|
|
379
|
+
const stack = new cdk.Stack();
|
|
380
|
+
expect(() => {
|
|
381
|
+
new lib_1.CloudFrontToOaiToS3(stack, "test-cloudfront-apigateway", {
|
|
382
|
+
insertHttpSecurityHeaders: true,
|
|
383
|
+
responseHeadersPolicyProps: {
|
|
384
|
+
securityHeadersBehavior: {
|
|
385
|
+
strictTransportSecurity: {
|
|
386
|
+
accessControlMaxAge: aws_cdk_lib_1.Duration.seconds(63072),
|
|
387
|
+
includeSubdomains: true,
|
|
388
|
+
override: false,
|
|
389
|
+
preload: true
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.');
|
|
395
|
+
});
|
|
396
|
+
test('Test that we do not create an Access Log bucket for CF logs if one is provided', () => {
|
|
397
|
+
const stack = new cdk.Stack();
|
|
398
|
+
const cfS3AccessLogBucket = new s3.Bucket(stack, 'cf-s3-access-logs');
|
|
399
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'test-cloudfront-oai-s3', {
|
|
400
|
+
cloudFrontLoggingBucketProps: {
|
|
401
|
+
serverAccessLogsBucket: cfS3AccessLogBucket
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
405
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
406
|
+
});
|
|
407
|
+
// =====================
|
|
408
|
+
// S3 Content Bucket Access Logs Bucket
|
|
409
|
+
// =====================
|
|
410
|
+
test('Providing loggingBucketProps and existingLoggingBucket is an error', () => {
|
|
411
|
+
const stack = new cdk.Stack();
|
|
412
|
+
const logBucket = new s3.Bucket(stack, 'log-bucket', {});
|
|
413
|
+
const app = () => {
|
|
414
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
415
|
+
bucketProps: {
|
|
416
|
+
serverAccessLogsBucket: logBucket,
|
|
417
|
+
},
|
|
418
|
+
loggingBucketProps: {
|
|
419
|
+
bucketName: 'anything'
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
expect(app).toThrowError(/Error - bothlog bucket props and an existing log bucket were provided.\n/);
|
|
424
|
+
});
|
|
425
|
+
test('Providing existingLoggingBucket and logS3AccessLogs=false is an error', () => {
|
|
426
|
+
const stack = new cdk.Stack();
|
|
427
|
+
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
428
|
+
const app = () => {
|
|
429
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
430
|
+
bucketProps: {
|
|
431
|
+
serverAccessLogsBucket: logBucket,
|
|
432
|
+
},
|
|
433
|
+
logS3AccessLogs: false
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
expect(app).toThrowError(/Error - logS3AccessLogs is false, but a log bucket was provided in bucketProps.\n/);
|
|
437
|
+
});
|
|
438
|
+
test('Providing loggingBucketProps and logS3AccessLogs=false is an error', () => {
|
|
439
|
+
const stack = new cdk.Stack();
|
|
440
|
+
const app = () => {
|
|
441
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
442
|
+
loggingBucketProps: {
|
|
443
|
+
bucketName: 'anything'
|
|
444
|
+
},
|
|
445
|
+
logS3AccessLogs: false
|
|
446
|
+
});
|
|
447
|
+
};
|
|
448
|
+
// NOTE: This error is thrown by CheckS3Props(), not CheckConstructSpecificProps()
|
|
449
|
+
expect(app).toThrowError(/Error - If logS3AccessLogs is false, supplying loggingBucketProps or existingLoggingBucketObj is invalid.\n/);
|
|
450
|
+
});
|
|
451
|
+
// test('No new loggingBucket is created if existingLoggingBucket is supplied', () => {
|
|
452
|
+
test('loggingBucketProps is supplied is integrated into architecture correctly', () => {
|
|
453
|
+
const stack = new cdk.Stack();
|
|
454
|
+
const testName = "test-name";
|
|
455
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
456
|
+
bucketProps: {
|
|
457
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
458
|
+
},
|
|
459
|
+
loggingBucketProps: {
|
|
460
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
461
|
+
autoDeleteObjects: true,
|
|
462
|
+
bucketName: testName
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
expect(construct.s3LoggingBucket).toBeDefined();
|
|
466
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
467
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
468
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
469
|
+
BucketName: testName
|
|
470
|
+
});
|
|
471
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
472
|
+
LoggingConfiguration: {
|
|
473
|
+
DestinationBucketName: {
|
|
474
|
+
Ref: assertions_1.Match.stringLikeRegexp('cloudfrontoais3S3LoggingBucket')
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
test('bucketProps:serverAccessLogsBucket is supplied is integrated into architecture correctly', () => {
|
|
480
|
+
const testName = 'some-name';
|
|
481
|
+
const stack = new cdk.Stack();
|
|
482
|
+
const logBucket = new s3.Bucket(stack, 'test-log', {
|
|
483
|
+
bucketName: testName,
|
|
484
|
+
});
|
|
485
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
486
|
+
bucketProps: {
|
|
487
|
+
serverAccessLogsBucket: logBucket,
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
expect(construct.s3LoggingBucket).toBeDefined();
|
|
491
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
492
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
493
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
494
|
+
LoggingConfiguration: {
|
|
495
|
+
DestinationBucketName: {
|
|
496
|
+
Ref: "testlogE88B4C6B"
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
// =====================
|
|
502
|
+
// CloudFront Log Bucket
|
|
503
|
+
// =====================
|
|
504
|
+
test('Providing cloudFrontLoggingBucketProps and a log bucket in cloudFrontDistrbutionProps is an error', () => {
|
|
505
|
+
const stack = new cdk.Stack();
|
|
506
|
+
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
507
|
+
const app = () => {
|
|
508
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
509
|
+
cloudFrontDistributionProps: {
|
|
510
|
+
logBucket
|
|
511
|
+
},
|
|
512
|
+
cloudFrontLoggingBucketProps: {
|
|
513
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
514
|
+
autoDeleteObjects: true
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
expect(app).toThrowError();
|
|
519
|
+
});
|
|
520
|
+
test('cloudFrontLoggingBucketProps are used correctly', () => {
|
|
521
|
+
const stack = new cdk.Stack();
|
|
522
|
+
const testName = "test-name";
|
|
523
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
524
|
+
cloudFrontLoggingBucketProps: {
|
|
525
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
526
|
+
autoDeleteObjects: true,
|
|
527
|
+
bucketName: testName
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
531
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
532
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
533
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
534
|
+
BucketName: testName
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
test('Logging disabled in CloudFront props is handled correctly', () => {
|
|
538
|
+
const stack = new cdk.Stack();
|
|
539
|
+
const construct = deploy(stack, { cloudFrontDistributionProps: { enableLogging: false } });
|
|
540
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
541
|
+
// Only the content bucket and it S3 Access Log bucket (no Cloudfront log bucket)
|
|
542
|
+
template.resourceCountIs("AWS::S3::Bucket", 2);
|
|
543
|
+
// No logging is configured
|
|
544
|
+
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
|
|
545
|
+
DistributionConfig: {
|
|
546
|
+
Logging: assertions_1.Match.anyValue()
|
|
547
|
+
}
|
|
548
|
+
}, 0);
|
|
549
|
+
expect(construct.cloudFrontLoggingBucket === undefined);
|
|
550
|
+
});
|
|
551
|
+
test('No new CloudFrontLoggingBucket is created if cloudFrontLoggingBucketProps:logBucket is supplied', () => {
|
|
552
|
+
const testName = 'random-value';
|
|
553
|
+
const stack = new cdk.Stack();
|
|
554
|
+
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {
|
|
555
|
+
bucketName: testName
|
|
556
|
+
});
|
|
557
|
+
// const construct =
|
|
558
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
559
|
+
cloudFrontDistributionProps: {
|
|
560
|
+
logBucket
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
564
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
565
|
+
// Content bucket, Content bucket S3 Access Log bucket, cloudfront log bucket
|
|
566
|
+
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
567
|
+
// Ensure our existing bucket has been used for cloudfront logging
|
|
568
|
+
template.hasResourceProperties("AWS::CloudFront::Distribution", {
|
|
569
|
+
DistributionConfig: {
|
|
570
|
+
Logging: {
|
|
571
|
+
Bucket: {
|
|
572
|
+
"Fn::GetAtt": [
|
|
573
|
+
"cloudfrontlogbucketDF7058FB",
|
|
574
|
+
"RegionalDomainName"
|
|
575
|
+
]
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
// =====================
|
|
582
|
+
// CloudFront Logs Bucket Access Log Bucket
|
|
583
|
+
// =====================
|
|
584
|
+
test('Providing cloudFrontLoggingBucketAccessLogBucketProps and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
|
|
585
|
+
const stack = new cdk.Stack();
|
|
586
|
+
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
587
|
+
const app = () => {
|
|
588
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
589
|
+
cloudFrontLoggingBucketProps: {
|
|
590
|
+
serverAccessLogsBucket: logBucket,
|
|
591
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
592
|
+
autoDeleteObjects: true
|
|
593
|
+
},
|
|
594
|
+
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
595
|
+
bucketName: 'specfic-name-is-inconsequential'
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
};
|
|
599
|
+
expect(app).toThrowError(/Error - an existing CloudFront log bucket S3 access log bucket and cloudFrontLoggingBucketAccessLogBucketProps were provided\n/);
|
|
600
|
+
});
|
|
601
|
+
test('Providing cloudFrontLoggingBucketAccessLogBucketProps and logCloudFrontAccessLog=false is an error', () => {
|
|
602
|
+
const stack = new cdk.Stack();
|
|
603
|
+
const app = () => {
|
|
604
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
605
|
+
logCloudFrontAccessLog: false,
|
|
606
|
+
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
607
|
+
bucketName: 'specfic-name-is-inconsequential'
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
};
|
|
611
|
+
expect(app).toThrowError(/Error - cloudFrontLoggingBucketAccessLogBucketProps were provided but logCloudFrontAccessLog was false\n/);
|
|
612
|
+
});
|
|
613
|
+
test('Providing logCloudFrontAccessLog=false and cloudFrontLoggingBucketProps:serverAccessLogsBucket is an error', () => {
|
|
614
|
+
const stack = new cdk.Stack();
|
|
615
|
+
const logBucket = new s3.Bucket(stack, 'cloudfront-log-bucket', {});
|
|
616
|
+
const app = () => {
|
|
617
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
618
|
+
cloudFrontLoggingBucketProps: {
|
|
619
|
+
serverAccessLogsBucket: logBucket,
|
|
620
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
621
|
+
autoDeleteObjects: true
|
|
622
|
+
},
|
|
623
|
+
logCloudFrontAccessLog: false,
|
|
624
|
+
});
|
|
625
|
+
};
|
|
626
|
+
expect(app).toThrowError(/Error - props.cloudFrontLoggingBucketProps.serverAccessLogsBucket was provided but logCloudFrontAccessLog was false\n/);
|
|
627
|
+
});
|
|
628
|
+
test('cloudFrontLoggingBucketAccessLogBucketProps are used correctly', () => {
|
|
629
|
+
const stack = new cdk.Stack();
|
|
630
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
631
|
+
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
632
|
+
websiteErrorDocument: 'placeholder',
|
|
633
|
+
websiteIndexDocument: 'placeholde-two'
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
637
|
+
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
638
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
639
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
640
|
+
WebsiteConfiguration: {
|
|
641
|
+
ErrorDocument: 'placeholder',
|
|
642
|
+
IndexDocument: 'placeholde-two'
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
test('If existing CloudFront Log bucket S3 Access Logging bucket is provided, it is used correctly', () => {
|
|
647
|
+
const stack = new cdk.Stack();
|
|
648
|
+
const testName = 'cf-log-s3-log';
|
|
649
|
+
const cfLogS3AccessLogBucket = new s3.Bucket(stack, 'cf-log-s3-access-log-bucket', {
|
|
650
|
+
bucketName: testName
|
|
651
|
+
});
|
|
652
|
+
new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
653
|
+
cloudFrontLoggingBucketProps: {
|
|
654
|
+
serverAccessLogsBucket: cfLogS3AccessLogBucket
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
658
|
+
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
659
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
660
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
661
|
+
BucketName: testName
|
|
662
|
+
});
|
|
663
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
664
|
+
LoggingConfiguration: {
|
|
665
|
+
DestinationBucketName: {
|
|
666
|
+
Ref: "cflogs3accesslogbucketDE374C27"
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
test('cloudFrontLoggingBucketAccessLogBucket property is set correctly', () => {
|
|
672
|
+
const stack = new cdk.Stack();
|
|
673
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
674
|
+
cloudFrontLoggingBucketAccessLogBucketProps: {
|
|
675
|
+
websiteErrorDocument: 'placeholder',
|
|
676
|
+
websiteIndexDocument: 'placeholde-two'
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
680
|
+
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
681
|
+
template.resourceCountIs("AWS::S3::Bucket", 4);
|
|
682
|
+
template.hasResourceProperties("AWS::S3::Bucket", {
|
|
683
|
+
WebsiteConfiguration: {
|
|
684
|
+
ErrorDocument: 'placeholder',
|
|
685
|
+
IndexDocument: 'placeholde-two'
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
expect(construct.cloudFrontLoggingBucketAccessLogBucket).toBeDefined();
|
|
689
|
+
expect(construct.cloudFrontLoggingBucketAccessLogBucket.bucketName).toBeDefined();
|
|
690
|
+
});
|
|
691
|
+
test('logCloudFrontAccessLog property is used correctly', () => {
|
|
692
|
+
const stack = new cdk.Stack();
|
|
693
|
+
const construct = new lib_1.CloudFrontToOaiToS3(stack, 'cloudfront-oai-s3', {
|
|
694
|
+
logCloudFrontAccessLog: false
|
|
695
|
+
});
|
|
696
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
697
|
+
// Content Bucket, Content Bucket S3 Access Log Bucket, CloudFront Log Bucket, CloudFront Log Bucket S3 Access Log Bucket
|
|
698
|
+
template.resourceCountIs("AWS::S3::Bucket", 3);
|
|
699
|
+
expect(construct.cloudFrontLoggingBucket).toBeDefined();
|
|
700
|
+
expect(construct.cloudFrontLoggingBucketAccessLogBucket).not.toBeDefined();
|
|
701
|
+
});
|
|
702
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5jbG91ZGZyb250LW9haS1zMy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdC5jbG91ZGZyb250LW9haS1zMy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7R0FXRzs7QUFFSCx1REFBeUQ7QUFDekQseUNBQXlDO0FBQ3pDLG1DQUFtQztBQUNuQyw2Q0FBNkQ7QUFDN0QsZ0NBQXVFO0FBQ3ZFLDBEQUEwRDtBQUMxRCwyREFBMkQ7QUFDM0QsaURBQTBDO0FBRTFDLFNBQVMsTUFBTSxDQUFDLEtBQWdCLEVBQUUsS0FBZ0M7SUFDaEUsT0FBTyxJQUFJLHlCQUFtQixDQUFDLEtBQUssRUFBRSx3QkFBd0IsRUFBRTtRQUM5RCxXQUFXLEVBQUU7WUFDWCxhQUFhLEVBQUUsR0FBRyxDQUFDLGFBQWEsQ0FBQyxPQUFPO1NBQ3pDO1FBQ0QsR0FBRyxLQUFLO0tBQ1QsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELElBQUksQ0FBQyw2Q0FBNkMsRUFBRSxHQUFHLEVBQUU7SUFDdkQsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDOUIsTUFBTSxTQUFTLEdBQUcsSUFBSSx5QkFBbUIsQ0FBQyxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFL0UsTUFBTSxDQUFDLFNBQVMsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzFELE1BQU0sQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNuRCxNQUFNLENBQUMsU0FBUyxDQUFDLHVCQUF1QixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEQsTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFD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QUUsR0FBRyxFQUFFO0lBQzdELE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBRTlCLE1BQU0sU0FBUyxHQUFHLElBQUkseUJBQW1CLENBQUMsS0FBSyxFQUFFLG1CQUFtQixFQUFFO1FBQ3BFLHNCQUFzQixFQUFFLEtBQUs7S0FDOUIsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcscUJBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFM0MseUhBQXlIO0lBQ3pILFFBQVEsQ0FBQyxlQUFlLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDL0MsTUFBTSxDQUFDLFNBQVMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3hELE1BQU0sQ0FBQyxTQUFTLENBQUMsc0NBQXNDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7QUFDN0UsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqICBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKS4gWW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZVxuICogIHdpdGggdGhlIExpY2Vuc2UuIEEgY29weSBvZiB0aGUgTGljZW5zZSBpcyBsb2NhdGVkIGF0XG4gKlxuICogICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiAgb3IgaW4gdGhlICdsaWNlbnNlJyBmaWxlIGFjY29tcGFueWluZyB0aGlzIGZpbGUuIFRoaXMgZmlsZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAnQVMgSVMnIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVNcbiAqICBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBleHByZXNzIG9yIGltcGxpZWQuIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xuICogIGFuZCBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQgeyBNYXRjaCwgVGVtcGxhdGUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXNzZXJ0aW9uc1wiO1xuaW1wb3J0ICogYXMgczMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCAqIGFzIGNkayBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IER1cmF0aW9uLCBSZW1vdmFsUG9saWN5LCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgQ2xvdWRGcm9udFRvT2FpVG9TMywgQ2xvdWRGcm9udFRvT2FpVG9TM1Byb3BzIH0gZnJvbSBcIi4uL2xpYlwiO1xuaW1wb3J0ICogYXMgYWNtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1jZXJ0aWZpY2F0ZW1hbmFnZXInO1xuaW1wb3J0ICogYXMgZGVmYXVsdHMgZnJvbSAnQGF3cy1zb2x1dGlvbnMtY29uc3RydWN0cy9jb3JlJztcbmltcG9ydCB7IEtleSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mta21zXCI7XG5cbmZ1bmN0aW9uIGRlcGxveShzdGFjazogY2RrLlN0YWNrLCBwcm9wcz86IENsb3VkRnJvbnRUb09haVRvUzNQcm9wcykge1xuICByZXR1cm4gbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0sXG4gICAgLi4ucHJvcHNcbiAgfSk7XG59XG5cbnRlc3QoJ2NvbnN0cnVjdCBkZWZhdWx0cyBzZXQgcHJvcGVydGllcyBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBjb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1vYWktczMnLCB7fSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250V2ViRGlzdHJpYnV0aW9uKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRGdW5jdGlvbikudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250TG9nZ2luZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0J1Y2tldCkudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5zM0xvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuczNCdWNrZXRJbnRlcmZhY2UpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG59KTtcblxudGVzdCgnY2hlY2sgczNCdWNrZXQgZGVmYXVsdCBlbmNyeXB0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6UzM6OkJ1Y2tldCcsIHtcbiAgICBCdWNrZXRFbmNyeXB0aW9uOiB7XG4gICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb246IFt7XG4gICAgICAgIFNlcnZlclNpZGVFbmNyeXB0aW9uQnlEZWZhdWx0OiB7XG4gICAgICAgICAgU1NFQWxnb3JpdGhtOiBcIkFFUzI1NlwiXG4gICAgICAgIH1cbiAgICAgIH1dXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdjaGVjayB0aGF0IGFuIE9BSSBpcyBjcmVhdGVkJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBTM09yaWdpbkNvbmZpZzoge1xuICAgICAgICAgICAgT3JpZ2luQWNjZXNzSWRlbnRpdHk6IE1hdGNoLmFueVZhbHVlKClcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ2NvbmZpcm0gTk8gT0FDIGlzIGNyZWF0ZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBkZXBsb3koc3RhY2spO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgdGVtcGxhdGUucmVzb3VyY2VQcm9wZXJ0aWVzQ291bnRJcyhcIkFXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uXCIsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgIE9yaWdpbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIE9yaWdpbkFjY2Vzc0NvbnRyb2xJZDogTWF0Y2guYW55VmFsdWUoKSxcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSwgMCk7XG59KTtcblxudGVzdCgnY2hlY2sgczNCdWNrZXQgcHVibGljIGFjY2VzcyBibG9jayBjb25maWd1cmF0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgZGVwbG95KHN0YWNrKTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6UzM6OkJ1Y2tldCcsIHtcbiAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246IHtcbiAgICAgIEJsb2NrUHVibGljQWNsczogdHJ1ZSxcbiAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgSWdub3JlUHVibGljQWNsczogdHJ1ZSxcbiAgICAgIFJlc3RyaWN0UHVibGljQnVja2V0czogdHJ1ZVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgndGVzdCBzM0J1Y2tldCBvdmVycmlkZSBwdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb24nLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9PYWlUb1MzUHJvcHMgPSB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIGJsb2NrUHVibGljQWNjZXNzOiB7XG4gICAgICAgIGJsb2NrUHVibGljQWNsczogZmFsc2UsXG4gICAgICAgIGJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgICBpZ25vcmVQdWJsaWNBY2xzOiBmYWxzZSxcbiAgICAgICAgcmVzdHJpY3RQdWJsaWNCdWNrZXRzOiB0cnVlXG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LW9haS1zMycsIHByb3BzKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiB7XG4gICAgICBCbG9ja1B1YmxpY0FjbHM6IGZhbHNlLFxuICAgICAgQmxvY2tQdWJsaWNQb2xpY3k6IHRydWUsXG4gICAgICBJZ25vcmVQdWJsaWNBY2xzOiBmYWxzZSxcbiAgICAgIFJlc3RyaWN0UHVibGljQnVja2V0czogdHJ1ZVxuICAgIH0sXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2NoZWNrIGV4aXN0aW5nIGJ1Y2tldCcsICgpID0+IHtcbiAgY29uc3QgYnVja2V0TmFtZSA9IFwibXktYnVja2V0XCI7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGV4aXN0aW5nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgYnVja2V0TmFtZSwge1xuICAgIGJ1Y2tldE5hbWU6ICdteS1idWNrZXQnXG4gIH0pO1xuXG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9PYWlUb1MzUHJvcHMgPSB7XG4gICAgZXhpc3RpbmdCdWNrZXRPYmo6IGV4aXN0aW5nQnVja2V0XG4gIH07XG5cbiAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzJywgcHJvcHMpO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiBidWNrZXROYW1lXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2NoZWNrIHByb3BlcnRpZXMnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdDogQ2xvdWRGcm9udFRvT2FpVG9TMyA9IGRlcGxveShzdGFjayk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250V2ViRGlzdHJpYnV0aW9uKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LnMzQnVja2V0KS50b0JlRGVmaW5lZCgpO1xufSk7XG5cbnRlc3QoXCJDb25maXJtIENoZWNrUzNQcm9wcyBpcyBjYWxsZWRcIiwgKCkgPT4ge1xuICAvLyBTdGFja1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCB0ZXN0QnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ3Rlc3QtYnVja2V0Jywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICAvLyBIZWxwZXIgZGVjbGFyYXRpb25cbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJiYWQtczMtYXJnc1wiLCB7XG4gICAgICBleGlzdGluZ0J1Y2tldE9iajogdGVzdEJ1Y2tldCxcbiAgICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgICAgfSxcbiAgICB9KTtcbiAgfTtcbiAgLy8gQXNzZXJ0aW9uXG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcignRXJyb3IgLSBFaXRoZXIgcHJvdmlkZSBidWNrZXRQcm9wcyBvciBleGlzdGluZ0J1Y2tldE9iaiwgYnV0IG5vdCBib3RoLlxcbicpO1xufSk7XG5cbnRlc3QoXCJUZXN0IGV4aXN0aW5nQnVja2V0T2JqXCIsICgpID0+IHtcbiAgLy8gU3RhY2tcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGNvbnN0cnVjdDogQ2xvdWRGcm9udFRvT2FpVG9TMyA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCBcImV4aXN0aW5nSUJ1Y2tldFwiLCB7XG4gICAgZXhpc3RpbmdCdWNrZXRPYmo6IHMzLkJ1Y2tldC5mcm9tQnVja2V0TmFtZShzdGFjaywgJ215YnVja2V0JywgJ215YnVja2V0JylcbiAgfSk7XG4gIC8vIEFzc2VydGlvblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRXZWJEaXN0cmlidXRpb24pLnRvQmVEZWZpbmVkKCk7XG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDIpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBEb21haW5OYW1lOiB7XG4gICAgICAgICAgICBcIkZuOjpKb2luXCI6IFtcbiAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICAgW1xuICAgICAgICAgICAgICAgIFwibXlidWNrZXQuczMuXCIsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgUmVmOiBcIkFXUzo6UmVnaW9uXCJcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIFwiLlwiLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIFJlZjogXCJBV1M6OlVSTFN1ZmZpeFwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBdXG4gICAgICAgICAgICBdXG4gICAgICAgICAgfSxcbiAgICAgICAgICBJZDogXCJleGlzdGluZ0lCdWNrZXRDbG91ZEZyb250RGlzdHJpYnV0aW9uT3JpZ2luMUQ1ODQ5MTI1XCIsXG4gICAgICAgICAgUzNPcmlnaW5Db25maWc6IHtcbiAgICAgICAgICAgIE9yaWdpbkFjY2Vzc0lkZW50aXR5OiBNYXRjaC5hbnlWYWx1ZSgpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCd0ZXN0IGNsb3VkZnJvbnQgd2l0aCBjdXN0b20gZG9tYWluIG5hbWVzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjZXJ0aWZpY2F0ZSA9IGFjbS5DZXJ0aWZpY2F0ZS5mcm9tQ2VydGlmaWNhdGVBcm4oc3RhY2ssICdDZXJ0JywgJ2Fybjoke0F3cy5QQVJUSVRJT059OmFjbTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmNlcnRpZmljYXRlLzExMTEyMjIyLTMzMzMtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMicpO1xuXG4gIGNvbnN0IHByb3BzOiBDbG91ZEZyb250VG9PYWlUb1MzUHJvcHMgPSB7XG4gICAgY2xvdWRGcm9udERpc3RyaWJ1dGlvblByb3BzOiB7XG4gICAgICBkb21haW5OYW1lczogWydteWRvbWFpbnMnXSxcbiAgICAgIGNlcnRpZmljYXRlXG4gICAgfVxuICB9O1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAndGVzdC1jbG91ZGZyb250LW9haS1zMycsIHByb3BzKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uXCIsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgIEFsaWFzZXM6IFtcbiAgICAgICAgXCJteWRvbWFpbnNcIlxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdChcIlRlc3QgdGhhdCBhIENNSyBvbiB0aGUgYnVja2V0IHRocm93cyBhbiBlcnJvclwiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBleGlzdGluZ0J1Y2tldCA9IGRlZmF1bHRzLkNyZWF0ZVNjcmFwQnVja2V0KHN0YWNrLCBcImVuY3J5cHRlZFwiLCB7XG4gICAgZW5jcnlwdGlvbjogczMuQnVja2V0RW5jcnlwdGlvbi5LTVMsXG4gICAgZW5jcnlwdGlvbktleTogbmV3IEtleShzdGFjaywgJ0tleScsIHtcbiAgICAgIGVuYWJsZUtleVJvdGF0aW9uOiB0cnVlXG4gICAgfSlcbiAgfSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCBcImV4aXN0aW5nSUJ1Y2tldFwiLCB7XG4gICAgICBleGlzdGluZ0J1Y2tldE9iajogZXhpc3RpbmdCdWNrZXRcbiAgICB9KTtcbiAgfTtcbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIGJ1Y2tldHMgY2Fubm90IHVzZSBDTUtzIHdpdGggT0FJc1xcbi8pO1xufSk7XG5cbnRlc3QoXCJUZXN0IHRoYXQgYSBDTUsgaW4gdGhlIHByb3BzIHRocm93cyBhbiBlcnJvclwiLCAoKSA9PiB7XG4gIC8vIFN0YWNrXG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gbmV3IEtleShzdGFjaywgJ2Nta0tleScsIHtcbiAgICBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZSxcbiAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgfSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCBcImV4aXN0aW5nSUJ1Y2tldFwiLCB7XG4gICAgICBidWNrZXRQcm9wczoge1xuICAgICAgICBlbmZvcmNlU1NMOiB0cnVlLFxuICAgICAgICBlbmNyeXB0aW9uOiBzMy5CdWNrZXRFbmNyeXB0aW9uLktNUyxcbiAgICAgICAgZW5jcnlwdGlvbktleVxuICAgICAgfSxcbiAgICB9KTtcbiAgfTtcbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIGJ1Y2tldHMgY2Fubm90IHVzZSBDTUtzIHdpdGggT0FJc1xcbi8pO1xufSk7XG5cbnRlc3QoJ0Nsb3VkZnJvbnQgbG9nZ2luZyBidWNrZXQgd2l0aCBkZXN0cm95IHJlbW92YWwgcG9saWN5IGFuZCBhdXRvIGRlbGV0ZSBvYmplY3RzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCBjbG91ZGZyb250TG9nQnVja2V0TmFtZSA9ICdjZi1sb2ctYnVja2V0JztcbiAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gICAgICBidWNrZXROYW1lOiBjbG91ZGZyb250TG9nQnVja2V0TmFtZVxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIE93bmVyc2hpcENvbnRyb2xzOiB7IFJ1bGVzOiBbeyBPYmplY3RPd25lcnNoaXA6IFwiT2JqZWN0V3JpdGVyXCIgfV0gfSxcbiAgICBCdWNrZXROYW1lOiBjbG91ZGZyb250TG9nQnVja2V0TmFtZSxcbiAgfSk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQ3VzdG9tOjpTM0F1dG9EZWxldGVPYmplY3RzXCIsIHtcbiAgICBTZXJ2aWNlVG9rZW46IHtcbiAgICAgIFwiRm46OkdldEF0dFwiOiBbXG4gICAgICAgIFwiQ3VzdG9tUzNBdXRvRGVsZXRlT2JqZWN0c0N1c3RvbVJlc291cmNlUHJvdmlkZXJIYW5kbGVyOUQ5MDE4NEZcIixcbiAgICAgICAgXCJBcm5cIlxuICAgICAgXVxuICAgIH0sXG4gICAgQnVja2V0TmFtZToge1xuICAgICAgUmVmOiBNYXRjaC5zdHJpbmdMaWtlUmVnZXhwKFwiY2xvdWRmcm9udG9haXMzQ2xvdWRmcm9udExvZ2dpbmdCdWNrZXRcIilcbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ3MzIGJ1Y2tldCB3aXRoIG9uZSBjb250ZW50IGJ1Y2tldCBhbmQgbm8gYWNjZXNzIGxvZ2dpbmcgb2YgQ09OVEVOVCBidWNrZXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSxcbiAgICBsb2dTM0FjY2Vzc0xvZ3M6IGZhbHNlXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgLy8gQ29udGVudCBidWNrZXQrQ2xvdWRmcm9udCBMb2dzIGJ1Y2tldCtcbiAgLy8gQWNjZXNzIExvZyBidWNrZXQgZm9yIENsb3VkZnJvbnQgTG9ncyBidWNrZXQgPSAzIGJ1Y2tldHNcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDMpO1xuICBleHBlY3QoY29uc3RydWN0LnMzTG9nZ2luZ0J1Y2tldCkudG9FcXVhbCh1bmRlZmluZWQpO1xufSk7XG5cbnRlc3QoJ0Nsb3VkRnJvbnQgb3JpZ2luIHBhdGggcHJlc2VudCB3aGVuIHByb3ZpZGVkJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ2Nsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIG9yaWdpblBhdGg6ICcvdGVzdFBhdGgnXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb25cIiwge1xuICAgIERpc3RyaWJ1dGlvbkNvbmZpZzpcbiAgICB7XG4gICAgICBPcmlnaW5zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBPcmlnaW5QYXRoOiBcIi90ZXN0UGF0aFwiLFxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcbn0pO1xuXG50ZXN0KCdDbG91ZEZyb250IG9yaWdpbiBwYXRoIHNob3VsZCBub3QgYmUgcHJlc2VudCBpZiBub3QgcHJvdmlkZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7fSk7XG5cbiAgZGVmYXVsdHMuZXhwZWN0Tm9uZXhpc3RlbmNlKHN0YWNrLCBcIkFXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uXCIsIHtcbiAgICBEaXN0cmlidXRpb25Db25maWc6XG4gICAge1xuICAgICAgT3JpZ2luczogW1xuICAgICAgICB7XG4gICAgICAgICAgT3JpZ2luUGF0aDogTWF0Y2guYW55VmFsdWUoKSxcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnVGVzdCB0aGUgZGVwbG95bWVudCB3aXRoIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yIGluc3RlYWQgb2YgSFRUUCBzZWN1cml0eSBoZWFkZXJzJywgKCkgPT4ge1xuICAvLyBJbml0aWFsIHNldHVwXG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gIGNvbnN0IHRlc3RDb25zdHJ1Y3QgPSBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgJ3Rlc3QtY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgaW5zZXJ0SHR0cFNlY3VyaXR5SGVhZGVyczogZmFsc2UsXG4gICAgcmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHM6IHtcbiAgICAgIHNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yOiB7XG4gICAgICAgIHN0cmljdFRyYW5zcG9ydFNlY3VyaXR5OiB7XG4gICAgICAgICAgYWNjZXNzQ29udHJvbE1heEFnZTogRHVyYXRpb24uc2Vjb25kcyg2MzA3MiksXG4gICAgICAgICAgaW5jbHVkZVN1YmRvbWFpbnM6IHRydWUsXG4gICAgICAgICAgb3ZlcnJpZGU6IHRydWUsXG4gICAgICAgICAgcHJlbG9hZDogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBjb250ZW50U2VjdXJpdHlQb2xpY3k6IHtcbiAgICAgICAgICBjb250ZW50U2VjdXJpdHlQb2xpY3k6IFwidXBncmFkZS1pbnNlY3VyZS1yZXF1ZXN0czsgZGVmYXVsdC1zcmMgJ25vbmUnO1wiLFxuICAgICAgICAgIG92ZXJyaWRlOiB0cnVlXG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICAvLyBBc3NlcnRpb25cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OlJlc3BvbnNlSGVhZGVyc1BvbGljeVwiLCB7XG4gICAgUmVzcG9uc2VIZWFkZXJzUG9saWN5Q29uZmlnOiB7XG4gICAgICBTZWN1cml0eUhlYWRlcnNDb25maWc6IHtcbiAgICAgICAgQ29udGVudFNlY3VyaXR5UG9saWN5OiB7XG4gICAgICAgICAgQ29udGVudFNlY3VyaXR5UG9saWN5OiBcInVwZ3JhZGUtaW5zZWN1cmUtcmVxdWVzdHM7IGRlZmF1bHQtc3JjICdub25lJztcIixcbiAgICAgICAgICBPdmVycmlkZTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBTdHJpY3RUcmFuc3BvcnRTZWN1cml0eToge1xuICAgICAgICAgIEFjY2Vzc0NvbnRyb2xNYXhBZ2VTZWM6IDYzMDcyLFxuICAgICAgICAgIEluY2x1ZGVTdWJkb21haW5zOiB0cnVlLFxuICAgICAgICAgIE92ZXJyaWRlOiB0cnVlLFxuICAgICAgICAgIFByZWxvYWQ6IHRydWVcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGV4cGVjdCh0ZXN0Q29uc3RydWN0LmNsb3VkRnJvbnRGdW5jdGlvbikudG9FcXVhbCh1bmRlZmluZWQpO1xufSk7XG5cbnRlc3QoXCJ0aHJvdyBleGNlcHRpb24gaWYgaW5zZXJ0SHR0cFNlY3VyaXR5SGVhZGVycyBhbmQgcmVzcG9uc2VIZWFkZXJzUG9saWN5UHJvcHMgYXJlIHByb3ZpZGVkXCIsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgZXhwZWN0KCgpID0+IHtcbiAgICBuZXcgQ2xvdWRGcm9udFRvT2FpVG9TMyhzdGFjaywgXCJ0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzXCIsIHtcbiAgICAgIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnM6IHRydWUsXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wczoge1xuICAgICAgICBzZWN1cml0eUhlYWRlcnNCZWhhdmlvcjoge1xuICAgICAgICAgIHN0cmljdFRyYW5zcG9ydFNlY3VyaXR5OiB7XG4gICAgICAgICAgICBhY2Nlc3NDb250cm9sTWF4QWdlOiBEdXJhdGlvbi5zZWNvbmRzKDYzMDcyKSxcbiAgICAgICAgICAgIGluY2x1ZGVTdWJkb21haW5zOiB0cnVlLFxuICAgICAgICAgICAgb3ZlcnJpZGU6IGZhbHNlLFxuICAgICAgICAgICAgcHJlbG9hZDogdHJ1ZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9KS50b1Rocm93RXJyb3IoKTtcbn0pO1xuXG50ZXN0KFwiQ29uZmlybSBDaGVja0Nsb3VkRnJvbnRQcm9wcyBpcyBiZWluZyBjYWxsZWRcIiwgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBleHBlY3QoKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCBcInRlc3QtY2xvdWRmcm9udC1hcGlnYXRld2F5XCIsIHtcbiAgICAgIGluc2VydEh0dHBTZWN1cml0eUhlYWRlcnM6IHRydWUsXG4gICAgICByZXNwb25zZUhlYWRlcnNQb2xpY3lQcm9wczoge1xuICAgICAgICBzZWN1cml0eUhlYWRlcnNCZWhhdmlvcjoge1xuICAgICAgICAgIHN0cmljdFRyYW5zcG9ydFNlY3VyaXR5OiB7XG4gICAgICAgICAgICBhY2Nlc3NDb250cm9sTWF4QWdlOiBEdXJhdGlvbi5zZWNvbmRzKDYzMDcyKSxcbiAgICAgICAgICAgIGluY2x1ZGVTdWJkb21haW5zOiB0cnVlLFxuICAgICAgICAgICAgb3ZlcnJpZGU6IGZhbHNlLFxuICAgICAgICAgICAgcHJlbG9hZDogdHJ1ZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9KS50b1Rocm93RXJyb3IoJ3Jlc3BvbnNlSGVhZGVyc1BvbGljeVByb3BzLnNlY3VyaXR5SGVhZGVyc0JlaGF2aW9yIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBodHRwU2VjdXJpdHlIZWFkZXJzIGlzIHNldCB0byBgZmFsc2VgLicpO1xufSk7XG5cbnRlc3QoJ1Rlc3QgdGhhdCB3ZSBkbyBub3QgY3JlYXRlIGFuIEFjY2VzcyBMb2cgYnVja2V0IGZvciBDRiBsb2dzIGlmIG9uZSBpcyBwcm92aWRlZCcsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGNmUzNBY2Nlc3NMb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2YtczMtYWNjZXNzLWxvZ3MnKTtcbiAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICd0ZXN0LWNsb3VkZnJvbnQtb2FpLXMzJywge1xuICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGNmUzNBY2Nlc3NMb2dCdWNrZXRcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuXG59KTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09XG4vLyBTMyBDb250ZW50IEJ1Y2tldCBBY2Nlc3MgTG9ncyBCdWNrZXRcbi8vID09PT09PT09PT09PT09PT09PT09PVxudGVzdCgnUHJvdmlkaW5nIGxvZ2dpbmdCdWNrZXRQcm9wcyBhbmQgZXhpc3RpbmdMb2dnaW5nQnVja2V0IGlzIGFuIGVycm9yJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2xvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBidWNrZXRQcm9wczoge1xuICAgICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBsb2dCdWNrZXQsXG4gICAgICB9LFxuICAgICAgbG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdhbnl0aGluZydcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIGJvdGhsb2cgYnVja2V0IHByb3BzIGFuZCBhbiBleGlzdGluZyBsb2cgYnVja2V0IHdlcmUgcHJvdmlkZWQuXFxuLyk7XG59KTtcblxudGVzdCgnUHJvdmlkaW5nIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldCBhbmQgbG9nUzNBY2Nlc3NMb2dzPWZhbHNlIGlzIGFuIGVycm9yJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2Nsb3VkZnJvbnQtbG9nLWJ1Y2tldCcsIHt9KTtcblxuICBjb25zdCBhcHAgPSAoKSA9PiB7XG4gICAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICAgIGJ1Y2tldFByb3BzOiB7XG4gICAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGxvZ0J1Y2tldCxcbiAgICAgIH0sXG4gICAgICBsb2dTM0FjY2Vzc0xvZ3M6IGZhbHNlXG4gICAgfSk7XG4gIH07XG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcigvRXJyb3IgLSBsb2dTM0FjY2Vzc0xvZ3MgaXMgZmFsc2UsIGJ1dCBhIGxvZyBidWNrZXQgd2FzIHByb3ZpZGVkIGluIGJ1Y2tldFByb3BzLlxcbi8pO1xufSk7XG5cbnRlc3QoJ1Byb3ZpZGluZyBsb2dnaW5nQnVja2V0UHJvcHMgYW5kIGxvZ1MzQWNjZXNzTG9ncz1mYWxzZSBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBsb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgICAgYnVja2V0TmFtZTogJ2FueXRoaW5nJ1xuICAgICAgfSxcbiAgICAgIGxvZ1MzQWNjZXNzTG9nczogZmFsc2VcbiAgICB9KTtcbiAgfTtcbiAgLy8gTk9URTogVGhpcyBlcnJvciBpcyB0aHJvd24gYnkgQ2hlY2tTM1Byb3BzKCksIG5vdCBDaGVja0NvbnN0cnVjdFNwZWNpZmljUHJvcHMoKVxuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoL0Vycm9yIC0gSWYgbG9nUzNBY2Nlc3NMb2dzIGlzIGZhbHNlLCBzdXBwbHlpbmcgbG9nZ2luZ0J1Y2tldFByb3BzIG9yIGV4aXN0aW5nTG9nZ2luZ0J1Y2tldE9iaiBpcyBpbnZhbGlkLlxcbi8pO1xufSk7XG5cbi8vIHRlc3QoJ05vIG5ldyBsb2dnaW5nQnVja2V0IGlzIGNyZWF0ZWQgaWYgZXhpc3RpbmdMb2dnaW5nQnVja2V0IGlzIHN1cHBsaWVkJywgKCkgPT4ge1xudGVzdCgnbG9nZ2luZ0J1Y2tldFByb3BzIGlzIHN1cHBsaWVkIGlzIGludGVncmF0ZWQgaW50byBhcmNoaXRlY3R1cmUgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCB0ZXN0TmFtZSA9IFwidGVzdC1uYW1lXCI7XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgYnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSxcbiAgICBsb2dnaW5nQnVja2V0UHJvcHM6IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gICAgfVxuICB9KTtcblxuICBleHBlY3QoY29uc3RydWN0LnMzTG9nZ2luZ0J1Y2tldCkudG9CZURlZmluZWQoKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCA0KTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIEJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gIH0pO1xuXG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6UzM6OkJ1Y2tldFwiLCB7XG4gICAgTG9nZ2luZ0NvbmZpZ3VyYXRpb246IHtcbiAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZToge1xuICAgICAgICBSZWY6IE1hdGNoLnN0cmluZ0xpa2VSZWdleHAoJ2Nsb3VkZnJvbnRvYWlzM1MzTG9nZ2luZ0J1Y2tldCcpXG4gICAgICB9XG4gICAgfVxuICB9KTtcbn0pO1xudGVzdCgnYnVja2V0UHJvcHM6c2VydmVyQWNjZXNzTG9nc0J1Y2tldCBpcyBzdXBwbGllZCBpcyBpbnRlZ3JhdGVkIGludG8gYXJjaGl0ZWN0dXJlIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3QgdGVzdE5hbWUgPSAnc29tZS1uYW1lJztcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICd0ZXN0LWxvZycsIHtcbiAgICBidWNrZXROYW1lOiB0ZXN0TmFtZSxcbiAgfSk7XG5cbiAgY29uc3QgY29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBidWNrZXRQcm9wczoge1xuICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogbG9nQnVja2V0LFxuICAgIH0sXG4gIH0pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuczNMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIExvZ2dpbmdDb25maWd1cmF0aW9uOiB7XG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6IHtcbiAgICAgICAgUmVmOiBcInRlc3Rsb2dFODhCNEM2QlwiXG4gICAgICB9XG4gICAgfVxuICB9KTtcbn0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbi8vIENsb3VkRnJvbnQgTG9nIEJ1Y2tldFxuLy8gPT09PT09PT09PT09PT09PT09PT09XG50ZXN0KCdQcm92aWRpbmcgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wcyBhbmQgYSBsb2cgYnVja2V0IGluIGNsb3VkRnJvbnREaXN0cmJ1dGlvblByb3BzIGlzIGFuIGVycm9yJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcbiAgY29uc3QgbG9nQnVja2V0ID0gbmV3IHMzLkJ1Y2tldChzdGFjaywgJ2Nsb3VkZnJvbnQtbG9nLWJ1Y2tldCcsIHt9KTtcblxuICBjb25zdCBhcHAgPSAoKSA9PiB7XG4gICAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICAgIGNsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wczoge1xuICAgICAgICBsb2dCdWNrZXRcbiAgICAgIH0sXG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlXG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKCk7XG59KTtcbnRlc3QoJ2Nsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHMgYXJlIHVzZWQgY29ycmVjdGx5JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBjb25zdCB0ZXN0TmFtZSA9IFwidGVzdC1uYW1lXCI7XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczoge1xuICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgIGF1dG9EZWxldGVPYmplY3RzOiB0cnVlLFxuICAgICAgYnVja2V0TmFtZTogdGVzdE5hbWVcbiAgICB9XG4gIH0pO1xuXG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxufSk7XG50ZXN0KCdMb2dnaW5nIGRpc2FibGVkIGluIENsb3VkRnJvbnQgcHJvcHMgaXMgaGFuZGxlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IGRlcGxveShzdGFjaywgeyBjbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHM6IHsgZW5hYmxlTG9nZ2luZzogZmFsc2UgfSB9KTtcbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIE9ubHkgdGhlIGNvbnRlbnQgYnVja2V0IGFuZCBpdCBTMyBBY2Nlc3MgTG9nIGJ1Y2tldCAobm8gQ2xvdWRmcm9udCBsb2cgYnVja2V0KVxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgMik7XG5cbiAgLy8gTm8gbG9nZ2luZyBpcyBjb25maWd1cmVkXG4gIHRlbXBsYXRlLnJlc291cmNlUHJvcGVydGllc0NvdW50SXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBMb2dnaW5nOiBNYXRjaC5hbnlWYWx1ZSgpXG4gICAgfVxuICB9LCAwKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5jbG91ZEZyb250TG9nZ2luZ0J1Y2tldCA9PT0gdW5kZWZpbmVkKTtcbn0pO1xudGVzdCgnTm8gbmV3IENsb3VkRnJvbnRMb2dnaW5nQnVja2V0IGlzIGNyZWF0ZWQgaWYgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wczpsb2dCdWNrZXQgaXMgc3VwcGxpZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHRlc3ROYW1lID0gJ3JhbmRvbS12YWx1ZSc7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCBsb2dCdWNrZXQgPSBuZXcgczMuQnVja2V0KHN0YWNrLCAnY2xvdWRmcm9udC1sb2ctYnVja2V0Jywge1xuICAgIGJ1Y2tldE5hbWU6IHRlc3ROYW1lXG4gIH0pO1xuXG4gIC8vIGNvbnN0IGNvbnN0cnVjdCA9XG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udERpc3RyaWJ1dGlvblByb3BzOiB7XG4gICAgICBsb2dCdWNrZXRcbiAgICB9LFxuICB9KTtcblxuICBleHBlY3QoY29uc3RydWN0LmNsb3VkRnJvbnRMb2dnaW5nQnVja2V0KS50b0JlRGVmaW5lZCgpO1xuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBidWNrZXQsIENvbnRlbnQgYnVja2V0IFMzIEFjY2VzcyBMb2cgYnVja2V0LCBjbG91ZGZyb250IGxvZyBidWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDMpO1xuXG4gIC8vIEVuc3VyZSBvdXIgZXhpc3RpbmcgYnVja2V0IGhhcyBiZWVuIHVzZWQgZm9yIGNsb3VkZnJvbnQgbG9nZ2luZ1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvblwiLCB7XG4gICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICBMb2dnaW5nOiB7XG4gICAgICAgIEJ1Y2tldDoge1xuICAgICAgICAgIFwiRm46OkdldEF0dFwiOiBbXG4gICAgICAgICAgICBcImNsb3VkZnJvbnRsb2didWNrZXRERjcwNThGQlwiLFxuICAgICAgICAgICAgXCJSZWdpb25hbERvbWFpbk5hbWVcIlxuICAgICAgICAgIF1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbn0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT1cbi8vIENsb3VkRnJvbnQgTG9ncyBCdWNrZXQgQWNjZXNzIExvZyBCdWNrZXRcbi8vID09PT09PT09PT09PT09PT09PT09PVxudGVzdCgnUHJvdmlkaW5nIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgYW5kIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6c2VydmVyQWNjZXNzTG9nc0J1Y2tldCBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjbG91ZGZyb250LWxvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGxvZ0J1Y2tldCxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWVcbiAgICAgIH0sXG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldEFjY2Vzc0xvZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdzcGVjZmljLW5hbWUtaXMtaW5jb25zZXF1ZW50aWFsJ1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIGV4cGVjdChhcHApLnRvVGhyb3dFcnJvcihcbiAgICAvRXJyb3IgLSBhbiBleGlzdGluZyBDbG91ZEZyb250IGxvZyBidWNrZXQgUzMgYWNjZXNzIGxvZyBidWNrZXQgYW5kIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgd2VyZSBwcm92aWRlZFxcbi8pO1xufSk7XG50ZXN0KCdQcm92aWRpbmcgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wcyBhbmQgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZz1mYWxzZSBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBsb2dDbG91ZEZyb250QWNjZXNzTG9nOiBmYWxzZSxcbiAgICAgIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHM6IHtcbiAgICAgICAgYnVja2V0TmFtZTogJ3NwZWNmaWMtbmFtZS1pcy1pbmNvbnNlcXVlbnRpYWwnXG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKC9FcnJvciAtIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0UHJvcHMgd2VyZSBwcm92aWRlZCBidXQgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZyB3YXMgZmFsc2VcXG4vKTtcbn0pO1xudGVzdCgnUHJvdmlkaW5nIGxvZ0Nsb3VkRnJvbnRBY2Nlc3NMb2c9ZmFsc2UgYW5kIGNsb3VkRnJvbnRMb2dnaW5nQnVja2V0UHJvcHM6c2VydmVyQWNjZXNzTG9nc0J1Y2tldCBpcyBhbiBlcnJvcicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG4gIGNvbnN0IGxvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjbG91ZGZyb250LWxvZy1idWNrZXQnLCB7fSk7XG5cbiAgY29uc3QgYXBwID0gKCkgPT4ge1xuICAgIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICAgIHNlcnZlckFjY2Vzc0xvZ3NCdWNrZXQ6IGxvZ0J1Y2tldCxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWVcbiAgICAgIH0sXG4gICAgICBsb2dDbG91ZEZyb250QWNjZXNzTG9nOiBmYWxzZSxcbiAgICB9KTtcbiAgfTtcblxuICBleHBlY3QoYXBwKS50b1Rocm93RXJyb3IoL0Vycm9yIC0gcHJvcHMuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRQcm9wcy5zZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0IHdhcyBwcm92aWRlZCBidXQgbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZyB3YXMgZmFsc2VcXG4vKTtcbn0pO1xudGVzdCgnY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wcyBhcmUgdXNlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wczoge1xuICAgICAgd2Vic2l0ZUVycm9yRG9jdW1lbnQ6ICdwbGFjZWhvbGRlcicsXG4gICAgICB3ZWJzaXRlSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFdlYnNpdGVDb25maWd1cmF0aW9uOiB7XG4gICAgICBFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbn0pO1xudGVzdCgnSWYgZXhpc3RpbmcgQ2xvdWRGcm9udCBMb2cgYnVja2V0IFMzIEFjY2VzcyBMb2dnaW5nIGJ1Y2tldCBpcyBwcm92aWRlZCwgaXQgaXMgdXNlZCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuICBjb25zdCB0ZXN0TmFtZSA9ICdjZi1sb2ctczMtbG9nJztcbiAgY29uc3QgY2ZMb2dTM0FjY2Vzc0xvZ0J1Y2tldCA9IG5ldyBzMy5CdWNrZXQoc3RhY2ssICdjZi1sb2ctczMtYWNjZXNzLWxvZy1idWNrZXQnLCB7XG4gICAgYnVja2V0TmFtZTogdGVzdE5hbWVcbiAgfSk7XG5cbiAgbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBjbG91ZEZyb250TG9nZ2luZ0J1Y2tldFByb3BzOiB7XG4gICAgICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBjZkxvZ1MzQWNjZXNzTG9nQnVja2V0XG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBCdWNrZXQsIENvbnRlbnQgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldFxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgNCk7XG5cbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpTMzo6QnVja2V0XCIsIHtcbiAgICBCdWNrZXROYW1lOiB0ZXN0TmFtZVxuICB9KTtcblxuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIExvZ2dpbmdDb25maWd1cmF0aW9uOiB7XG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6IHtcbiAgICAgICAgUmVmOiBcImNmbG9nczNhY2Nlc3Nsb2didWNrZXRERTM3NEMyN1wiXG4gICAgICB9XG4gICAgfVxuICB9KTtcblxufSk7XG5cbnRlc3QoJ2Nsb3VkRnJvbnRMb2dnaW5nQnVja2V0QWNjZXNzTG9nQnVja2V0IHByb3BlcnR5IGlzIHNldCBjb3JyZWN0bHknLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBDbG91ZEZyb250VG9PYWlUb1MzKHN0YWNrLCAnY2xvdWRmcm9udC1vYWktczMnLCB7XG4gICAgY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXRQcm9wczoge1xuICAgICAgd2Vic2l0ZUVycm9yRG9jdW1lbnQ6ICdwbGFjZWhvbGRlcicsXG4gICAgICB3ZWJzaXRlSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIENvbnRlbnQgQnVja2V0LCBDb250ZW50IEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldCwgQ2xvdWRGcm9udCBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQgUzMgQWNjZXNzIExvZyBCdWNrZXRcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpTMzo6QnVja2V0XCIsIDQpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwge1xuICAgIFdlYnNpdGVDb25maWd1cmF0aW9uOiB7XG4gICAgICBFcnJvckRvY3VtZW50OiAncGxhY2Vob2xkZXInLFxuICAgICAgSW5kZXhEb2N1bWVudDogJ3BsYWNlaG9sZGUtdHdvJ1xuICAgIH1cbiAgfSk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQhLmJ1Y2tldE5hbWUpLnRvQmVEZWZpbmVkKCk7XG59KTtcblxudGVzdCgnbG9nQ2xvdWRGcm9udEFjY2Vzc0xvZyBwcm9wZXJ0eSBpcyB1c2VkIGNvcnJlY3RseScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgY29uc3QgY29uc3RydWN0ID0gbmV3IENsb3VkRnJvbnRUb09haVRvUzMoc3RhY2ssICdjbG91ZGZyb250LW9haS1zMycsIHtcbiAgICBsb2dDbG91ZEZyb250QWNjZXNzTG9nOiBmYWxzZVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gQ29udGVudCBCdWNrZXQsIENvbnRlbnQgQnVja2V0IFMzIEFjY2VzcyBMb2cgQnVja2V0LCBDbG91ZEZyb250IExvZyBCdWNrZXQsIENsb3VkRnJvbnQgTG9nIEJ1Y2tldCBTMyBBY2Nlc3MgTG9nIEJ1Y2tldFxuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OlMzOjpCdWNrZXRcIiwgMyk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXQpLnRvQmVEZWZpbmVkKCk7XG4gIGV4cGVjdChjb25zdHJ1Y3QuY2xvdWRGcm9udExvZ2dpbmdCdWNrZXRBY2Nlc3NMb2dCdWNrZXQpLm5vdC50b0JlRGVmaW5lZCgpO1xufSk7XG4iXX0=
|