1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.SecretValue = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const cx_api_1 = require("@aws-cdk/cx-api");
|
8 | const cfn_dynamic_reference_1 = require("./cfn-dynamic-reference");
|
9 | const cfn_resource_1 = require("./cfn-resource");
|
10 | const feature_flags_1 = require("./feature-flags");
|
11 | const cfn_reference_1 = require("./private/cfn-reference");
|
12 | const intrinsic_1 = require("./private/intrinsic");
|
13 | const token_1 = require("./token");
|
14 | /**
|
15 | * Work with secret values in the CDK
|
16 | *
|
17 | * Constructs that need secrets will declare parameters of type `SecretValue`.
|
18 | *
|
19 | * The actual values of these secrets should not be committed to your
|
20 | * repository, or even end up in the synthesized CloudFormation template. Instead, you should
|
21 | * store them in an external system like AWS Secrets Manager or SSM Parameter
|
22 | * Store, and you can reference them by calling `SecretValue.secretsManager()` or
|
23 | * `SecretValue.ssmSecure()`.
|
24 | *
|
25 | * You can use `SecretValue.unsafePlainText()` to construct a `SecretValue` from a
|
26 | * literal string, but doing so is highly discouraged.
|
27 | *
|
28 | * To make sure secret values don't accidentally end up in readable parts
|
29 | * of your infrastructure definition (such as the environment variables
|
30 | * of an AWS Lambda Function, where everyone who can read the function
|
31 | * definition has access to the secret), using secret values directly is not
|
32 | * allowed. You must pass them to constructs that accept `SecretValue`
|
33 | * properties, which are guaranteed to use the value only in CloudFormation
|
34 | * properties that are write-only.
|
35 | *
|
36 | * If you are sure that what you are doing is safe, you can call
|
37 | * `secretValue.unsafeUnwrap()` to access the protected string of the secret
|
38 | * value.
|
39 | *
|
40 | * (If you are writing something like an AWS Lambda Function and need to access
|
41 | * a secret inside it, make the API call to `GetSecretValue` directly inside
|
42 | * your Lamba's code, instead of using environment variables.)
|
43 | */
|
44 | class SecretValue extends intrinsic_1.Intrinsic {
|
45 | /**
|
46 | * Construct a SecretValue (do not use!)
|
47 | *
|
48 | * Do not use the constructor directly: use one of the factory functions on the class
|
49 | * instead.
|
50 | */
|
51 | constructor(protectedValue, options) {
|
52 | super(protectedValue, options);
|
53 | try {
|
54 | jsiiDeprecationWarnings._aws_cdk_core_IntrinsicProps(options);
|
55 | }
|
56 | catch (error) {
|
57 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
58 | Error.captureStackTrace(error, SecretValue);
|
59 | }
|
60 | throw error;
|
61 | }
|
62 | this.rawValue = protectedValue;
|
63 | }
|
64 | /**
|
65 | * Test whether an object is a SecretValue
|
66 | */
|
67 | static isSecretValue(x) {
|
68 | return typeof x === 'object' && x && x[SECRET_VALUE_SYM];
|
69 | }
|
70 | /**
|
71 | * Construct a literal secret value for use with secret-aware constructs
|
72 | *
|
73 | * Do not use this method for any secrets that you care about! The value
|
74 | * will be visible to anyone who has access to the CloudFormation template
|
75 | * (via the AWS Console, SDKs, or CLI).
|
76 | *
|
77 | * The only reasonable use case for using this method is when you are testing.
|
78 | *
|
79 | * @deprecated Use `unsafePlainText()` instead.
|
80 | */
|
81 | static plainText(secret) {
|
82 | try {
|
83 | jsiiDeprecationWarnings.print("@aws-cdk/core.SecretValue#plainText", "Use `unsafePlainText()` instead.");
|
84 | }
|
85 | catch (error) {
|
86 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
87 | Error.captureStackTrace(error, this.plainText);
|
88 | }
|
89 | throw error;
|
90 | }
|
91 | return new SecretValue(secret);
|
92 | }
|
93 | /**
|
94 | * Construct a literal secret value for use with secret-aware constructs
|
95 | *
|
96 | * Do not use this method for any secrets that you care about! The value
|
97 | * will be visible to anyone who has access to the CloudFormation template
|
98 | * (via the AWS Console, SDKs, or CLI).
|
99 | *
|
100 | * The only reasonable use case for using this method is when you are testing.
|
101 | */
|
102 | static unsafePlainText(secret) {
|
103 | return new SecretValue(secret);
|
104 | }
|
105 | /**
|
106 | * Creates a `SecretValue` with a value which is dynamically loaded from AWS Secrets Manager.
|
107 | * @param secretId The ID or ARN of the secret
|
108 | * @param options Options
|
109 | */
|
110 | static secretsManager(secretId, options = {}) {
|
111 | try {
|
112 | jsiiDeprecationWarnings._aws_cdk_core_SecretsManagerSecretOptions(options);
|
113 | }
|
114 | catch (error) {
|
115 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
116 | Error.captureStackTrace(error, this.secretsManager);
|
117 | }
|
118 | throw error;
|
119 | }
|
120 | if (!secretId) {
|
121 | throw new Error('secretId cannot be empty');
|
122 | }
|
123 | if (!token_1.Token.isUnresolved(secretId) && !secretId.startsWith('arn:') && secretId.includes(':')) {
|
124 | throw new Error(`secret id "${secretId}" is not an ARN but contains ":"`);
|
125 | }
|
126 | if (options.versionStage && options.versionId) {
|
127 | throw new Error(`verionStage: '${options.versionStage}' and versionId: '${options.versionId}' were both provided but only one is allowed`);
|
128 | }
|
129 | const parts = [
|
130 | secretId,
|
131 | 'SecretString',
|
132 | options.jsonField || '',
|
133 | options.versionStage || '',
|
134 | options.versionId || '',
|
135 | ];
|
136 | const dyref = new cfn_dynamic_reference_1.CfnDynamicReference(cfn_dynamic_reference_1.CfnDynamicReferenceService.SECRETS_MANAGER, parts.join(':'));
|
137 | return this.cfnDynamicReference(dyref);
|
138 | }
|
139 | /**
|
140 | * Use a secret value stored from a Systems Manager (SSM) parameter.
|
141 | *
|
142 | * @param parameterName The name of the parameter in the Systems Manager
|
143 | * Parameter Store. The parameter name is case-sensitive.
|
144 | *
|
145 | * @param version An integer that specifies the version of the parameter to
|
146 | * use. If you don't specify the exact version, AWS CloudFormation uses the
|
147 | * latest version of the parameter.
|
148 | */
|
149 | static ssmSecure(parameterName, version) {
|
150 | return this.cfnDynamicReference(new cfn_dynamic_reference_1.CfnDynamicReference(cfn_dynamic_reference_1.CfnDynamicReferenceService.SSM_SECURE, version ? `${parameterName}:${version}` : parameterName));
|
151 | }
|
152 | /**
|
153 | * Obtain the secret value through a CloudFormation dynamic reference.
|
154 | *
|
155 | * If possible, use `SecretValue.ssmSecure` or `SecretValue.secretsManager` directly.
|
156 | *
|
157 | * @param ref The dynamic reference to use.
|
158 | */
|
159 | static cfnDynamicReference(ref) {
|
160 | try {
|
161 | jsiiDeprecationWarnings._aws_cdk_core_CfnDynamicReference(ref);
|
162 | }
|
163 | catch (error) {
|
164 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
165 | Error.captureStackTrace(error, this.cfnDynamicReference);
|
166 | }
|
167 | throw error;
|
168 | }
|
169 | return new SecretValue(ref);
|
170 | }
|
171 | /**
|
172 | * Obtain the secret value through a CloudFormation parameter.
|
173 | *
|
174 | * Generally, this is not a recommended approach. AWS Secrets Manager is the
|
175 | * recommended way to reference secrets.
|
176 | *
|
177 | * @param param The CloudFormation parameter to use.
|
178 | */
|
179 | static cfnParameter(param) {
|
180 | try {
|
181 | jsiiDeprecationWarnings._aws_cdk_core_CfnParameter(param);
|
182 | }
|
183 | catch (error) {
|
184 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
185 | Error.captureStackTrace(error, this.cfnParameter);
|
186 | }
|
187 | throw error;
|
188 | }
|
189 | if (!param.noEcho) {
|
190 | throw new Error('CloudFormation parameter must be configured with "NoEcho"');
|
191 | }
|
192 | return new SecretValue(param.value);
|
193 | }
|
194 | /**
|
195 | * Use a resource's output as secret value
|
196 | */
|
197 | static resourceAttribute(attr) {
|
198 | const resolved = token_1.Tokenization.reverseCompleteString(attr);
|
199 | if (!resolved || !cfn_reference_1.CfnReference.isCfnReference(resolved) || !cfn_resource_1.CfnResource.isCfnResource(resolved.target)) {
|
200 | throw new Error('SecretValue.resourceAttribute() must be used with a resource attribute');
|
201 | }
|
202 | return new SecretValue(attr);
|
203 | }
|
204 | /**
|
205 | * Disable usage protection on this secret
|
206 | *
|
207 | * Call this to indicate that you want to use the secret value held by this
|
208 | * object in an unchecked way. If you don't call this method, using the secret
|
209 | * value directly in a string context or as a property value somewhere will
|
210 | * produce an error.
|
211 | *
|
212 | * This method has 'unsafe' in the name on purpose! Make sure that the
|
213 | * construct property you are using the returned value in is does not end up
|
214 | * in a place in your AWS infrastructure where it could be read by anyone
|
215 | * unexpected.
|
216 | *
|
217 | * When in doubt, don't call this method and only pass the object to constructs that
|
218 | * accept `SecretValue` parameters.
|
219 | */
|
220 | unsafeUnwrap() {
|
221 | return token_1.Token.asString(this.rawValue);
|
222 | }
|
223 | /**
|
224 | * Resolve the secret
|
225 | *
|
226 | * If the feature flag is not set, resolve as normal. Otherwise, throw a descriptive
|
227 | * error that the usage guard is missing.
|
228 | */
|
229 | resolve(context) {
|
230 | try {
|
231 | jsiiDeprecationWarnings._aws_cdk_core_IResolveContext(context);
|
232 | }
|
233 | catch (error) {
|
234 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
235 | Error.captureStackTrace(error, this.resolve);
|
236 | }
|
237 | throw error;
|
238 | }
|
239 | if (feature_flags_1.FeatureFlags.of(context.scope).isEnabled(cx_api_1.CHECK_SECRET_USAGE)) {
|
240 | throw new Error(`Synthing a secret value to ${context.documentPath.join('/')}. Using a SecretValue here risks exposing your secret. Only pass SecretValues to constructs that accept a SecretValue property, or call AWS Secrets Manager directly in your runtime code. Call 'secretValue.unsafeUnwrap()' if you understand and accept the risks.`);
|
241 | }
|
242 | return super.resolve(context);
|
243 | }
|
244 | }
|
245 | exports.SecretValue = SecretValue;
|
246 | _a = JSII_RTTI_SYMBOL_1;
|
247 | SecretValue[_a] = { fqn: "@aws-cdk/core.SecretValue", version: "1.204.0" };
|
248 | const SECRET_VALUE_SYM = Symbol.for('@aws-cdk/core.SecretValue');
|
249 | Object.defineProperty(SecretValue.prototype, SECRET_VALUE_SYM, {
|
250 | value: true,
|
251 | configurable: false,
|
252 | enumerable: false,
|
253 | writable: false,
|
254 | });
|
255 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjcmV0LXZhbHVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2VjcmV0LXZhbHVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDRDQUFxRDtBQUNyRCxtRUFBMEY7QUFFMUYsaURBQTZDO0FBQzdDLG1EQUErQztBQUMvQywyREFBdUQ7QUFDdkQsbURBQWdFO0FBRWhFLG1DQUE4QztBQUU5Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFDSCxNQUFhLFdBQVksU0FBUSxxQkFBUztJQTJIeEM7Ozs7O09BS0c7SUFDSCxZQUFZLGNBQW1CLEVBQUUsT0FBd0I7UUFDdkQsS0FBSyxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQzs7Ozs7OytDQWxJdEIsV0FBVzs7OztRQW1JcEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxjQUFjLENBQUM7S0FDaEM7SUFuSUQ7O09BRUc7SUFDSSxNQUFNLENBQUMsYUFBYSxDQUFDLENBQU07UUFDaEMsT0FBTyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0tBQzFEO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNJLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBYzs7Ozs7Ozs7OztRQUNwQyxPQUFPLElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQ2hDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxNQUFNLENBQUMsZUFBZSxDQUFDLE1BQWM7UUFDMUMsT0FBTyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztLQUNoQztJQUVEOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQWdCLEVBQUUsVUFBdUMsRUFBRTs7Ozs7Ozs7OztRQUN0RixJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1NBQzdDO1FBRUQsSUFBSSxDQUFDLGFBQUss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QUFDO0tBQy9COztBQXZLSCxrQ0F3S0M7OztBQWlDRCxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQztBQUVqRSxNQUFNLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7SUFDN0QsS0FBSyxFQUFFLElBQUk7SUFDWCxZQUFZLEVBQUUsS0FBSztJQUNuQixVQUFVLEVBQUUsS0FBSztJQUNqQixRQUFRLEVBQUUsS0FBSztDQUNoQixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDSEVDS19TRUNSRVRfVVNBR0UgfSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgQ2ZuRHluYW1pY1JlZmVyZW5jZSwgQ2ZuRHluYW1pY1JlZmVyZW5jZVNlcnZpY2UgfSBmcm9tICcuL2Nmbi1keW5hbWljLXJlZmVyZW5jZSc7XG5pbXBvcnQgeyBDZm5QYXJhbWV0ZXIgfSBmcm9tICcuL2Nmbi1wYXJhbWV0ZXInO1xuaW1wb3J0IHsgQ2ZuUmVzb3VyY2UgfSBmcm9tICcuL2Nmbi1yZXNvdXJjZSc7XG5pbXBvcnQgeyBGZWF0dXJlRmxhZ3MgfSBmcm9tICcuL2ZlYXR1cmUtZmxhZ3MnO1xuaW1wb3J0IHsgQ2ZuUmVmZXJlbmNlIH0gZnJvbSAnLi9wcml2YXRlL2Nmbi1yZWZlcmVuY2UnO1xuaW1wb3J0IHsgSW50cmluc2ljLCBJbnRyaW5zaWNQcm9wcyB9IGZyb20gJy4vcHJpdmF0ZS9pbnRyaW5zaWMnO1xuaW1wb3J0IHsgSVJlc29sdmVDb250ZXh0IH0gZnJvbSAnLi9yZXNvbHZhYmxlJztcbmltcG9ydCB7IFRva2VuLCBUb2tlbml6YXRpb24gfSBmcm9tICcuL3Rva2VuJztcblxuLyoqXG4gKiBXb3JrIHdpdGggc2VjcmV0IHZhbHVlcyBpbiB0aGUgQ0RLXG4gKlxuICogQ29uc3RydWN0cyB0aGF0IG5lZWQgc2VjcmV0cyB3aWxsIGRlY2xhcmUgcGFyYW1ldGVycyBvZiB0eXBlIGBTZWNyZXRWYWx1ZWAuXG4gKlxuICogVGhlIGFjdHVhbCB2YWx1ZXMgb2YgdGhlc2Ugc2VjcmV0cyBzaG91bGQgbm90IGJlIGNvbW1pdHRlZCB0byB5b3VyXG4gKiByZXBvc2l0b3J5LCBvciBldmVuIGVuZCB1cCBpbiB0aGUgc3ludGhlc2l6ZWQgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUuIEluc3RlYWQsIHlvdSBzaG91bGRcbiAqIHN0b3JlIHRoZW0gaW4gYW4gZXh0ZXJuYWwgc3lzdGVtIGxpa2UgQVdTIFNlY3JldHMgTWFuYWdlciBvciBTU00gUGFyYW1ldGVyXG4gKiBTdG9yZSwgYW5kIHlvdSBjYW4gcmVmZXJlbmNlIHRoZW0gYnkgY2FsbGluZyBgU2VjcmV0VmFsdWUuc2VjcmV0c01hbmFnZXIoKWAgb3JcbiAqIGBTZWNyZXRWYWx1ZS5zc21TZWN1cmUoKWAuXG4gKlxuICogWW91IGNhbiB1c2UgYFNlY3JldFZhbHVlLnVuc2FmZVBsYWluVGV4dCgpYCB0byBjb25zdHJ1Y3QgYSBgU2VjcmV0VmFsdWVgIGZyb20gYVxuICogbGl0ZXJhbCBzdHJpbmcsIGJ1dCBkb2luZyBzbyBpcyBoaWdobHkgZGlzY291cmFnZWQuXG4gKlxuICogVG8gbWFrZSBzdXJlIHNlY3JldCB2YWx1ZXMgZG9uJ3QgYWNjaWRlbnRhbGx5IGVuZCB1cCBpbiByZWFkYWJsZSBwYXJ0c1xuICogb2YgeW91ciBpbmZyYXN0cnVjdHVyZSBkZWZpbml0aW9uIChzdWNoIGFzIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAqIG9mIGFuIEFXUyBMYW1iZGEgRnVuY3Rpb24sIHdoZXJlIGV2ZXJ5b25lIHdobyBjYW4gcmVhZCB0aGUgZnVuY3Rpb25cbiAqIGRlZmluaXRpb24gaGFzIGFjY2VzcyB0byB0aGUgc2VjcmV0KSwgdXNpbmcgc2VjcmV0IHZhbHVlcyBkaXJlY3RseSBpcyBub3RcbiAqIGFsbG93ZWQuIFlvdSBtdXN0IHBhc3MgdGhlbSB0byBjb25zdHJ1Y3RzIHRoYXQgYWNjZXB0IGBTZWNyZXRWYWx1ZWBcbiAqIHByb3BlcnRpZXMsIHdoaWNoIGFyZSBndWFyYW50ZWVkIHRvIHVzZSB0aGUgdmFsdWUgb25seSBpbiBDbG91ZEZvcm1hdGlvblxuICogcHJvcGVydGllcyB0aGF0IGFyZSB3cml0ZS1vbmx5LlxuICpcbiAqIElmIHlvdSBhcmUgc3VyZSB0aGF0IHdoYXQgeW91IGFyZSBkb2luZyBpcyBzYWZlLCB5b3UgY2FuIGNhbGxcbiAqIGBzZWNyZXRWYWx1ZS51bnNhZmVVbndyYXAoKWAgdG8gYWNjZXNzIHRoZSBwcm90ZWN0ZWQgc3RyaW5nIG9mIHRoZSBzZWNyZXRcbiAqIHZhbHVlLlxuICpcbiAqIChJZiB5b3UgYXJlIHdyaXRpbmcgc29tZXRoaW5nIGxpa2UgYW4gQVdTIExhbWJkYSBGdW5jdGlvbiBhbmQgbmVlZCB0byBhY2Nlc3NcbiAqIGEgc2VjcmV0IGluc2lkZSBpdCwgbWFrZSB0aGUgQVBJIGNhbGwgdG8gYEdldFNlY3JldFZhbHVlYCBkaXJlY3RseSBpbnNpZGVcbiAqIHlvdXIgTGFtYmEncyBjb2RlLCBpbnN0ZWFkIG9mIHVzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlcy4pXG4gKi9cbmV4cG9ydCBjbGFzcyBTZWNyZXRWYWx1ZSBleHRlbmRzIEludHJpbnNpYyB7XG4gIC8qKlxuICAgKiBUZXN0IHdoZXRoZXIgYW4gb2JqZWN0IGlzIGEgU2VjcmV0VmFsdWVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXNTZWNyZXRWYWx1ZSh4OiBhbnkpOiB4IGlzIFNlY3JldFZhbHVlIHtcbiAgICByZXR1cm4gdHlwZW9mIHggPT09ICdvYmplY3QnICYmIHggJiYgeFtTRUNSRVRfVkFMVUVfU1lNXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgYSBsaXRlcmFsIHNlY3JldCB2YWx1ZSBmb3IgdXNlIHdpdGggc2VjcmV0LWF3YXJlIGNvbnN0cnVjdHNcbiAgICpcbiAgICogRG8gbm90IHVzZSB0aGlzIG1ldGhvZCBmb3IgYW55IHNlY3JldHMgdGhhdCB5b3UgY2FyZSBhYm91dCEgVGhlIHZhbHVlXG4gICAqIHdpbGwgYmUgdmlzaWJsZSB0byBhbnlvbmUgd2hvIGhhcyBhY2Nlc3MgdG8gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlXG4gICAqICh2aWEgdGhlIEFXUyBDb25zb2xlLCBTREtzLCBvciBDTEkpLlxuICAgKlxuICAgKiBUaGUgb25seSByZWFzb25hYmxlIHVzZSBjYXNlIGZvciB1c2luZyB0aGlzIG1ldGhvZCBpcyB3aGVuIHlvdSBhcmUgdGVzdGluZy5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgVXNlIGB1bnNhZmVQbGFpblRleHQoKWAgaW5zdGVhZC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcGxhaW5UZXh0KHNlY3JldDogc3RyaW5nKTogU2VjcmV0VmFsdWUge1xuICAgIHJldHVybiBuZXcgU2VjcmV0VmFsdWUoc2VjcmV0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgYSBsaXRlcmFsIHNlY3JldCB2YWx1ZSBmb3IgdXNlIHdpdGggc2VjcmV0LWF3YXJlIGNvbnN0cnVjdHNcbiAgICpcbiAgICogRG8gbm90IHVzZSB0aGlzIG1ldGhvZCBmb3IgYW55IHNlY3JldHMgdGhhdCB5b3UgY2FyZSBhYm91dCEgVGhlIHZhbHVlXG4gICAqIHdpbGwgYmUgdmlzaWJsZSB0byBhbnlvbmUgd2hvIGhhcyBhY2Nlc3MgdG8gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlXG4gICAqICh2aWEgdGhlIEFXUyBDb25zb2xlLCBTREtzLCBvciBDTEkpLlxuICAgKlxuICAgKiBUaGUgb25seSByZWFzb25hYmxlIHVzZSBjYXNlIGZvciB1c2luZyB0aGlzIG1ldGhvZCBpcyB3aGVuIHlvdSBhcmUgdGVzdGluZy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgdW5zYWZlUGxhaW5UZXh0KHNlY3JldDogc3RyaW5nKTogU2VjcmV0VmFsdWUge1xuICAgIHJldHVybiBuZXcgU2VjcmV0VmFsdWUoc2VjcmV0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgYFNlY3JldFZhbHVlYCB3aXRoIGEgdmFsdWUgd2hpY2ggaXMgZHluYW1pY2FsbHkgbG9hZGVkIGZyb20gQVdTIFNlY3JldHMgTWFuYWdlci5cbiAgICogQHBhcmFtIHNlY3JldElkIFRoZSBJRCBvciBBUk4gb2YgdGhlIHNlY3JldFxuICAgKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHNlY3JldHNNYW5hZ2VyKHNlY3JldElkOiBzdHJpbmcsIG9wdGlvbnM6IFNlY3JldHNNYW5hZ2VyU2VjcmV0T3B0aW9ucyA9IHt9KTogU2VjcmV0VmFsdWUge1xuICAgIGlmICghc2VjcmV0SWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignc2VjcmV0SWQgY2Fubm90IGJlIGVtcHR5Jyk7XG4gICAgfVxuXG4gICAgaWYgKCFUb2tlbi5pc1VucmVzb2x2ZWQoc2VjcmV0SWQpICYmICFzZWNyZXRJZC5zdGFydHNXaXRoKCdhcm46JykgJiYgc2VjcmV0SWQuaW5jbHVkZXMoJzonKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBzZWNyZXQgaWQgXCIke3NlY3JldElkfVwiIGlzIG5vdCBhbiBBUk4gYnV0IGNvbnRhaW5zIFwiOlwiYCk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMudmVyc2lvblN0YWdlICYmIG9wdGlvbnMudmVyc2lvbklkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHZlcmlvblN0YWdlOiAnJHtvcHRpb25zLnZlcnNpb25TdGFnZX0nIGFuZCB2ZXJzaW9uSWQ6ICcke29wdGlvbnMudmVyc2lvbklkfScgd2VyZSBib3RoIHByb3ZpZGVkIGJ1dCBvbmx5IG9uZSBpcyBhbGxvd2VkYCk7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydHMgPSBbXG4gICAgICBzZWNyZXRJZCxcbiAgICAgICdTZWNyZXRTdHJpbmcnLFxuICAgICAgb3B0aW9ucy5qc29uRmllbGQgfHwgJycsXG4gICAgICBvcHRpb25zLnZlcnNpb25TdGFnZSB8fCAnJyxcbiAgICAgIG9wdGlvbnMudmVyc2lvbklkIHx8ICcnLFxuICAgIF07XG5cbiAgICBjb25zdCBkeXJlZiA9IG5ldyBDZm5EeW5hbWljUmVmZXJlbmNlKENmbkR5bmFtaWNSZWZlcmVuY2VTZXJ2aWNlLlNFQ1JFVFNfTUFOQUdFUiwgcGFydHMuam9pbignOicpKTtcbiAgICByZXR1cm4gdGhpcy5jZm5EeW5hbWljUmVmZXJlbmNlKGR5cmVmKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgYSBzZWNyZXQgdmFsdWUgc3RvcmVkIGZyb20gYSBTeXN0ZW1zIE1hbmFnZXIgKFNTTSkgcGFyYW1ldGVyLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1ldGVyTmFtZSBUaGUgbmFtZSBvZiB0aGUgcGFyYW1ldGVyIGluIHRoZSBTeXN0ZW1zIE1hbmFnZXJcbiAgICogUGFyYW1ldGVyIFN0b3JlLiBUaGUgcGFyYW1ldGVyIG5hbWUgaXMgY2FzZS1zZW5zaXRpdmUuXG4gICAqXG4gICAqIEBwYXJhbSB2ZXJzaW9uIEFuIGludGVnZXIgdGhhdCBzcGVjaWZpZXMgdGhlIHZlcnNpb24gb2YgdGhlIHBhcmFtZXRlciB0b1xuICAgKiB1c2UuIElmIHlvdSBkb24ndCBzcGVjaWZ5IHRoZSBleGFjdCB2ZXJzaW9uLCBBV1MgQ2xvdWRGb3JtYXRpb24gdXNlcyB0aGVcbiAgICogbGF0ZXN0IHZlcnNpb24gb2YgdGhlIHBhcmFtZXRlci5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3NtU2VjdXJlKHBhcmFtZXRlck5hbWU6IHN0cmluZywgdmVyc2lvbj86IHN0cmluZyk6IFNlY3JldFZhbHVlIHtcbiAgICByZXR1cm4gdGhpcy5jZm5EeW5hbWljUmVmZXJlbmNlKFxuICAgICAgbmV3IENmbkR5bmFtaWNSZWZlcmVuY2UoQ2ZuRHluYW1pY1JlZmVyZW5jZVNlcnZpY2UuU1NNX1NFQ1VSRSxcbiAgICAgICAgdmVyc2lvbiA/IGAke3BhcmFtZXRlck5hbWV9OiR7dmVyc2lvbn1gIDogcGFyYW1ldGVyTmFtZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGFpbiB0aGUgc2VjcmV0IHZhbHVlIHRocm91Z2ggYSBDbG91ZEZvcm1hdGlvbiBkeW5hbWljIHJlZmVyZW5jZS5cbiAgICpcbiAgICogSWYgcG9zc2libGUsIHVzZSBgU2VjcmV0VmFsdWUuc3NtU2VjdXJlYCBvciBgU2VjcmV0VmFsdWUuc2VjcmV0c01hbmFnZXJgIGRpcmVjdGx5LlxuICAgKlxuICAgKiBAcGFyYW0gcmVmIFRoZSBkeW5hbWljIHJlZmVyZW5jZSB0byB1c2UuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNmbkR5bmFtaWNSZWZlcmVuY2UocmVmOiBDZm5EeW5hbWljUmVmZXJlbmNlKSB7XG4gICAgcmV0dXJuIG5ldyBTZWNyZXRWYWx1ZShyZWYpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGFpbiB0aGUgc2VjcmV0IHZhbHVlIHRocm91Z2ggYSBDbG91ZEZvcm1hdGlvbiBwYXJhbWV0ZXIuXG4gICAqXG4gICAqIEdlbmVyYWxseSwgdGhpcyBpcyBub3QgYSByZWNvbW1lbmRlZCBhcHByb2FjaC4gQVdTIFNlY3JldHMgTWFuYWdlciBpcyB0aGVcbiAgICogcmVjb21tZW5kZWQgd2F5IHRvIHJlZmVyZW5jZSBzZWNyZXRzLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW0gVGhlIENsb3VkRm9ybWF0aW9uIHBhcmFtZXRlciB0byB1c2UuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNmblBhcmFtZXRlcihwYXJhbTogQ2ZuUGFyYW1ldGVyKSB7XG4gICAgaWYgKCFwYXJhbS5ub0VjaG8pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2xvdWRGb3JtYXRpb24gcGFyYW1ldGVyIG11c3QgYmUgY29uZmlndXJlZCB3aXRoIFwiTm9FY2hvXCInKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFNlY3JldFZhbHVlKHBhcmFtLnZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgYSByZXNvdXJjZSdzIG91dHB1dCBhcyBzZWNyZXQgdmFsdWVcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcmVzb3VyY2VBdHRyaWJ1dGUoYXR0cjogc3RyaW5nKSB7XG4gICAgY29uc3QgcmVzb2x2ZWQgPSBUb2tlbml6YXRpb24ucmV2ZXJzZUNvbXBsZXRlU3RyaW5nKGF0dHIpO1xuICAgIGlmICghcmVzb2x2ZWQgfHwgIUNmblJlZmVyZW5jZS5pc0NmblJlZmVyZW5jZShyZXNvbHZlZCkgfHwgIUNmblJlc291cmNlLmlzQ2ZuUmVzb3VyY2UocmVzb2x2ZWQudGFyZ2V0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdTZWNyZXRWYWx1ZS5yZXNvdXJjZUF0dHJpYnV0ZSgpIG11c3QgYmUgdXNlZCB3aXRoIGEgcmVzb3VyY2UgYXR0cmlidXRlJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBTZWNyZXRWYWx1ZShhdHRyKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVhZG9ubHkgcmF3VmFsdWU6IGFueTtcblxuICAvKipcbiAgICogQ29uc3RydWN0IGEgU2VjcmV0VmFsdWUgKGRvIG5vdCB1c2UhKVxuICAgKlxuICAgKiBEbyBub3QgdXNlIHRoZSBjb25zdHJ1Y3RvciBkaXJlY3RseTogdXNlIG9uZSBvZiB0aGUgZmFjdG9yeSBmdW5jdGlvbnMgb24gdGhlIGNsYXNzXG4gICAqIGluc3RlYWQuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWRWYWx1ZTogYW55LCBvcHRpb25zPzogSW50cmluc2ljUHJvcHMpIHtcbiAgICBzdXBlcihwcm90ZWN0ZWRWYWx1ZSwgb3B0aW9ucyk7XG4gICAgdGhpcy5yYXdWYWx1ZSA9IHByb3RlY3RlZFZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIERpc2FibGUgdXNhZ2UgcHJvdGVjdGlvbiBvbiB0aGlzIHNlY3JldFxuICAgKlxuICAgKiBDYWxsIHRoaXMgdG8gaW5kaWNhdGUgdGhhdCB5b3Ugd2FudCB0byB1c2UgdGhlIHNlY3JldCB2YWx1ZSBoZWxkIGJ5IHRoaXNcbiAgICogb2JqZWN0IGluIGFuIHVuY2hlY2tlZCB3YXkuIElmIHlvdSBkb24ndCBjYWxsIHRoaXMgbWV0aG9kLCB1c2luZyB0aGUgc2VjcmV0XG4gICAqIHZhbHVlIGRpcmVjdGx5IGluIGEgc3RyaW5nIGNvbnRleHQgb3IgYXMgYSBwcm9wZXJ0eSB2YWx1ZSBzb21ld2hlcmUgd2lsbFxuICAgKiBwcm9kdWNlIGFuIGVycm9yLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBoYXMgJ3Vuc2FmZScgaW4gdGhlIG5hbWUgb24gcHVycG9zZSEgTWFrZSBzdXJlIHRoYXQgdGhlXG4gICAqIGNvbnN0cnVjdCBwcm9wZXJ0eSB5b3UgYXJlIHVzaW5nIHRoZSByZXR1cm5lZCB2YWx1ZSBpbiBpcyBkb2VzIG5vdCBlbmQgdXBcbiAgICogaW4gYSBwbGFjZSBpbiB5b3VyIEFXUyBpbmZyYXN0cnVjdHVyZSB3aGVyZSBpdCBjb3VsZCBiZSByZWFkIGJ5IGFueW9uZVxuICAgKiB1bmV4cGVjdGVkLlxuICAgKlxuICAgKiBXaGVuIGluIGRvdWJ0LCBkb24ndCBjYWxsIHRoaXMgbWV0aG9kIGFuZCBvbmx5IHBhc3MgdGhlIG9iamVjdCB0byBjb25zdHJ1Y3RzIHRoYXRcbiAgICogYWNjZXB0IGBTZWNyZXRWYWx1ZWAgcGFyYW1ldGVycy5cbiAgICovXG4gIHB1YmxpYyB1bnNhZmVVbndyYXAoKSB7XG4gICAgcmV0dXJuIFRva2VuLmFzU3RyaW5nKHRoaXMucmF3VmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgdGhlIHNlY3JldFxuICAgKlxuICAgKiBJZiB0aGUgZmVhdHVyZSBmbGFnIGlzIG5vdCBzZXQsIHJlc29sdmUgYXMgbm9ybWFsLiBPdGhlcndpc2UsIHRocm93IGEgZGVzY3JpcHRpdmVcbiAgICogZXJyb3IgdGhhdCB0aGUgdXNhZ2UgZ3VhcmQgaXMgbWlzc2luZy5cbiAgICovXG4gIHB1YmxpYyByZXNvbHZlKGNvbnRleHQ6IElSZXNvbHZlQ29udGV4dCkge1xuICAgIGlmIChGZWF0dXJlRmxhZ3Mub2YoY29udGV4dC5zY29wZSkuaXNFbmFibGVkKENIRUNLX1NFQ1JFVF9VU0FHRSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFN5bnRoaW5nIGEgc2VjcmV0IHZhbHVlIHRvICR7Y29udGV4dC5kb2N1bWVudFBhdGguam9pbignLycpfS4gVXNpbmcgYSBTZWNyZXRWYWx1ZSBoZXJlIHJpc2tzIGV4cG9zaW5nIHlvdXIgc2VjcmV0LiBPbmx5IHBhc3MgU2VjcmV0VmFsdWVzIHRvIGNvbnN0cnVjdHMgdGhhdCBhY2NlcHQgYSBTZWNyZXRWYWx1ZSBwcm9wZXJ0eSwgb3IgY2FsbCBBV1MgU2VjcmV0cyBNYW5hZ2VyIGRpcmVjdGx5IGluIHlvdXIgcnVudGltZSBjb2RlLiBDYWxsICdzZWNyZXRWYWx1ZS51bnNhZmVVbndyYXAoKScgaWYgeW91IHVuZGVyc3RhbmQgYW5kIGFjY2VwdCB0aGUgcmlza3MuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBzdXBlci5yZXNvbHZlKGNvbnRleHQpO1xuICB9XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgcmVmZXJlbmNpbmcgYSBzZWNyZXQgdmFsdWUgZnJvbSBTZWNyZXRzIE1hbmFnZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VjcmV0c01hbmFnZXJTZWNyZXRPcHRpb25zIHtcbiAgLyoqXG4gICAqIFNwZWNpZmllcyB0aGUgc2VjcmV0IHZlcnNpb24gdGhhdCB5b3Ugd2FudCB0byByZXRyaWV2ZSBieSB0aGUgc3RhZ2luZyBsYWJlbCBhdHRhY2hlZCB0byB0aGUgdmVyc2lvbi5cbiAgICpcbiAgICogQ2FuIHNwZWNpZnkgYXQgbW9zdCBvbmUgb2YgYHZlcnNpb25JZGAgYW5kIGB2ZXJzaW9uU3RhZ2VgLlxuICAgKlxuICAgKiBAZGVmYXVsdCBBV1NDVVJSRU5UXG4gICAqL1xuICByZWFkb25seSB2ZXJzaW9uU3RhZ2U/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB0aGUgdW5pcXVlIGlkZW50aWZpZXIgb2YgdGhlIHZlcnNpb24gb2YgdGhlIHNlY3JldCB5b3Ugd2FudCB0byB1c2UuXG4gICAqXG4gICAqIENhbiBzcGVjaWZ5IGF0IG1vc3Qgb25lIG9mIGB2ZXJzaW9uSWRgIGFuZCBgdmVyc2lvblN0YWdlYC5cbiAgICpcbiAgICogQGRlZmF1bHQgQVdTQ1VSUkVOVFxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbklkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUga2V5IG9mIGEgSlNPTiBmaWVsZCB0byByZXRyaWV2ZS4gVGhpcyBjYW4gb25seSBiZSB1c2VkIGlmIHRoZSBzZWNyZXRcbiAgICogc3RvcmVzIGEgSlNPTiBvYmplY3QuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcmV0dXJucyBhbGwgdGhlIGNvbnRlbnQgc3RvcmVkIGluIHRoZSBTZWNyZXRzIE1hbmFnZXIgc2VjcmV0LlxuICAgKi9cbiAgcmVhZG9ubHkganNvbkZpZWxkPzogc3RyaW5nO1xufVxuXG5jb25zdCBTRUNSRVRfVkFMVUVfU1lNID0gU3ltYm9sLmZvcignQGF3cy1jZGsvY29yZS5TZWNyZXRWYWx1ZScpO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoU2VjcmV0VmFsdWUucHJvdG90eXBlLCBTRUNSRVRfVkFMVUVfU1lNLCB7XG4gIHZhbHVlOiB0cnVlLFxuICBjb25maWd1cmFibGU6IGZhbHNlLFxuICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgd3JpdGFibGU6IGZhbHNlLFxufSk7Il19 |
\ | No newline at end of file |