@pipeline-builder/api-core 3.4.35 → 3.4.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,388 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.PerOrgKmsKeyProvider = exports.KmsKeyProvider = exports.EnvKeyProvider = void 0;
6
+ exports.getDefaultKeyProvider = getDefaultKeyProvider;
7
+ exports.resetDefaultKeyProvider = resetDefaultKeyProvider;
8
+ exports.setKeyProvider = setKeyProvider;
9
+ exports.encryptSecret = encryptSecret;
10
+ exports.decryptSecret = decryptSecret;
11
+ exports.isEncryptedBlob = isEncryptedBlob;
12
+ /**
13
+ * Per-org envelope encryption for secret columns.
14
+ *
15
+ * Today's posture for org-scoped secrets (aiProviderKeys, webhook URLs,
16
+ * registry credentials) is clear-text in Mongo / Postgres with app-layer
17
+ * masking on output. This module is the encryption primitive that lets the
18
+ * model layer swap clear-text strings for `EncryptedBlob` values at write
19
+ * time and decrypt at read time.
20
+ *
21
+ * Cryptography * - AES-256-GCM (authenticated encryption).
22
+ * - Per-org key derived via HKDF-SHA256(masterKey, salt=orgId, info='secrets-v1').
23
+ * Each org gets a unique key without operator key-management ceremony.
24
+ * - 12-byte IV generated per encryption with `crypto.randomBytes`.
25
+ * - 16-byte authentication tag concatenated with ciphertext (standard GCM).
26
+ *
27
+ * Operator configuration * - `SECRET_ENCRYPTION_KEY` env: hex- or base64-encoded 32-byte master key.
28
+ * Required when `encryptSecret`/`decryptSecret` are called. Missing key
29
+ * throws encryption is fail-closed; we never silently round-trip a
30
+ * secret as plaintext.
31
+ *
32
+ * KMS migration path * - The two exported functions take a `provider` parameter. The default
33
+ * `EnvKeyProvider` implements HKDF derivation. A future `AwsKmsProvider`
34
+ * plugs in here: it can call KMS `Encrypt` / `Decrypt` to wrap a DEK
35
+ * rather than holding a master key in env. The on-disk blob shape
36
+ * (`{ alg, iv, ciphertext, kid? }`) is forward-compatible `kid`
37
+ * carries the KMS key id when the provider needs it.
38
+ */
39
+ const crypto_1 = require("crypto");
40
+ /**
41
+ * Default provider derives a per-org key from `SECRET_ENCRYPTION_KEY` via
42
+ * HKDF-SHA256. Suitable for self-hosted / dev where operators don't have KMS.
43
+ *
44
+ * Fails fast if the env is missing or the key is the wrong length so misconfig
45
+ * surfaces at first use rather than silently fingerprinting all writes with
46
+ * a default zero key.
47
+ */
48
+ class EnvKeyProvider {
49
+ masterKey;
50
+ constructor(masterKeyOverride) {
51
+ const raw = masterKeyOverride ?? process.env.SECRET_ENCRYPTION_KEY;
52
+ if (!raw) {
53
+ throw new Error('SECRET_ENCRYPTION_KEY env is required for secret encryption');
54
+ }
55
+ // Accept either hex (64 chars) or base64 (44 chars including padding) for
56
+ // operator convenience both decode to a 32-byte key.
57
+ const decoded = raw.length === 64 && /^[0-9a-f]+$/i.test(raw)
58
+ ? Buffer.from(raw, 'hex')
59
+ : Buffer.from(raw, 'base64');
60
+ if (decoded.length !== 32) {
61
+ throw new Error(`SECRET_ENCRYPTION_KEY must decode to 32 bytes (got ${decoded.length})`);
62
+ }
63
+ this.masterKey = decoded;
64
+ }
65
+ deriveKey(orgId) {
66
+ // HKDF binds the master key to the org so two orgs encrypting the same
67
+ // plaintext produce different ciphertexts keeps a stolen DB unable to
68
+ // tell which orgs share secrets via ciphertext comparison.
69
+ const derived = (0, crypto_1.hkdfSync)('sha256', this.masterKey, Buffer.from(orgId, 'utf8'), 'secrets-v1', 32);
70
+ // hkdfSync returns ArrayBuffer in older Node typings; normalize to Buffer.
71
+ return Buffer.from(derived);
72
+ }
73
+ }
74
+ exports.EnvKeyProvider = EnvKeyProvider;
75
+ /**
76
+ * AWS-KMS-backed KeyProvider.
77
+ *
78
+ * Trade-off picked: store ONE master key encrypted under a KMS CMK; on
79
+ * first use, call `kms:Decrypt` to recover the master key bytes; HKDF-
80
+ * derive per-org from it (same as EnvKeyProvider). The process then holds
81
+ * the plaintext master key in memory until restart.
82
+ *
83
+ * PROS: one KMS call per process lifetime (cheap, low p99 impact),
84
+ * the encrypted-master-key blob is safe to commit/log/checkin,
85
+ * KMS audit log records when the master is recovered.
86
+ * CONS: process memory still holds the master key same posture as
87
+ * EnvKeyProvider once warmed up. For stronger isolation an
88
+ * operator can move to per-record envelope encryption (call
89
+ * GenerateDataKey on every write); that's a follow-on.
90
+ *
91
+ * Operator setup * 1. Create a KMS CMK with key policy allowing the platform service's
92
+ * IAM role kms:Decrypt.
93
+ * 2. Generate a random 32-byte master * head -c 32 /dev/urandom | base64
94
+ * 3. Wrap it with KMS * aws kms encrypt --key-id <KEY_ID> \
95
+ * --plaintext <base64-from-step-2> --output text \
96
+ * --query CiphertextBlob
97
+ * 4. Set on the service * SECRET_ENCRYPTION_KMS_KEY_ID=<KEY_ID>
98
+ * SECRET_ENCRYPTION_KMS_CIPHERTEXT=<base64-output-of-step-3>
99
+ * 5. Pick this provider via `setKeyProvider(new KmsKeyProvider())`.
100
+ *
101
+ * Construct lazily importing the AWS SDK has a non-trivial cold-start
102
+ * cost so envs that stay on EnvKeyProvider never load it.
103
+ */
104
+ class KmsKeyProvider {
105
+ masterKeyCache = null;
106
+ keyId;
107
+ ciphertextB64;
108
+ region;
109
+ endpoint;
110
+ decryptInFlight = null;
111
+ constructor(opts) {
112
+ const keyId = opts?.keyId ?? process.env.SECRET_ENCRYPTION_KMS_KEY_ID;
113
+ const ciphertext = opts?.ciphertextBase64 ?? process.env.SECRET_ENCRYPTION_KMS_CIPHERTEXT;
114
+ if (!keyId)
115
+ throw new Error('SECRET_ENCRYPTION_KMS_KEY_ID env is required for KmsKeyProvider');
116
+ if (!ciphertext)
117
+ throw new Error('SECRET_ENCRYPTION_KMS_CIPHERTEXT env is required for KmsKeyProvider');
118
+ this.keyId = keyId;
119
+ this.ciphertextB64 = ciphertext;
120
+ this.region = opts?.region ?? process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION;
121
+ this.endpoint = opts?.endpoint ?? process.env.AWS_KMS_ENDPOINT;
122
+ }
123
+ deriveKey(orgId) {
124
+ if (!this.masterKeyCache) {
125
+ throw new Error('KmsKeyProvider is not warmed up. Call `await provider.warmup()` once at service startup before any encrypt/decrypt.');
126
+ }
127
+ const derived = (0, crypto_1.hkdfSync)('sha256', this.masterKeyCache, Buffer.from(orgId, 'utf8'), 'secrets-v1', 32);
128
+ return Buffer.from(derived);
129
+ }
130
+ /**
131
+ * Eagerly recover the master key from KMS so subsequent `deriveKey`
132
+ * calls are sync. Idempotent concurrent callers share the same in-
133
+ * flight promise so we don't spawn multiple KMS Decrypt requests at
134
+ * boot. Throws on any KMS failure; the caller (typically the service's
135
+ * onBeforeStart hook) decides whether to fall back to a different
136
+ * provider or fail-startup.
137
+ */
138
+ async warmup() {
139
+ if (this.masterKeyCache)
140
+ return;
141
+ if (!this.decryptInFlight) {
142
+ this.decryptInFlight = this.fetchAndDecrypt();
143
+ }
144
+ this.masterKeyCache = await this.decryptInFlight;
145
+ }
146
+ async fetchAndDecrypt() {
147
+ // Dynamic import so EnvKeyProvider-only envs don't load the SDK.
148
+ const { KMSClient, DecryptCommand } = await import('@aws-sdk/client-kms');
149
+ const client = new KMSClient({
150
+ region: this.region,
151
+ ...(this.endpoint ? { endpoint: this.endpoint } : {}),
152
+ });
153
+ const resp = await client.send(new DecryptCommand({
154
+ KeyId: this.keyId,
155
+ CiphertextBlob: Buffer.from(this.ciphertextB64, 'base64'),
156
+ }));
157
+ if (!resp.Plaintext) {
158
+ throw new Error('KMS Decrypt returned an empty Plaintext');
159
+ }
160
+ const buf = Buffer.from(resp.Plaintext);
161
+ if (buf.length !== 32) {
162
+ throw new Error(`KMS Decrypt returned ${buf.length}-byte key; expected 32`);
163
+ }
164
+ return buf;
165
+ }
166
+ }
167
+ exports.KmsKeyProvider = KmsKeyProvider;
168
+ // Lazy singleton operator code in long-lived services pays the env-parse
169
+ // cost once, and tests can mint their own provider with a literal key.
170
+ let defaultProvider = null;
171
+ function getDefaultProvider() {
172
+ if (!defaultProvider)
173
+ defaultProvider = new EnvKeyProvider();
174
+ return defaultProvider;
175
+ }
176
+ /** Read the active default provider. Exposed so service code (e.g. an
177
+ * admin endpoint that just rotated an org's KMS config) can call
178
+ * `provider.evict(orgId)` on the live provider rather than reconstructing
179
+ * one. Triggers lazy initialization on first access, same as the internal
180
+ * callers below. */
181
+ function getDefaultKeyProvider() {
182
+ return getDefaultProvider();
183
+ }
184
+ /** Reset the cached default provider for tests that mutate `process.env`. */
185
+ function resetDefaultKeyProvider() { defaultProvider = null; }
186
+ /** Replace the default provider services that opt into KMS call this
187
+ * once at startup with a warmed-up `KmsKeyProvider`. */
188
+ function setKeyProvider(provider) { defaultProvider = provider; }
189
+ /**
190
+ * Per-org KMS-backed KeyProvider. The blast radius of a KMS key compromise
191
+ * is one org instead of every org under a shared master.
192
+ *
193
+ * Each org has its own KMS CMK + its own wrapped master (stored in Mongo
194
+ * via the operator's setup script). On first encrypt/decrypt for an org,
195
+ * the provider:
196
+ * 1. Calls the resolver to fetch the org's KMS config.
197
+ * 2. Calls `kms:Decrypt` to recover the 32-byte master.
198
+ * 3. Caches the recovered master in-memory for the process lifetime.
199
+ * 4. HKDF-derives per-call from that master + the org id salt.
200
+ *
201
+ * Blobs encrypted by this provider carry `kid = <kms-key-id>` so the
202
+ * decrypt path detects a stale config (operator rotated the key but
203
+ * existing rows weren't re-encrypted) BEFORE AES-GCM throws an opaque
204
+ * authentication-tag error.
205
+ *
206
+ * Orgs without per-org config fall through to the `fallback` provider —
207
+ * mixed-mode deployments where some orgs have KMS isolation and others
208
+ * stay on the shared master are explicitly supported.
209
+ */
210
+ class PerOrgKmsKeyProvider {
211
+ /** Cached per-org master keys, keyed by orgId. */
212
+ masters = new Map();
213
+ /** Resolved per-org configs cached for the process lifetime. */
214
+ configs = new Map();
215
+ /** In-flight resolver promises so concurrent first-touch callers share one KMS Decrypt.
216
+ * Resolves to `null` for orgs with no per-org config — caller treats null as
217
+ * "fall through to the fallback provider", same as a cold cache miss. */
218
+ inFlight = new Map();
219
+ /** Provider used for orgs that have no per-org config. */
220
+ fallback;
221
+ resolver;
222
+ region;
223
+ endpoint;
224
+ constructor(opts) {
225
+ this.resolver = opts.resolver;
226
+ this.fallback = opts.fallback;
227
+ this.region = opts.region ?? process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION;
228
+ this.endpoint = opts.endpoint ?? process.env.AWS_KMS_ENDPOINT;
229
+ }
230
+ /** Sync `deriveKey` only works for already-warmed orgs. Cold orgs fall
231
+ * through to the fallback provider. Callers that want per-org isolation
232
+ * MUST `await deriveKeyAsync(orgId)` once first (e.g. during request setup
233
+ * or as part of a warmup pass) — otherwise the org silently uses the
234
+ * shared master. */
235
+ deriveKey(orgId) {
236
+ const cached = this.masters.get(orgId);
237
+ if (!cached)
238
+ return this.fallback.deriveKey(orgId);
239
+ const derived = (0, crypto_1.hkdfSync)('sha256', cached.key, Buffer.from(orgId, 'utf8'), 'secrets-v1', 32);
240
+ return Buffer.from(derived);
241
+ }
242
+ async deriveKeyAsync(orgId) {
243
+ await this.ensureWarmed(orgId);
244
+ return this.deriveKey(orgId);
245
+ }
246
+ kidFor(orgId) {
247
+ return this.masters.get(orgId)?.kid ?? this.fallback.kidFor?.(orgId);
248
+ }
249
+ /**
250
+ * Resolve the org's KMS config, call Decrypt, cache the master. Subsequent
251
+ * calls for the same org are no-ops. Concurrent callers share the in-flight
252
+ * Decrypt promise.
253
+ *
254
+ * Returns silently when the org has no per-org config — the fallback
255
+ * provider handles those orgs.
256
+ */
257
+ async ensureWarmed(orgId) {
258
+ if (this.masters.has(orgId))
259
+ return;
260
+ // Install the in-flight promise SYNCHRONOUSLY before yielding so concurrent
261
+ // callers find it on the second-and-later passes. Awaiting the resolver
262
+ // before populating the map is the bug that lets a Promise.all of 3
263
+ // callers fire 3 KMS Decrypts.
264
+ let promise = this.inFlight.get(orgId);
265
+ if (!promise) {
266
+ promise = this.resolveAndDecrypt(orgId);
267
+ this.inFlight.set(orgId, promise);
268
+ void promise.finally(() => { if (this.inFlight.get(orgId) === promise)
269
+ this.inFlight.delete(orgId); });
270
+ }
271
+ const result = await promise;
272
+ if (result)
273
+ this.masters.set(orgId, result);
274
+ }
275
+ async resolveAndDecrypt(orgId) {
276
+ let cfg = this.configs.get(orgId);
277
+ if (!cfg) {
278
+ const resolved = await this.resolver(orgId);
279
+ if (!resolved)
280
+ return null; // no per-org config → caller uses fallback
281
+ cfg = resolved;
282
+ this.configs.set(orgId, cfg);
283
+ }
284
+ const key = await this.fetchAndDecrypt(cfg);
285
+ return { key, kid: cfg.keyId };
286
+ }
287
+ async fetchAndDecrypt(cfg) {
288
+ const { KMSClient, DecryptCommand } = await import('@aws-sdk/client-kms');
289
+ const client = new KMSClient({
290
+ region: this.region,
291
+ ...(this.endpoint ? { endpoint: this.endpoint } : {}),
292
+ });
293
+ const resp = await client.send(new DecryptCommand({
294
+ KeyId: cfg.keyId,
295
+ CiphertextBlob: Buffer.from(cfg.ciphertextBase64, 'base64'),
296
+ }));
297
+ if (!resp.Plaintext)
298
+ throw new Error(`KMS Decrypt returned empty Plaintext for key ${cfg.keyId}`);
299
+ const buf = Buffer.from(resp.Plaintext);
300
+ if (buf.length !== 32)
301
+ throw new Error(`KMS Decrypt returned ${buf.length}-byte key for ${cfg.keyId}; expected 32`);
302
+ return buf;
303
+ }
304
+ /** Evict a cached per-org master. Use after a key rotation so the next
305
+ * touch re-fetches the new wrapped master from the resolver. */
306
+ evict(orgId) {
307
+ this.masters.delete(orgId);
308
+ this.configs.delete(orgId);
309
+ }
310
+ }
311
+ exports.PerOrgKmsKeyProvider = PerOrgKmsKeyProvider;
312
+ /**
313
+ * Encrypt a plaintext string for storage. Returns an `EncryptedBlob` that
314
+ * can be JSON-serialized into the underlying column / Mongo document.
315
+ *
316
+ * Empty strings round-trip as `null` so the calling model layer can treat
317
+ * "no secret set" identically to "field absent".
318
+ */
319
+ function encryptSecret(plaintext, orgId, provider = getDefaultProvider()) {
320
+ if (!plaintext) {
321
+ throw new Error('Refusing to encrypt empty string; caller should store null instead');
322
+ }
323
+ const key = provider.deriveKey(orgId);
324
+ const iv = (0, crypto_1.randomBytes)(12);
325
+ const cipher = (0, crypto_1.createCipheriv)('aes-256-gcm', key, iv);
326
+ const enc = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
327
+ const tag = cipher.getAuthTag();
328
+ // PerOrgKmsKeyProvider tags blobs with the KMS key id used so the
329
+ // decrypt path can refuse to operate if the operator later swaps in a
330
+ // different per-org config (a misconfigured swap shouldn't silently
331
+ // accept a stale blob it can't verify against the right CMK).
332
+ const kid = provider.kidFor?.(orgId);
333
+ return {
334
+ alg: 'aes-256-gcm-v1',
335
+ iv: iv.toString('base64'),
336
+ // GCM tag MUST travel with the ciphertext or `decryptSecret` can't
337
+ // verify integrity concatenate so the on-disk shape is one field.
338
+ ciphertext: Buffer.concat([enc, tag]).toString('base64'),
339
+ ...(kid !== undefined ? { kid } : {}),
340
+ };
341
+ }
342
+ /**
343
+ * Decrypt an `EncryptedBlob` written by `encryptSecret`. Throws on * - unknown `alg` (forces an explicit migration when the format changes)
344
+ * - wrong orgId (HKDF binding mismatch fails the auth tag)
345
+ * - tampered ciphertext (GCM auth tag check fails)
346
+ *
347
+ * Callers handle the throw masking the failure as `null` would hide
348
+ * silent corruption / wrong-org reads.
349
+ */
350
+ function decryptSecret(blob, orgId, provider = getDefaultProvider()) {
351
+ if (blob.alg !== 'aes-256-gcm-v1') {
352
+ throw new Error(`Unsupported encryption alg: ${blob.alg}`);
353
+ }
354
+ // If both the provider AND the blob report a kid, they must match.
355
+ // Mismatch usually means an operator rotated/replaced an org's KMS
356
+ // config and is now reading a blob encrypted under the OLD key —
357
+ // failing loud here beats letting AES-GCM throw an opaque auth-tag error.
358
+ const providerKid = provider.kidFor?.(orgId);
359
+ if (providerKid !== undefined && blob.kid !== undefined && providerKid !== blob.kid) {
360
+ throw new Error(`KMS key id mismatch: blob was encrypted under ${blob.kid}, current provider uses ${providerKid} for org ${orgId}`);
361
+ }
362
+ const key = provider.deriveKey(orgId);
363
+ const iv = Buffer.from(blob.iv, 'base64');
364
+ const all = Buffer.from(blob.ciphertext, 'base64');
365
+ // Split off the 16-byte auth tag appended in encryptSecret. Any tampering
366
+ // to either the ciphertext OR the tag causes the next `final()` to
367
+ // throw with "Unsupported state or unable to authenticate data".
368
+ const tag = all.subarray(all.length - 16);
369
+ const enc = all.subarray(0, all.length - 16);
370
+ const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', key, iv);
371
+ decipher.setAuthTag(tag);
372
+ const dec = Buffer.concat([decipher.update(enc), decipher.final()]);
373
+ return dec.toString('utf8');
374
+ }
375
+ /**
376
+ * Type guard handy for model layers that hold a column whose value may be
377
+ * either a clear-text string (legacy / unencrypted) OR an encrypted blob
378
+ * (post-migration). Mixed states arise mid-migration; the model decides
379
+ * what to do (decrypt on read, encrypt on next write).
380
+ */
381
+ function isEncryptedBlob(value) {
382
+ return (typeof value === 'object'
383
+ && value !== null
384
+ && value.alg === 'aes-256-gcm-v1'
385
+ && typeof value.iv === 'string'
386
+ && typeof value.ciphertext === 'string');
387
+ }
388
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjcmV0LWVuY3J5cHRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvc2VjcmV0LWVuY3J5cHRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7OztBQWlOdEMsc0RBRUM7QUFHRCwwREFBMkU7QUFJM0Usd0NBQTJGO0FBMEozRixzQ0F5QkM7QUFVRCxzQ0EyQkM7QUFRRCwwQ0FPQztBQS9iRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQkc7QUFFSCxtQ0FBaUY7QUE2QmpGOzs7Ozs7O0dBT0c7QUFDSCxNQUFhLGNBQWM7SUFDUixTQUFTLENBQVM7SUFFbkMsWUFBWSxpQkFBMEI7UUFDcEMsTUFBTSxHQUFHLEdBQUcsaUJBQWlCLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQztRQUNuRSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDVCxNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7UUFDakYsQ0FBQztRQUNELDBFQUEwRTtRQUMxRSxzREFBc0Q7UUFDdEQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLE1BQU0sS0FBSyxFQUFFLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDM0QsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQztZQUN6QixDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDL0IsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0RBQXNELE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQzNGLENBQUM7UUFDRCxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQztJQUMzQixDQUFDO0lBRUQsU0FBUyxD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LEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEUsT0FBTyxHQUFHLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQzlCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxLQUFjO0lBQzVDLE9BQU8sQ0FBRSxPQUFPLEtBQUssS0FBSyxRQUFRO1dBQzdCLEtBQUssS0FBSyxJQUFJO1dBQ2IsS0FBMkIsQ0FBQyxHQUFHLEtBQUssZ0JBQWdCO1dBQ3JELE9BQVEsS0FBMEIsQ0FBQyxFQUFFLEtBQUssUUFBUTtXQUNsRCxPQUFRLEtBQWtDLENBQUMsVUFBVSxLQUFLLFFBQVEsQ0FDdEUsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiAgUGVyLW9yZyBlbnZlbG9wZSBlbmNyeXB0aW9uIGZvciBzZWNyZXQgY29sdW1ucy5cbiAqXG4gKiBUb2RheSdzIHBvc3R1cmUgZm9yIG9yZy1zY29wZWQgc2VjcmV0cyAoYWlQcm92aWRlcktleXMsIHdlYmhvb2sgVVJMcyxcbiAqIHJlZ2lzdHJ5IGNyZWRlbnRpYWxzKSBpcyBjbGVhci10ZXh0IGluIE1vbmdvIC8gUG9zdGdyZXMgd2l0aCBhcHAtbGF5ZXJcbiAqIG1hc2tpbmcgb24gb3V0cHV0LiBUaGlzIG1vZHVsZSBpcyB0aGUgZW5jcnlwdGlvbiBwcmltaXRpdmUgdGhhdCBsZXRzIHRoZVxuICogbW9kZWwgbGF5ZXIgc3dhcCBjbGVhci10ZXh0IHN0cmluZ3MgZm9yIGBFbmNyeXB0ZWRCbG9iYCB2YWx1ZXMgYXQgd3JpdGVcbiAqIHRpbWUgYW5kIGRlY3J5cHQgYXQgcmVhZCB0aW1lLlxuICpcbiAqIENyeXB0b2dyYXBoeSAqIC0gQUVTLTI1Ni1HQ00gKGF1dGhlbnRpY2F0ZWQgZW5jcnlwdGlvbikuXG4gKiAtIFBlci1vcmcga2V5IGRlcml2ZWQgdmlhIEhLREYtU0hBMjU2KG1hc3RlcktleSwgc2FsdD1vcmdJZCwgaW5mbz0nc2VjcmV0cy12MScpLlxuICogRWFjaCBvcmcgZ2V0cyBhIHVuaXF1ZSBrZXkgd2l0aG91dCBvcGVyYXRvciBrZXktbWFuYWdlbWVudCBjZXJlbW9ueS5cbiAqIC0gMTItYnl0ZSBJViBnZW5lcmF0ZWQgcGVyIGVuY3J5cHRpb24gd2l0aCBgY3J5cHRvLnJhbmRvbUJ5dGVzYC5cbiAqIC0gMTYtYnl0ZSBhdXRoZW50aWNhdGlvbiB0YWcgY29uY2F0ZW5hdGVkIHdpdGggY2lwaGVydGV4dCAoc3RhbmRhcmQgR0NNKS5cbiAqXG4gKiBPcGVyYXRvciBjb25maWd1cmF0aW9uICogLSBgU0VDUkVUX0VOQ1JZUFRJT05fS0VZYCBlbnY6IGhleC0gb3IgYmFzZTY0LWVuY29kZWQgMzItYnl0ZSBtYXN0ZXIga2V5LlxuICogUmVxdWlyZWQgd2hlbiBgZW5jcnlwdFNlY3JldGAvYGRlY3J5cHRTZWNyZXRgIGFyZSBjYWxsZWQuIE1pc3Npbmcga2V5XG4gKiB0aHJvd3MgIGVuY3J5cHRpb24gaXMgZmFpbC1jbG9zZWQ7IHdlIG5ldmVyIHNpbGVudGx5IHJvdW5kLXRyaXAgYVxuICogc2VjcmV0IGFzIHBsYWludGV4dC5cbiAqXG4gKiBLTVMgbWlncmF0aW9uIHBhdGggKiAtIFRoZSB0d28gZXhwb3J0ZWQgZnVuY3Rpb25zIHRha2UgYSBgcHJvdmlkZXJgIHBhcmFtZXRlci4gVGhlIGRlZmF1bHRcbiAqIGBFbnZLZXlQcm92aWRlcmAgaW1wbGVtZW50cyBIS0RGIGRlcml2YXRpb24uIEEgZnV0dXJlIGBBd3NLbXNQcm92aWRlcmBcbiAqIHBsdWdzIGluIGhlcmU6IGl0IGNhbiBjYWxsIEtNUyBgRW5jcnlwdGAgLyBgRGVjcnlwdGAgdG8gd3JhcCBhIERFS1xuICogcmF0aGVyIHRoYW4gaG9sZGluZyBhIG1hc3RlciBrZXkgaW4gZW52LiBUaGUgb24tZGlzayBibG9iIHNoYXBlXG4gKiAoYHsgYWxnLCBpdiwgY2lwaGVydGV4dCwga2lkPyB9YCkgaXMgZm9yd2FyZC1jb21wYXRpYmxlICBga2lkYFxuICogY2FycmllcyB0aGUgS01TIGtleSBpZCB3aGVuIHRoZSBwcm92aWRlciBuZWVkcyBpdC5cbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVDaXBoZXJpdiwgY3JlYXRlRGVjaXBoZXJpdiwgaGtkZlN5bmMsIHJhbmRvbUJ5dGVzIH0gZnJvbSAnY3J5cHRvJztcblxuLyoqIE9uLWRpc2sgc2hhcGUgb2YgYW4gZW5jcnlwdGVkIHNlY3JldC4gSlNPTi1zZXJpYWxpemFibGUuICovXG5leHBvcnQgaW50ZXJmYWNlIEVuY3J5cHRlZEJsb2Ige1xuICAvKiogQWxnb3JpdGhtIHRhZy4gQnVtcCBvbiBmb3JtYXQgY2hhbmdlIHNvIGEgZnV0dXJlIG1pZ3JhdGlvbiBjYW4gZGV0ZWN0IG9sZCBibG9icy4gKi9cbiAgYWxnOiAnYWVzLTI1Ni1nY20tdjEnO1xuICAvKiogQmFzZTY0LWVuY29kZWQgMTItYnl0ZSBJVi4gKi9cbiAgaXY6IHN0cmluZztcbiAgLyoqIEJhc2U2NC1lbmNvZGVkIGNpcGhlcnRleHQgKyAxNi1ieXRlIGF1dGhlbnRpY2F0aW9uIHRhZyBjb25jYXRlbmF0ZWQuICovXG4gIGNpcGhlcnRleHQ6IHN0cmluZztcbiAgLyoqIE9wdGlvbmFsIGtleSBpZCAgcG9wdWxhdGVkIGJ5IEtNUy1iYWNrZWQgcHJvdmlkZXJzLCBpZ25vcmVkIGJ5IHRoZSBlbnYgcHJvdmlkZXIuICovXG4gIGtpZD86IHN0cmluZztcbn1cblxuLyoqIFBsdWdnYWJsZSBrZXkgc291cmNlLiBFbnYtYmFja2VkIGJ5IGRlZmF1bHQ7IEtNUy1iYWNrZWQgYXZhaWxhYmxlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBLZXlQcm92aWRlciB7XG4gIC8qKiBEZXJpdmUgYSAzMi1ieXRlIHN5bW1ldHJpYyBrZXkgYm91bmQgdG8gYG9yZ0lkYC4gKi9cbiAgZGVyaXZlS2V5KG9yZ0lkOiBzdHJpbmcpOiBCdWZmZXI7XG4gIC8qKiBPcHRpb25hbCBhc3luYyB2YXJpYW50IGZvciBwcm92aWRlcnMgdGhhdCBuZWVkIHRvIGRvIEkvTyAoZS5nLlxuICAgKiAgcGVyLW9yZyBLTVMgbG9va3VwIHRoZSBmaXJzdCB0aW1lIGFuIG9yZyBpcyBzZWVuKS4gRGVmYXVsdFxuICAgKiAgaW1wbGVtZW50YXRpb24gZm9yd2FyZHMgdG8gdGhlIHN5bmMgYGRlcml2ZUtleWAuICovXG4gIGRlcml2ZUtleUFzeW5jPyhvcmdJZDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+O1xuICAvKiogT3B0aW9uYWwgS01TLWtleS1pZCB0aGlzIHByb3ZpZGVyIHVzZWQgZm9yIGBvcmdJZGAuIEVtYmVkZGVkIGluIHRoZVxuICAgKiAgYEVuY3J5cHRlZEJsb2Iua2lkYCBmaWVsZCBvbiB3cml0ZSBzbyBkZWNyeXB0IGNhbiB2ZXJpZnkgdGhlIHJpZ2h0XG4gICAqICBLTVMgQ01LIGlzIGJlaW5nIHVzZWQgKGRlZmVuc2UgYWdhaW5zdCBhbiBhdHRhY2tlciB3aG8gc3dhcHMgYSBibG9iXG4gICAqICBiZXR3ZWVuIG9yZ3MpLiBEZWZhdWx0IHJldHVybnMgdW5kZWZpbmVkIChlbnYgcHJvdmlkZXIpLiAqL1xuICBraWRGb3I/KG9yZ0lkOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogRGVmYXVsdCBwcm92aWRlciAgZGVyaXZlcyBhIHBlci1vcmcga2V5IGZyb20gYFNFQ1JFVF9FTkNSWVBUSU9OX0tFWWAgdmlhXG4gKiBIS0RGLVNIQTI1Ni4gU3VpdGFibGUgZm9yIHNlbGYtaG9zdGVkIC8gZGV2IHdoZXJlIG9wZXJhdG9ycyBkb24ndCBoYXZlIEtNUy5cbiAqXG4gKiBGYWlscyBmYXN0IGlmIHRoZSBlbnYgaXMgbWlzc2luZyBvciB0aGUga2V5IGlzIHRoZSB3cm9uZyBsZW5ndGggc28gbWlzY29uZmlnXG4gKiBzdXJmYWNlcyBhdCBmaXJzdCB1c2UgcmF0aGVyIHRoYW4gc2lsZW50bHkgZmluZ2VycHJpbnRpbmcgYWxsIHdyaXRlcyB3aXRoXG4gKiBhIGRlZmF1bHQgemVybyBrZXkuXG4gKi9cbmV4cG9ydCBjbGFzcyBFbnZLZXlQcm92aWRlciBpbXBsZW1lbnRzIEtleVByb3ZpZGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBtYXN0ZXJLZXk6IEJ1ZmZlcjtcblxuICBjb25zdHJ1Y3RvcihtYXN0ZXJLZXlPdmVycmlkZT86IHN0cmluZykge1xuICAgIGNvbnN0IHJhdyA9IG1hc3RlcktleU92ZXJyaWRlID8/IHByb2Nlc3MuZW52LlNFQ1JFVF9FTkNSWVBUSU9OX0tFWTtcbiAgICBpZiAoIXJhdykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdTRUNSRVRfRU5DUllQVElPTl9LRVkgZW52IGlzIHJlcXVpcmVkIGZvciBzZWNyZXQgZW5jcnlwdGlvbicpO1xuICAgIH1cbiAgICAvLyBBY2NlcHQgZWl0aGVyIGhleCAoNjQgY2hhcnMpIG9yIGJhc2U2NCAoNDQgY2hhcnMgaW5jbHVkaW5nIHBhZGRpbmcpIGZvclxuICAgIC8vIG9wZXJhdG9yIGNvbnZlbmllbmNlICBib3RoIGRlY29kZSB0byBhIDMyLWJ5dGUga2V5LlxuICAgIGNvbnN0IGRlY29kZWQgPSByYXcubGVuZ3RoID09PSA2NCAmJiAvXlswLTlhLWZdKyQvaS50ZXN0KHJhdylcbiAgICAgID8gQnVmZmVyLmZyb20ocmF3LCAnaGV4JylcbiAgICAgIDogQnVmZmVyLmZyb20ocmF3LCAnYmFzZTY0Jyk7XG4gICAgaWYgKGRlY29kZWQubGVuZ3RoICE9PSAzMikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTRUNSRVRfRU5DUllQVElPTl9LRVkgbXVzdCBkZWNvZGUgdG8gMzIgYnl0ZXMgKGdvdCAke2RlY29kZWQubGVuZ3RofSlgKTtcbiAgICB9XG4gICAgdGhpcy5tYXN0ZXJLZXkgPSBkZWNvZGVkO1xuICB9XG5cbiAgZGVyaXZlS2V5KG9yZ0lkOiBzdHJpbmcpOiBCdWZmZXIge1xuICAgIC8vIEhLREYgYmluZHMgdGhlIG1hc3RlciBrZXkgdG8gdGhlIG9yZyBzbyB0d28gb3JncyBlbmNyeXB0aW5nIHRoZSBzYW1lXG4gICAgLy8gcGxhaW50ZXh0IHByb2R1Y2UgZGlmZmVyZW50IGNpcGhlcnRleHRzICBrZWVwcyBhIHN0b2xlbiBEQiB1bmFibGUgdG9cbiAgICAvLyB0ZWxsIHdoaWNoIG9yZ3Mgc2hhcmUgc2VjcmV0cyB2aWEgY2lwaGVydGV4dCBjb21wYXJpc29uLlxuICAgIGNvbnN0IGRlcml2ZWQgPSBoa2RmU3luYyggJ3NoYTI1NicsXG4gICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgIEJ1ZmZlci5mcm9tKG9yZ0lkLCAndXRmOCcpLFxuICAgICAgJ3NlY3JldHMtdjEnLFxuICAgICAgMzIsXG4gICAgKTtcbiAgICAvLyBoa2RmU3luYyByZXR1cm5zIEFycmF5QnVmZmVyIGluIG9sZGVyIE5vZGUgdHlwaW5nczsgbm9ybWFsaXplIHRvIEJ1ZmZlci5cbiAgICByZXR1cm4gQnVmZmVyLmZyb20oZGVyaXZlZCk7XG4gIH1cbn1cblxuLyoqXG4gKiAgQVdTLUtNUy1iYWNrZWQgS2V5UHJvdmlkZXIuXG4gKlxuICogVHJhZGUtb2ZmIHBpY2tlZDogc3RvcmUgT05FIG1hc3RlciBrZXkgZW5jcnlwdGVkIHVuZGVyIGEgS01TIENNSzsgb25cbiAqIGZpcnN0IHVzZSwgY2FsbCBga21zOkRlY3J5cHRgIHRvIHJlY292ZXIgdGhlIG1hc3RlciBrZXkgYnl0ZXM7IEhLREYtXG4gKiBkZXJpdmUgcGVyLW9yZyBmcm9tIGl0IChzYW1lIGFzIEVudktleVByb3ZpZGVyKS4gVGhlIHByb2Nlc3MgdGhlbiBob2xkc1xuICogdGhlIHBsYWludGV4dCBtYXN0ZXIga2V5IGluIG1lbW9yeSB1bnRpbCByZXN0YXJ0LlxuICpcbiAqIFBST1M6IG9uZSBLTVMgY2FsbCBwZXIgcHJvY2VzcyBsaWZldGltZSAoY2hlYXAsIGxvdyBwOTkgaW1wYWN0KSxcbiAqIHRoZSBlbmNyeXB0ZWQtbWFzdGVyLWtleSBibG9iIGlzIHNhZmUgdG8gY29tbWl0L2xvZy9jaGVja2luLFxuICogS01TIGF1ZGl0IGxvZyByZWNvcmRzIHdoZW4gdGhlIG1hc3RlciBpcyByZWNvdmVyZWQuXG4gKiBDT05TOiBwcm9jZXNzIG1lbW9yeSBzdGlsbCBob2xkcyB0aGUgbWFzdGVyIGtleSAgc2FtZSBwb3N0dXJlIGFzXG4gKiBFbnZLZXlQcm92aWRlciBvbmNlIHdhcm1lZCB1cC4gRm9yIHN0cm9uZ2VyIGlzb2xhdGlvbiBhblxuICogb3BlcmF0b3IgY2FuIG1vdmUgdG8gcGVyLXJlY29yZCBlbnZlbG9wZSBlbmNyeXB0aW9uIChjYWxsXG4gKiBHZW5lcmF0ZURhdGFLZXkgb24gZXZlcnkgd3JpdGUpOyB0aGF0J3MgYSBmb2xsb3ctb24uXG4gKlxuICogT3BlcmF0b3Igc2V0dXAgKiAxLiBDcmVhdGUgYSBLTVMgQ01LIHdpdGgga2V5IHBvbGljeSBhbGxvd2luZyB0aGUgcGxhdGZvcm0gc2VydmljZSdzXG4gKiBJQU0gcm9sZSBrbXM6RGVjcnlwdC5cbiAqIDIuIEdlbmVyYXRlIGEgcmFuZG9tIDMyLWJ5dGUgbWFzdGVyICogaGVhZCAtYyAzMiAvZGV2L3VyYW5kb20gfCBiYXNlNjRcbiAqIDMuIFdyYXAgaXQgd2l0aCBLTVMgKiBhd3Mga21zIGVuY3J5cHQgLS1rZXktaWQgPEtFWV9JRD4gXFxcbiAqIC0tcGxhaW50ZXh0IDxiYXNlNjQtZnJvbS1zdGVwLTI+IC0tb3V0cHV0IHRleHQgXFxcbiAqIC0tcXVlcnkgQ2lwaGVydGV4dEJsb2JcbiAqIDQuIFNldCBvbiB0aGUgc2VydmljZSAqIFNFQ1JFVF9FTkNSWVBUSU9OX0tNU19LRVlfSUQ9PEtFWV9JRD5cbiAqIFNFQ1JFVF9FTkNSWVBUSU9OX0tNU19DSVBIRVJURVhUPTxiYXNlNjQtb3V0cHV0LW9mLXN0ZXAtMz5cbiAqIDUuIFBpY2sgdGhpcyBwcm92aWRlciB2aWEgYHNldEtleVByb3ZpZGVyKG5ldyBLbXNLZXlQcm92aWRlcigpKWAuXG4gKlxuICogQ29uc3RydWN0IGxhemlseSAgaW1wb3J0aW5nIHRoZSBBV1MgU0RLIGhhcyBhIG5vbi10cml2aWFsIGNvbGQtc3RhcnRcbiAqIGNvc3Qgc28gZW52cyB0aGF0IHN0YXkgb24gRW52S2V5UHJvdmlkZXIgbmV2ZXIgbG9hZCBpdC5cbiAqL1xuZXhwb3J0IGNsYXNzIEttc0tleVByb3ZpZGVyIGltcGxlbWVudHMgS2V5UHJvdmlkZXIge1xuICBwcml2YXRlIG1hc3RlcktleUNhY2hlOiBCdWZmZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSBrZXlJZDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGNpcGhlcnRleHRCNjQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZW5kcG9pbnQ/OiBzdHJpbmc7XG4gIHByaXZhdGUgZGVjcnlwdEluRmxpZ2h0OiBQcm9taXNlPEJ1ZmZlcj4gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihvcHRzPzogeyBrZXlJZD86IHN0cmluZzsgY2lwaGVydGV4dEJhc2U2ND86IHN0cmluZzsgcmVnaW9uPzogc3RyaW5nOyBlbmRwb2ludD86IHN0cmluZyB9KSB7XG4gICAgY29uc3Qga2V5SWQgPSBvcHRzPy5rZXlJZCA/PyBwcm9jZXNzLmVudi5TRUNSRVRfRU5DUllQVElPTl9LTVNfS0VZX0lEO1xuICAgIGNvbnN0IGNpcGhlcnRleHQgPSBvcHRzPy5jaXBoZXJ0ZXh0QmFzZTY0ID8/IHByb2Nlc3MuZW52LlNFQ1JFVF9FTkNSWVBUSU9OX0tNU19DSVBIRVJURVhUO1xuICAgIGlmICgha2V5SWQpIHRocm93IG5ldyBFcnJvcignU0VDUkVUX0VOQ1JZUFRJT05fS01TX0tFWV9JRCBlbnYgaXMgcmVxdWlyZWQgZm9yIEttc0tleVByb3ZpZGVyJyk7XG4gICAgaWYgKCFjaXBoZXJ0ZXh0KSB0aHJvdyBuZXcgRXJyb3IoJ1NFQ1JFVF9FTkNSWVBUSU9OX0tNU19DSVBIRVJURVhUIGVudiBpcyByZXF1aXJlZCBmb3IgS21zS2V5UHJvdmlkZXInKTtcbiAgICB0aGlzLmtleUlkID0ga2V5SWQ7XG4gICAgdGhpcy5jaXBoZXJ0ZXh0QjY0ID0gY2lwaGVydGV4dDtcbiAgICB0aGlzLnJlZ2lvbiA9IG9wdHM/LnJlZ2lvbiA/PyBwcm9jZXNzLmVudi5BV1NfUkVHSU9OID8/IHByb2Nlc3MuZW52LkFXU19ERUZBVUxUX1JFR0lPTjtcbiAgICB0aGlzLmVuZHBvaW50ID0gb3B0cz8uZW5kcG9pbnQgPz8gcHJvY2Vzcy5lbnYuQVdTX0tNU19FTkRQT0lOVDtcbiAgfVxuXG4gIGRlcml2ZUtleShvcmdJZDogc3RyaW5nKTogQnVmZmVyIHtcbiAgICBpZiAoIXRoaXMubWFzdGVyS2V5Q2FjaGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvciggJ0ttc0tleVByb3ZpZGVyIGlzIG5vdCB3YXJtZWQgdXAuIENhbGwgYGF3YWl0IHByb3ZpZGVyLndhcm11cCgpYCBvbmNlIGF0IHNlcnZpY2Ugc3RhcnR1cCBiZWZvcmUgYW55IGVuY3J5cHQvZGVjcnlwdC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgZGVyaXZlZCA9IGhrZGZTeW5jKCdzaGEyNTYnLCB0aGlzLm1hc3RlcktleUNhY2hlLCBCdWZmZXIuZnJvbShvcmdJZCwgJ3V0ZjgnKSwgJ3NlY3JldHMtdjEnLCAzMik7XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRlcml2ZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVhZ2VybHkgcmVjb3ZlciB0aGUgbWFzdGVyIGtleSBmcm9tIEtNUyBzbyBzdWJzZXF1ZW50IGBkZXJpdmVLZXlgXG4gICAqIGNhbGxzIGFyZSBzeW5jLiBJZGVtcG90ZW50ICBjb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgdGhlIHNhbWUgaW4tXG4gICAqIGZsaWdodCBwcm9taXNlIHNvIHdlIGRvbid0IHNwYXduIG11bHRpcGxlIEtNUyBEZWNyeXB0IHJlcXVlc3RzIGF0XG4gICAqIGJvb3QuIFRocm93cyBvbiBhbnkgS01TIGZhaWx1cmU7IHRoZSBjYWxsZXIgKHR5cGljYWxseSB0aGUgc2VydmljZSdzXG4gICAqIG9uQmVmb3JlU3RhcnQgaG9vaykgZGVjaWRlcyB3aGV0aGVyIHRvIGZhbGwgYmFjayB0byBhIGRpZmZlcmVudFxuICAgKiBwcm92aWRlciBvciBmYWlsLXN0YXJ0dXAuXG4gICAqL1xuICBhc3luYyB3YXJtdXAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMubWFzdGVyS2V5Q2FjaGUpIHJldHVybjtcbiAgICBpZiAoIXRoaXMuZGVjcnlwdEluRmxpZ2h0KSB7XG4gICAgICB0aGlzLmRlY3J5cHRJbkZsaWdodCA9IHRoaXMuZmV0Y2hBbmREZWNyeXB0KCk7XG4gICAgfVxuICAgIHRoaXMubWFzdGVyS2V5Q2FjaGUgPSBhd2FpdCB0aGlzLmRlY3J5cHRJbkZsaWdodDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hBbmREZWNyeXB0KCk6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgLy8gRHluYW1pYyBpbXBvcnQgc28gRW52S2V5UHJvdmlkZXItb25seSBlbnZzIGRvbid0IGxvYWQgdGhlIFNESy5cbiAgICBjb25zdCB7IEtNU0NsaWVudCwgRGVjcnlwdENvbW1hbmQgfSA9IGF3YWl0IGltcG9ydCgnQGF3cy1zZGsvY2xpZW50LWttcycpO1xuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBLTVNDbGllbnQoe1xuICAgICAgcmVnaW9uOiB0aGlzLnJlZ2lvbixcbiAgICAgIC4uLih0aGlzLmVuZHBvaW50ID8geyBlbmRwb2ludDogdGhpcy5lbmRwb2ludCB9OiB7fSksXG4gICAgfSk7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGNsaWVudC5zZW5kKG5ldyBEZWNyeXB0Q29tbWFuZCh7XG4gICAgICBLZXlJZDogdGhpcy5rZXlJZCxcbiAgICAgIENpcGhlcnRleHRCbG9iOiBCdWZmZXIuZnJvbSh0aGlzLmNpcGhlcnRleHRCNjQsICdiYXNlNjQnKSxcbiAgICB9KSk7XG4gICAgaWYgKCFyZXNwLlBsYWludGV4dCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdLTVMgRGVjcnlwdCByZXR1cm5lZCBhbiBlbXB0eSBQbGFpbnRleHQnKTtcbiAgICB9XG4gICAgY29uc3QgYnVmID0gQnVmZmVyLmZyb20ocmVzcC5QbGFpbnRleHQpO1xuICAgIGlmIChidWYubGVuZ3RoICE9PSAzMikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBLTVMgRGVjcnlwdCByZXR1cm5lZCAke2J1Zi5sZW5ndGh9LWJ5dGUga2V5OyBleHBlY3RlZCAzMmApO1xuICAgIH1cbiAgICByZXR1cm4gYnVmO1xuICB9XG59XG5cbi8vIExhenkgc2luZ2xldG9uICBvcGVyYXRvciBjb2RlIGluIGxvbmctbGl2ZWQgc2VydmljZXMgcGF5cyB0aGUgZW52LXBhcnNlXG4vLyBjb3N0IG9uY2UsIGFuZCB0ZXN0cyBjYW4gbWludCB0aGVpciBvd24gcHJvdmlkZXIgd2l0aCBhIGxpdGVyYWwga2V5LlxubGV0IGRlZmF1bHRQcm92aWRlcjogS2V5UHJvdmlkZXIgfCBudWxsID0gbnVsbDtcbmZ1bmN0aW9uIGdldERlZmF1bHRQcm92aWRlcigpOiBLZXlQcm92aWRlciB7XG4gIGlmICghZGVmYXVsdFByb3ZpZGVyKSBkZWZhdWx0UHJvdmlkZXIgPSBuZXcgRW52S2V5UHJvdmlkZXIoKTtcbiAgcmV0dXJuIGRlZmF1bHRQcm92aWRlcjtcbn1cblxuLyoqIFJlYWQgdGhlIGFjdGl2ZSBkZWZhdWx0IHByb3ZpZGVyLiBFeHBvc2VkIHNvIHNlcnZpY2UgY29kZSAoZS5nLiBhblxuICogIGFkbWluIGVuZHBvaW50IHRoYXQganVzdCByb3RhdGVkIGFuIG9yZydzIEtNUyBjb25maWcpIGNhbiBjYWxsXG4gKiAgYHByb3ZpZGVyLmV2aWN0KG9yZ0lkKWAgb24gdGhlIGxpdmUgcHJvdmlkZXIgcmF0aGVyIHRoYW4gcmVjb25zdHJ1Y3RpbmdcbiAqICBvbmUuIFRyaWdnZXJzIGxhenkgaW5pdGlhbGl6YXRpb24gb24gZmlyc3QgYWNjZXNzLCBzYW1lIGFzIHRoZSBpbnRlcm5hbFxuICogIGNhbGxlcnMgYmVsb3cuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGVmYXVsdEtleVByb3ZpZGVyKCk6IEtleVByb3ZpZGVyIHtcbiAgcmV0dXJuIGdldERlZmF1bHRQcm92aWRlcigpO1xufVxuXG4vKiogUmVzZXQgdGhlIGNhY2hlZCBkZWZhdWx0IHByb3ZpZGVyICBmb3IgdGVzdHMgdGhhdCBtdXRhdGUgYHByb2Nlc3MuZW52YC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldERlZmF1bHRLZXlQcm92aWRlcigpOiB2b2lkIHsgZGVmYXVsdFByb3ZpZGVyID0gbnVsbDsgfVxuXG4vKiogUmVwbGFjZSB0aGUgZGVmYXVsdCBwcm92aWRlciAgc2VydmljZXMgdGhhdCBvcHQgaW50byBLTVMgY2FsbCB0aGlzXG4gKiBvbmNlIGF0IHN0YXJ0dXAgd2l0aCBhIHdhcm1lZC11cCBgS21zS2V5UHJvdmlkZXJgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldEtleVByb3ZpZGVyKHByb3ZpZGVyOiBLZXlQcm92aWRlcik6IHZvaWQgeyBkZWZhdWx0UHJvdmlkZXIgPSBwcm92aWRlcjsgfVxuXG4vKiogUGVyLW9yZyBLTVMgY29uZmlnIHRoZSBvcGVyYXRvciBzdXBwbGllcy4gVGhlIGBrZXlJZGAgaWRlbnRpZmllcyB0aGVcbiAqICBLTVMgQ01LIHRvIGNhbGwgRGVjcnlwdCBvbjsgYGNpcGhlcnRleHRCYXNlNjRgIGlzIHRoZSB3cmFwcGVkIDMyLWJ5dGVcbiAqICBtYXN0ZXIgZ2VuZXJhdGVkIGJ5IGBhd3Mga21zIGVuY3J5cHRgIGFnYWluc3QgdGhhdCBrZXkuICovXG5leHBvcnQgaW50ZXJmYWNlIFBlck9yZ0ttc0NvbmZpZyB7XG4gIGtleUlkOiBzdHJpbmc7XG4gIGNpcGhlcnRleHRCYXNlNjQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBc3luYyByZXNvbHZlciB0aGF0IG1hcHMgYW4gb3JnIGlkIHRvIGl0cyBLTVMgY29uZmlnLiBSZXR1cm5zIGBudWxsYCB3aGVuXG4gKiB0aGUgb3JnIGhhcyBubyBwZXItb3JnIGNvbmZpZyDigJQgdGhlIHByb3ZpZGVyIHRoZW4gZmFsbHMgYmFjayB0byB0aGVcbiAqIGBmYWxsYmFja2AgcHJvdmlkZXIgc3VwcGxpZWQgYXQgY29uc3RydWN0aW9uICh1c3VhbGx5IGFuIEVudktleVByb3ZpZGVyXG4gKiBvciBhIGRlZmF1bHQgS21zS2V5UHJvdmlkZXIpLlxuICovXG5leHBvcnQgdHlwZSBQZXJPcmdLbXNSZXNvbHZlciA9IChvcmdJZDogc3RyaW5nKSA9PiBQcm9taXNlPFBlck9yZ0ttc0NvbmZpZyB8IG51bGw+O1xuXG4vKipcbiAqIFBlci1vcmcgS01TLWJhY2tlZCBLZXlQcm92aWRlci4gVGhlIGJsYXN0IHJhZGl1cyBvZiBhIEtNUyBrZXkgY29tcHJvbWlzZVxuICogaXMgb25lIG9yZyBpbnN0ZWFkIG9mIGV2ZXJ5IG9yZyB1bmRlciBhIHNoYXJlZCBtYXN0ZXIuXG4gKlxuICogRWFjaCBvcmcgaGFzIGl0cyBvd24gS01TIENNSyArIGl0cyBvd24gd3JhcHBlZCBtYXN0ZXIgKHN0b3JlZCBpbiBNb25nb1xuICogdmlhIHRoZSBvcGVyYXRvcidzIHNldHVwIHNjcmlwdCkuIE9uIGZpcnN0IGVuY3J5cHQvZGVjcnlwdCBmb3IgYW4gb3JnLFxuICogdGhlIHByb3ZpZGVyOlxuICogICAxLiBDYWxscyB0aGUgcmVzb2x2ZXIgdG8gZmV0Y2ggdGhlIG9yZydzIEtNUyBjb25maWcuXG4gKiAgIDIuIENhbGxzIGBrbXM6RGVjcnlwdGAgdG8gcmVjb3ZlciB0aGUgMzItYnl0ZSBtYXN0ZXIuXG4gKiAgIDMuIENhY2hlcyB0aGUgcmVjb3ZlcmVkIG1hc3RlciBpbi1tZW1vcnkgZm9yIHRoZSBwcm9jZXNzIGxpZmV0aW1lLlxuICogICA0LiBIS0RGLWRlcml2ZXMgcGVyLWNhbGwgZnJvbSB0aGF0IG1hc3RlciArIHRoZSBvcmcgaWQgc2FsdC5cbiAqXG4gKiBCbG9icyBlbmNyeXB0ZWQgYnkgdGhpcyBwcm92aWRlciBjYXJyeSBga2lkID0gPGttcy1rZXktaWQ+YCBzbyB0aGVcbiAqIGRlY3J5cHQgcGF0aCBkZXRlY3RzIGEgc3RhbGUgY29uZmlnIChvcGVyYXRvciByb3RhdGVkIHRoZSBrZXkgYnV0XG4gKiBleGlzdGluZyByb3dzIHdlcmVuJ3QgcmUtZW5jcnlwdGVkKSBCRUZPUkUgQUVTLUdDTSB0aHJvd3MgYW4gb3BhcXVlXG4gKiBhdXRoZW50aWNhdGlvbi10YWcgZXJyb3IuXG4gKlxuICogT3JncyB3aXRob3V0IHBlci1vcmcgY29uZmlnIGZhbGwgdGhyb3VnaCB0byB0aGUgYGZhbGxiYWNrYCBwcm92aWRlciDigJRcbiAqIG1peGVkLW1vZGUgZGVwbG95bWVudHMgd2hlcmUgc29tZSBvcmdzIGhhdmUgS01TIGlzb2xhdGlvbiBhbmQgb3RoZXJzXG4gKiBzdGF5IG9uIHRoZSBzaGFyZWQgbWFzdGVyIGFyZSBleHBsaWNpdGx5IHN1cHBvcnRlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFBlck9yZ0ttc0tleVByb3ZpZGVyIGltcGxlbWVudHMgS2V5UHJvdmlkZXIge1xuICAvKiogQ2FjaGVkIHBlci1vcmcgbWFzdGVyIGtleXMsIGtleWVkIGJ5IG9yZ0lkLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IG1hc3RlcnMgPSBuZXcgTWFwPHN0cmluZywgeyBrZXk6IEJ1ZmZlcjsga2lkOiBzdHJpbmcgfT4oKTtcbiAgLyoqIFJlc29sdmVkIHBlci1vcmcgY29uZmlncyBjYWNoZWQgZm9yIHRoZSBwcm9jZXNzIGxpZmV0aW1lLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZ3MgPSBuZXcgTWFwPHN0cmluZywgUGVyT3JnS21zQ29uZmlnPigpO1xuICAvKiogSW4tZmxpZ2h0IHJlc29sdmVyIHByb21pc2VzIHNvIGNvbmN1cnJlbnQgZmlyc3QtdG91Y2ggY2FsbGVycyBzaGFyZSBvbmUgS01TIERlY3J5cHQuXG4gICAqICBSZXNvbHZlcyB0byBgbnVsbGAgZm9yIG9yZ3Mgd2l0aCBubyBwZXItb3JnIGNvbmZpZyDigJQgY2FsbGVyIHRyZWF0cyBudWxsIGFzXG4gICAqICBcImZhbGwgdGhyb3VnaCB0byB0aGUgZmFsbGJhY2sgcHJvdmlkZXJcIiwgc2FtZSBhcyBhIGNvbGQgY2FjaGUgbWlzcy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpbkZsaWdodCA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPHsga2V5OiBCdWZmZXI7IGtpZDogc3RyaW5nIH0gfCBudWxsPj4oKTtcbiAgLyoqIFByb3ZpZGVyIHVzZWQgZm9yIG9yZ3MgdGhhdCBoYXZlIG5vIHBlci1vcmcgY29uZmlnLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGZhbGxiYWNrOiBLZXlQcm92aWRlcjtcbiAgcHJpdmF0ZSByZWFkb25seSByZXNvbHZlcjogUGVyT3JnS21zUmVzb2x2ZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGVuZHBvaW50Pzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKG9wdHM6IHtcbiAgICByZXNvbHZlcjogUGVyT3JnS21zUmVzb2x2ZXI7XG4gICAgZmFsbGJhY2s6IEtleVByb3ZpZGVyO1xuICAgIHJlZ2lvbj86IHN0cmluZztcbiAgICBlbmRwb2ludD86IHN0cmluZztcbiAgfSkge1xuICAgIHRoaXMucmVzb2x2ZXIgPSBvcHRzLnJlc29sdmVyO1xuICAgIHRoaXMuZmFsbGJhY2sgPSBvcHRzLmZhbGxiYWNrO1xuICAgIHRoaXMucmVnaW9uID0gb3B0cy5yZWdpb24gPz8gcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTiA/PyBwcm9jZXNzLmVudi5BV1NfREVGQVVMVF9SRUdJT047XG4gICAgdGhpcy5lbmRwb2ludCA9IG9wdHMuZW5kcG9pbnQgPz8gcHJvY2Vzcy5lbnYuQVdTX0tNU19FTkRQT0lOVDtcbiAgfVxuXG4gIC8qKiBTeW5jIGBkZXJpdmVLZXlgIG9ubHkgd29ya3MgZm9yIGFscmVhZHktd2FybWVkIG9yZ3MuIENvbGQgb3JncyBmYWxsXG4gICAqICB0aHJvdWdoIHRvIHRoZSBmYWxsYmFjayBwcm92aWRlci4gQ2FsbGVycyB0aGF0IHdhbnQgcGVyLW9yZyBpc29sYXRpb25cbiAgICogIE1VU1QgYGF3YWl0IGRlcml2ZUtleUFzeW5jKG9yZ0lkKWAgb25jZSBmaXJzdCAoZS5nLiBkdXJpbmcgcmVxdWVzdCBzZXR1cFxuICAgKiAgb3IgYXMgcGFydCBvZiBhIHdhcm11cCBwYXNzKSDigJQgb3RoZXJ3aXNlIHRoZSBvcmcgc2lsZW50bHkgdXNlcyB0aGVcbiAgICogIHNoYXJlZCBtYXN0ZXIuICovXG4gIGRlcml2ZUtleShvcmdJZDogc3RyaW5nKTogQnVmZmVyIHtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLm1hc3RlcnMuZ2V0KG9yZ0lkKTtcbiAgICBpZiAoIWNhY2hlZCkgcmV0dXJuIHRoaXMuZmFsbGJhY2suZGVyaXZlS2V5KG9yZ0lkKTtcbiAgICBjb25zdCBkZXJpdmVkID0gaGtkZlN5bmMoJ3NoYTI1NicsIGNhY2hlZC5rZXksIEJ1ZmZlci5mcm9tKG9yZ0lkLCAndXRmOCcpLCAnc2VjcmV0cy12MScsIDMyKTtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oZGVyaXZlZCk7XG4gIH1cblxuICBhc3luYyBkZXJpdmVLZXlBc3luYyhvcmdJZDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVdhcm1lZChvcmdJZCk7XG4gICAgcmV0dXJuIHRoaXMuZGVyaXZlS2V5KG9yZ0lkKTtcbiAgfVxuXG4gIGtpZEZvcihvcmdJZDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5tYXN0ZXJzLmdldChvcmdJZCk/LmtpZCA/PyB0aGlzLmZhbGxiYWNrLmtpZEZvcj8uKG9yZ0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSBvcmcncyBLTVMgY29uZmlnLCBjYWxsIERlY3J5cHQsIGNhY2hlIHRoZSBtYXN0ZXIuIFN1YnNlcXVlbnRcbiAgICogY2FsbHMgZm9yIHRoZSBzYW1lIG9yZyBhcmUgbm8tb3BzLiBDb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgdGhlIGluLWZsaWdodFxuICAgKiBEZWNyeXB0IHByb21pc2UuXG4gICAqXG4gICAqIFJldHVybnMgc2lsZW50bHkgd2hlbiB0aGUgb3JnIGhhcyBubyBwZXItb3JnIGNvbmZpZyDigJQgdGhlIGZhbGxiYWNrXG4gICAqIHByb3ZpZGVyIGhhbmRsZXMgdGhvc2Ugb3Jncy5cbiAgICovXG4gIGFzeW5jIGVuc3VyZVdhcm1lZChvcmdJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMubWFzdGVycy5oYXMob3JnSWQpKSByZXR1cm47XG4gICAgLy8gSW5zdGFsbCB0aGUgaW4tZmxpZ2h0IHByb21pc2UgU1lOQ0hST05PVVNMWSBiZWZvcmUgeWllbGRpbmcgc28gY29uY3VycmVudFxuICAgIC8vIGNhbGxlcnMgZmluZCBpdCBvbiB0aGUgc2Vjb25kLWFuZC1sYXRlciBwYXNzZXMuIEF3YWl0aW5nIHRoZSByZXNvbHZlclxuICAgIC8vIGJlZm9yZSBwb3B1bGF0aW5nIHRoZSBtYXAgaXMgdGhlIGJ1ZyB0aGF0IGxldHMgYSBQcm9taXNlLmFsbCBvZiAzXG4gICAgLy8gY2FsbGVycyBmaXJlIDMgS01TIERlY3J5cHRzLlxuICAgIGxldCBwcm9taXNlID0gdGhpcy5pbkZsaWdodC5nZXQob3JnSWQpO1xuICAgIGlmICghcHJvbWlzZSkge1xuICAgICAgcHJvbWlzZSA9IHRoaXMucmVzb2x2ZUFuZERlY3J5cHQob3JnSWQpO1xuICAgICAgdGhpcy5pbkZsaWdodC5zZXQob3JnSWQsIHByb21pc2UpO1xuICAgICAgdm9pZCBwcm9taXNlLmZpbmFsbHkoKCkgPT4geyBpZiAodGhpcy5pbkZsaWdodC5nZXQob3JnSWQpID09PSBwcm9taXNlKSB0aGlzLmluRmxpZ2h0LmRlbGV0ZShvcmdJZCk7IH0pO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwcm9taXNlO1xuICAgIGlmIChyZXN1bHQpIHRoaXMubWFzdGVycy5zZXQob3JnSWQsIHJlc3VsdCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlc29sdmVBbmREZWNyeXB0KG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPHsga2V5OiBCdWZmZXI7IGtpZDogc3RyaW5nIH0gfCBudWxsPiB7XG4gICAgbGV0IGNmZyA9IHRoaXMuY29uZmlncy5nZXQob3JnSWQpO1xuICAgIGlmICghY2ZnKSB7XG4gICAgICBjb25zdCByZXNvbHZlZCA9IGF3YWl0IHRoaXMucmVzb2x2ZXIob3JnSWQpO1xuICAgICAgaWYgKCFyZXNvbHZlZCkgcmV0dXJuIG51bGw7IC8vIG5vIHBlci1vcmcgY29uZmlnIOKGkiBjYWxsZXIgdXNlcyBmYWxsYmFja1xuICAgICAgY2ZnID0gcmVzb2x2ZWQ7XG4gICAgICB0aGlzLmNvbmZpZ3Muc2V0KG9yZ0lkLCBjZmcpO1xuICAgIH1cbiAgICBjb25zdCBrZXkgPSBhd2FpdCB0aGlzLmZldGNoQW5kRGVjcnlwdChjZmcpO1xuICAgIHJldHVybiB7IGtleSwga2lkOiBjZmcua2V5SWQgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hBbmREZWNyeXB0KGNmZzogUGVyT3JnS21zQ29uZmlnKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBjb25zdCB7IEtNU0NsaWVudCwgRGVjcnlwdENvbW1hbmQgfSA9IGF3YWl0IGltcG9ydCgnQGF3cy1zZGsvY2xpZW50LWttcycpO1xuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBLTVNDbGllbnQoe1xuICAgICAgcmVnaW9uOiB0aGlzLnJlZ2lvbixcbiAgICAgIC4uLih0aGlzLmVuZHBvaW50ID8geyBlbmRwb2ludDogdGhpcy5lbmRwb2ludCB9IDoge30pLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjbGllbnQuc2VuZChuZXcgRGVjcnlwdENvbW1hbmQoe1xuICAgICAgS2V5SWQ6IGNmZy5rZXlJZCxcbiAgICAgIENpcGhlcnRleHRCbG9iOiBCdWZmZXIuZnJvbShjZmcuY2lwaGVydGV4dEJhc2U2NCwgJ2Jhc2U2NCcpLFxuICAgIH0pKTtcbiAgICBpZiAoIXJlc3AuUGxhaW50ZXh0KSB0aHJvdyBuZXcgRXJyb3IoYEtNUyBEZWNyeXB0IHJldHVybmVkIGVtcHR5IFBsYWludGV4dCBmb3Iga2V5ICR7Y2ZnLmtleUlkfWApO1xuICAgIGNvbnN0IGJ1ZiA9IEJ1ZmZlci5mcm9tKHJlc3AuUGxhaW50ZXh0KTtcbiAgICBpZiAoYnVmLmxlbmd0aCAhPT0gMzIpIHRocm93IG5ldyBFcnJvcihgS01TIERlY3J5cHQgcmV0dXJuZWQgJHtidWYubGVuZ3RofS1ieXRlIGtleSBmb3IgJHtjZmcua2V5SWR9OyBleHBlY3RlZCAzMmApO1xuICAgIHJldHVybiBidWY7XG4gIH1cblxuICAvKiogRXZpY3QgYSBjYWNoZWQgcGVyLW9yZyBtYXN0ZXIuIFVzZSBhZnRlciBhIGtleSByb3RhdGlvbiBzbyB0aGUgbmV4dFxuICAgKiAgdG91Y2ggcmUtZmV0Y2hlcyB0aGUgbmV3IHdyYXBwZWQgbWFzdGVyIGZyb20gdGhlIHJlc29sdmVyLiAqL1xuICBldmljdChvcmdJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5tYXN0ZXJzLmRlbGV0ZShvcmdJZCk7XG4gICAgdGhpcy5jb25maWdzLmRlbGV0ZShvcmdJZCk7XG4gIH1cbn1cblxuLyoqXG4gKiBFbmNyeXB0IGEgcGxhaW50ZXh0IHN0cmluZyBmb3Igc3RvcmFnZS4gUmV0dXJucyBhbiBgRW5jcnlwdGVkQmxvYmAgdGhhdFxuICogY2FuIGJlIEpTT04tc2VyaWFsaXplZCBpbnRvIHRoZSB1bmRlcmx5aW5nIGNvbHVtbiAvIE1vbmdvIGRvY3VtZW50LlxuICpcbiAqIEVtcHR5IHN0cmluZ3Mgcm91bmQtdHJpcCBhcyBgbnVsbGAgc28gdGhlIGNhbGxpbmcgbW9kZWwgbGF5ZXIgY2FuIHRyZWF0XG4gKiBcIm5vIHNlY3JldCBzZXRcIiBpZGVudGljYWxseSB0byBcImZpZWxkIGFic2VudFwiLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZW5jcnlwdFNlY3JldCggcGxhaW50ZXh0OiBzdHJpbmcsXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHByb3ZpZGVyOiBLZXlQcm92aWRlciA9IGdldERlZmF1bHRQcm92aWRlcigpLFxuKTogRW5jcnlwdGVkQmxvYiB7XG4gIGlmICghcGxhaW50ZXh0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdSZWZ1c2luZyB0byBlbmNyeXB0IGVtcHR5IHN0cmluZzsgY2FsbGVyIHNob3VsZCBzdG9yZSBudWxsIGluc3RlYWQnKTtcbiAgfVxuICBjb25zdCBrZXkgPSBwcm92aWRlci5kZXJpdmVLZXkob3JnSWQpO1xuICBjb25zdCBpdiA9IHJhbmRvbUJ5dGVzKDEyKTtcbiAgY29uc3QgY2lwaGVyID0gY3JlYXRlQ2lwaGVyaXYoJ2Flcy0yNTYtZ2NtJywga2V5LCBpdik7XG4gIGNvbnN0IGVuYyA9IEJ1ZmZlci5jb25jYXQoW2NpcGhlci51cGRhdGUocGxhaW50ZXh0LCAndXRmOCcpLCBjaXBoZXIuZmluYWwoKV0pO1xuICBjb25zdCB0YWcgPSBjaXBoZXIuZ2V0QXV0aFRhZygpO1xuICAvLyBQZXJPcmdLbXNLZXlQcm92aWRlciB0YWdzIGJsb2JzIHdpdGggdGhlIEtNUyBrZXkgaWQgdXNlZCBzbyB0aGVcbiAgLy8gZGVjcnlwdCBwYXRoIGNhbiByZWZ1c2UgdG8gb3BlcmF0ZSBpZiB0aGUgb3BlcmF0b3IgbGF0ZXIgc3dhcHMgaW4gYVxuICAvLyBkaWZmZXJlbnQgcGVyLW9yZyBjb25maWcgKGEgbWlzY29uZmlndXJlZCBzd2FwIHNob3VsZG4ndCBzaWxlbnRseVxuICAvLyBhY2NlcHQgYSBzdGFsZSBibG9iIGl0IGNhbid0IHZlcmlmeSBhZ2FpbnN0IHRoZSByaWdodCBDTUspLlxuICBjb25zdCBraWQgPSBwcm92aWRlci5raWRGb3I/LihvcmdJZCk7XG4gIHJldHVybiB7XG4gICAgYWxnOiAnYWVzLTI1Ni1nY20tdjEnLFxuICAgIGl2OiBpdi50b1N0cmluZygnYmFzZTY0JyksXG4gICAgLy8gR0NNIHRhZyBNVVNUIHRyYXZlbCB3aXRoIHRoZSBjaXBoZXJ0ZXh0IG9yIGBkZWNyeXB0U2VjcmV0YCBjYW4ndFxuICAgIC8vIHZlcmlmeSBpbnRlZ3JpdHkgIGNvbmNhdGVuYXRlIHNvIHRoZSBvbi1kaXNrIHNoYXBlIGlzIG9uZSBmaWVsZC5cbiAgICBjaXBoZXJ0ZXh0OiBCdWZmZXIuY29uY2F0KFtlbmMsIHRhZ10pLnRvU3RyaW5nKCdiYXNlNjQnKSxcbiAgICAuLi4oa2lkICE9PSB1bmRlZmluZWQgPyB7IGtpZCB9IDoge30pLFxuICB9O1xufVxuXG4vKipcbiAqIERlY3J5cHQgYW4gYEVuY3J5cHRlZEJsb2JgIHdyaXR0ZW4gYnkgYGVuY3J5cHRTZWNyZXRgLiBUaHJvd3Mgb24gKiAtIHVua25vd24gYGFsZ2AgKGZvcmNlcyBhbiBleHBsaWNpdCBtaWdyYXRpb24gd2hlbiB0aGUgZm9ybWF0IGNoYW5nZXMpXG4gKiAtIHdyb25nIG9yZ0lkIChIS0RGIGJpbmRpbmcgbWlzbWF0Y2ggZmFpbHMgdGhlIGF1dGggdGFnKVxuICogLSB0YW1wZXJlZCBjaXBoZXJ0ZXh0IChHQ00gYXV0aCB0YWcgY2hlY2sgZmFpbHMpXG4gKlxuICogQ2FsbGVycyBoYW5kbGUgdGhlIHRocm93ICBtYXNraW5nIHRoZSBmYWlsdXJlIGFzIGBudWxsYCB3b3VsZCBoaWRlXG4gKiBzaWxlbnQgY29ycnVwdGlvbiAvIHdyb25nLW9yZyByZWFkcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY3J5cHRTZWNyZXQoIGJsb2I6IEVuY3J5cHRlZEJsb2IsXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHByb3ZpZGVyOiBLZXlQcm92aWRlciA9IGdldERlZmF1bHRQcm92aWRlcigpLFxuKTogc3RyaW5nIHtcbiAgaWYgKGJsb2IuYWxnICE9PSAnYWVzLTI1Ni1nY20tdjEnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBlbmNyeXB0aW9uIGFsZzogJHtibG9iLmFsZ31gKTtcbiAgfVxuICAvLyBJZiBib3RoIHRoZSBwcm92aWRlciBBTkQgdGhlIGJsb2IgcmVwb3J0IGEga2lkLCB0aGV5IG11c3QgbWF0Y2guXG4gIC8vIE1pc21hdGNoIHVzdWFsbHkgbWVhbnMgYW4gb3BlcmF0b3Igcm90YXRlZC9yZXBsYWNlZCBhbiBvcmcncyBLTVNcbiAgLy8gY29uZmlnIGFuZCBpcyBub3cgcmVhZGluZyBhIGJsb2IgZW5jcnlwdGVkIHVuZGVyIHRoZSBPTEQga2V5IOKAlFxuICAvLyBmYWlsaW5nIGxvdWQgaGVyZSBiZWF0cyBsZXR0aW5nIEFFUy1HQ00gdGhyb3cgYW4gb3BhcXVlIGF1dGgtdGFnIGVycm9yLlxuICBjb25zdCBwcm92aWRlcktpZCA9IHByb3ZpZGVyLmtpZEZvcj8uKG9yZ0lkKTtcbiAgaWYgKHByb3ZpZGVyS2lkICE9PSB1bmRlZmluZWQgJiYgYmxvYi5raWQgIT09IHVuZGVmaW5lZCAmJiBwcm92aWRlcktpZCAhPT0gYmxvYi5raWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEtNUyBrZXkgaWQgbWlzbWF0Y2g6IGJsb2Igd2FzIGVuY3J5cHRlZCB1bmRlciAke2Jsb2Iua2lkfSwgY3VycmVudCBwcm92aWRlciB1c2VzICR7cHJvdmlkZXJLaWR9IGZvciBvcmcgJHtvcmdJZH1gKTtcbiAgfVxuICBjb25zdCBrZXkgPSBwcm92aWRlci5kZXJpdmVLZXkob3JnSWQpO1xuICBjb25zdCBpdiA9IEJ1ZmZlci5mcm9tKGJsb2IuaXYsICdiYXNlNjQnKTtcbiAgY29uc3QgYWxsID0gQnVmZmVyLmZyb20oYmxvYi5jaXBoZXJ0ZXh0LCAnYmFzZTY0Jyk7XG4gIC8vIFNwbGl0IG9mZiB0aGUgMTYtYnl0ZSBhdXRoIHRhZyBhcHBlbmRlZCBpbiBlbmNyeXB0U2VjcmV0LiBBbnkgdGFtcGVyaW5nXG4gIC8vICB0byBlaXRoZXIgdGhlIGNpcGhlcnRleHQgT1IgdGhlIHRhZyAgY2F1c2VzIHRoZSBuZXh0IGBmaW5hbCgpYCB0b1xuICAvLyB0aHJvdyB3aXRoIFwiVW5zdXBwb3J0ZWQgc3RhdGUgb3IgdW5hYmxlIHRvIGF1dGhlbnRpY2F0ZSBkYXRhXCIuXG4gIGNvbnN0IHRhZyA9IGFsbC5zdWJhcnJheShhbGwubGVuZ3RoIC0gMTYpO1xuICBjb25zdCBlbmMgPSBhbGwuc3ViYXJyYXkoMCwgYWxsLmxlbmd0aCAtIDE2KTtcbiAgY29uc3QgZGVjaXBoZXIgPSBjcmVhdGVEZWNpcGhlcml2KCdhZXMtMjU2LWdjbScsIGtleSwgaXYpO1xuICBkZWNpcGhlci5zZXRBdXRoVGFnKHRhZyk7XG4gIGNvbnN0IGRlYyA9IEJ1ZmZlci5jb25jYXQoW2RlY2lwaGVyLnVwZGF0ZShlbmMpLCBkZWNpcGhlci5maW5hbCgpXSk7XG4gIHJldHVybiBkZWMudG9TdHJpbmcoJ3V0ZjgnKTtcbn1cblxuLyoqXG4gKiBUeXBlIGd1YXJkICBoYW5keSBmb3IgbW9kZWwgbGF5ZXJzIHRoYXQgaG9sZCBhIGNvbHVtbiB3aG9zZSB2YWx1ZSBtYXkgYmVcbiAqIGVpdGhlciBhIGNsZWFyLXRleHQgc3RyaW5nIChsZWdhY3kgLyB1bmVuY3J5cHRlZCkgT1IgYW4gZW5jcnlwdGVkIGJsb2JcbiAqIChwb3N0LW1pZ3JhdGlvbikuIE1peGVkIHN0YXRlcyBhcmlzZSBtaWQtbWlncmF0aW9uOyB0aGUgbW9kZWwgZGVjaWRlc1xuICogd2hhdCB0byBkbyAoZGVjcnlwdCBvbiByZWFkLCBlbmNyeXB0IG9uIG5leHQgd3JpdGUpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFbmNyeXB0ZWRCbG9iKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgRW5jcnlwdGVkQmxvYiB7XG4gIHJldHVybiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCdcbiAgICAmJiB2YWx1ZSAhPT0gbnVsbFxuICAgICYmICh2YWx1ZSBhcyB7IGFsZz86IHVua25vd24gfSkuYWxnID09PSAnYWVzLTI1Ni1nY20tdjEnXG4gICAgJiYgdHlwZW9mICh2YWx1ZSBhcyB7IGl2PzogdW5rbm93biB9KS5pdiA9PT0gJ3N0cmluZydcbiAgICAmJiB0eXBlb2YgKHZhbHVlIGFzIHsgY2lwaGVydGV4dD86IHVua25vd24gfSkuY2lwaGVydGV4dCA9PT0gJ3N0cmluZydcbiAgKTtcbn1cbiJdfQ==
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "devDependencies": {
9
9
  "@stylistic/eslint-plugin": "^2",
10
10
  "@types/express": "5.0.6",
11
- "@types/jest": "^30.0.0",
11
+ "@types/jest": "30.0.0",
12
12
  "@types/jsonwebtoken": "9.0.10",
13
13
  "@types/node": "25.3.0",
14
14
  "@typescript-eslint/eslint-plugin": "^8",
@@ -16,13 +16,16 @@
16
16
  "eslint": "^9",
17
17
  "eslint-import-resolver-typescript": "^4.4.4",
18
18
  "eslint-plugin-import": "^2.32.0",
19
- "jest": "^30.2.0",
20
- "jest-junit": "^16",
21
- "ts-jest": "^29.4.6",
19
+ "jest": "30.0.0",
20
+ "jest-junit": "^17",
21
+ "ts-jest": "^29",
22
22
  "typescript": "5.9.3"
23
23
  },
24
24
  "dependencies": {
25
25
  "@asteasolutions/zod-to-openapi": "8.4.0",
26
+ "@aws-sdk/client-kms": "3.997.0",
27
+ "@aws-sdk/client-sts": "3.997.0",
28
+ "@aws-sdk/credential-providers": "3.997.0",
26
29
  "express": "5.2.1",
27
30
  "jsonwebtoken": "9.0.3",
28
31
  "winston": "3.19.0",
@@ -66,7 +69,7 @@
66
69
  "main": "lib/index.js",
67
70
  "license": "Apache-2.0",
68
71
  "homepage": "https://mwashburn160.github.io/pipeline-builder/",
69
- "version": "3.4.35",
72
+ "version": "3.4.37",
70
73
  "bugs": {
71
74
  "url": "https://github.com/mwashburn160/pipeline-builder/issues"
72
75
  },