@workflow/core 5.0.0-beta.35 → 5.0.0-beta.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.
Files changed (137) hide show
  1. package/dist/capabilities.d.ts +6 -0
  2. package/dist/capabilities.d.ts.map +1 -1
  3. package/dist/capabilities.js +13 -1
  4. package/dist/classify-error.d.ts.map +1 -1
  5. package/dist/classify-error.js +5 -2
  6. package/dist/create-hook.d.ts +41 -22
  7. package/dist/create-hook.d.ts.map +1 -1
  8. package/dist/create-hook.js +1 -1
  9. package/dist/describe-error.d.ts.map +1 -1
  10. package/dist/describe-error.js +12 -1
  11. package/dist/encryption.d.ts +15 -2
  12. package/dist/encryption.d.ts.map +1 -1
  13. package/dist/encryption.js +28 -7
  14. package/dist/flushable-stream.d.ts +55 -0
  15. package/dist/flushable-stream.d.ts.map +1 -1
  16. package/dist/flushable-stream.js +106 -4
  17. package/dist/global.d.ts +2 -0
  18. package/dist/global.d.ts.map +1 -1
  19. package/dist/global.js +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/log-format.js +3 -3
  24. package/dist/private.d.ts +82 -50
  25. package/dist/private.d.ts.map +1 -1
  26. package/dist/private.js +149 -22
  27. package/dist/replay-payload-cache.d.ts +57 -0
  28. package/dist/replay-payload-cache.d.ts.map +1 -0
  29. package/dist/replay-payload-cache.js +143 -0
  30. package/dist/runtime/constants.d.ts +11 -0
  31. package/dist/runtime/constants.d.ts.map +1 -1
  32. package/dist/runtime/constants.js +26 -1
  33. package/dist/runtime/count-step-started-events.d.ts +52 -0
  34. package/dist/runtime/count-step-started-events.d.ts.map +1 -0
  35. package/dist/runtime/count-step-started-events.js +72 -0
  36. package/dist/runtime/get-port-lazy.js +4 -4
  37. package/dist/runtime/helpers.d.ts +47 -16
  38. package/dist/runtime/helpers.d.ts.map +1 -1
  39. package/dist/runtime/helpers.js +97 -28
  40. package/dist/runtime/resume-hook.d.ts +6 -3
  41. package/dist/runtime/resume-hook.d.ts.map +1 -1
  42. package/dist/runtime/resume-hook.js +180 -58
  43. package/dist/runtime/run.d.ts.map +1 -1
  44. package/dist/runtime/run.js +3 -3
  45. package/dist/runtime/runs.d.ts.map +1 -1
  46. package/dist/runtime/runs.js +5 -3
  47. package/dist/runtime/start.d.ts.map +1 -1
  48. package/dist/runtime/start.js +65 -18
  49. package/dist/runtime/step-executor.d.ts +48 -8
  50. package/dist/runtime/step-executor.d.ts.map +1 -1
  51. package/dist/runtime/step-executor.js +90 -20
  52. package/dist/runtime/suspension-handler.js +3 -3
  53. package/dist/runtime/world.d.ts +2 -7
  54. package/dist/runtime/world.d.ts.map +1 -1
  55. package/dist/runtime/world.js +3 -10
  56. package/dist/runtime.d.ts +1 -1
  57. package/dist/runtime.d.ts.map +1 -1
  58. package/dist/runtime.js +398 -184
  59. package/dist/sealed-box.d.ts +167 -0
  60. package/dist/sealed-box.d.ts.map +1 -0
  61. package/dist/sealed-box.js +571 -0
  62. package/dist/serialization/client.d.ts +3 -3
  63. package/dist/serialization/client.d.ts.map +1 -1
  64. package/dist/serialization/client.js +1 -1
  65. package/dist/serialization/codec.d.ts +6 -4
  66. package/dist/serialization/codec.d.ts.map +1 -1
  67. package/dist/serialization/codec.js +1 -1
  68. package/dist/serialization/encryption.d.ts +118 -17
  69. package/dist/serialization/encryption.d.ts.map +1 -1
  70. package/dist/serialization/encryption.js +131 -15
  71. package/dist/serialization/step.d.ts +4 -4
  72. package/dist/serialization/step.d.ts.map +1 -1
  73. package/dist/serialization/step.js +2 -2
  74. package/dist/serialization/types.d.ts +20 -0
  75. package/dist/serialization/types.d.ts.map +1 -1
  76. package/dist/serialization/types.js +11 -1
  77. package/dist/serialization-format.d.ts +44 -4
  78. package/dist/serialization-format.d.ts.map +1 -1
  79. package/dist/serialization-format.js +66 -9
  80. package/dist/serialization.d.ts +61 -21
  81. package/dist/serialization.d.ts.map +1 -1
  82. package/dist/serialization.js +556 -200
  83. package/dist/set-attributes.d.ts +2 -7
  84. package/dist/set-attributes.d.ts.map +1 -1
  85. package/dist/set-attributes.js +1 -6
  86. package/dist/step/context-storage.d.ts +2 -2
  87. package/dist/step/context-storage.d.ts.map +1 -1
  88. package/dist/step/context-storage.js +2 -2
  89. package/dist/step/writable-stream.d.ts.map +1 -1
  90. package/dist/step/writable-stream.js +14 -3
  91. package/dist/step.d.ts.map +1 -1
  92. package/dist/step.js +87 -22
  93. package/dist/symbols.d.ts +26 -0
  94. package/dist/symbols.d.ts.map +1 -1
  95. package/dist/symbols.js +27 -1
  96. package/dist/telemetry/semantic-conventions.d.ts +4 -4
  97. package/dist/telemetry/semantic-conventions.js +2 -2
  98. package/dist/version.d.ts +1 -1
  99. package/dist/version.js +2 -2
  100. package/dist/vm/index.d.ts.map +1 -1
  101. package/dist/vm/index.js +76 -9
  102. package/dist/workflow/abort-controller.d.ts +1 -1
  103. package/dist/workflow/abort-controller.d.ts.map +1 -1
  104. package/dist/workflow/abort-controller.js +38 -3
  105. package/dist/workflow/hook.d.ts.map +1 -1
  106. package/dist/workflow/hook.js +85 -30
  107. package/dist/workflow/index.d.ts +1 -1
  108. package/dist/workflow/index.d.ts.map +1 -1
  109. package/dist/workflow/index.js +2 -2
  110. package/dist/workflow/set-attributes.d.ts +0 -9
  111. package/dist/workflow/set-attributes.d.ts.map +1 -1
  112. package/dist/workflow/set-attributes.js +1 -6
  113. package/dist/workflow/sleep.d.ts.map +1 -1
  114. package/dist/workflow/sleep.js +21 -9
  115. package/dist/workflow.d.ts +14 -11
  116. package/dist/workflow.d.ts.map +1 -1
  117. package/dist/workflow.js +37 -92
  118. package/docs/api-reference/create-hook.mdx +43 -2
  119. package/docs/api-reference/define-hook.mdx +26 -24
  120. package/docs/api-reference/fatal-error.mdx +29 -7
  121. package/docs/api-reference/fetch.mdx +3 -4
  122. package/docs/api-reference/set-attributes.mdx +0 -4
  123. package/docs/api-reference/sleep.mdx +1 -1
  124. package/docs/foundations/hooks.mdx +1 -1
  125. package/docs/foundations/idempotency.mdx +16 -9
  126. package/docs/how-it-works/cancellation.mdx +2 -2
  127. package/docs/how-it-works/code-transform.mdx +19 -15
  128. package/docs/how-it-works/encryption.mdx +3 -3
  129. package/docs/how-it-works/event-sourcing.mdx +6 -6
  130. package/docs/how-it-works/framework-integrations.mdx +96 -342
  131. package/package.json +6 -6
  132. package/dist/runtime/step-handler.d.ts +0 -2
  133. package/dist/runtime/step-handler.d.ts.map +0 -1
  134. package/dist/runtime/step-handler.js +0 -839
  135. package/dist/step-hydration-cache.d.ts +0 -148
  136. package/dist/step-hydration-cache.d.ts.map +0 -1
  137. package/dist/step-hydration-cache.js +0 -171
@@ -0,0 +1,571 @@
1
+ import { RuntimeDecryptionError, WorkflowRuntimeError } from '@workflow/errors';
2
+ import { decrypt as aesGcmDecrypt, encrypt as aesGcmEncrypt, NONCE_LENGTH, TAG_BYTES, } from './encryption.js';
3
+ /**
4
+ * Browser-compatible sealed-box (asymmetric) encryption for cross-run writes.
5
+ *
6
+ * ## Why this exists
7
+ *
8
+ * The symmetric `encr` path requires the writer to hold the recipient run's
9
+ * key — which also grants decrypt capability. For *cross-run* writes (a hook
10
+ * resumption targeting another run, or a child workflow writing into a
11
+ * parent's forwarded `WritableStream`) that is more authority than the writer
12
+ * needs, and obtaining the symmetric key across a deployment boundary costs a
13
+ * round trip to the Vercel API.
14
+ *
15
+ * A sealed box fixes both: the writer needs only the recipient's **public**
16
+ * key, which is not secret and therefore travels on the run entity (and in
17
+ * stream descriptors) at no cost. "Encrypt-only" stops being an honor-system
18
+ * convention enforced by `importKey(raw, ['encrypt'])` and becomes a
19
+ * cryptographic guarantee — a writer holding just the public key provably
20
+ * cannot read anything.
21
+ *
22
+ * ## Key hierarchy
23
+ *
24
+ * Both keys descend from the same per-run key material `K` that
25
+ * `World.getEncryptionKeyForRun()` already returns today, so nothing about
26
+ * key acquisition, the World interface, or the Vercel API changes:
27
+ *
28
+ * ```
29
+ * K (32 bytes, per-run, = HKDF(VERCEL_DEPLOYMENT_KEY, "projectId|runId"))
30
+ * ├── AES-256 key = K used directly → 'encr' envelopes (unchanged)
31
+ * └── X25519 scalar = HKDF(K, SCALAR_INFO) → 'encp' envelopes
32
+ * └── public key = X25519 basepoint · scalar (published, not secret)
33
+ * ```
34
+ *
35
+ * `K` is therefore both an AEAD key and a key-derivation key. This is sound:
36
+ * AES-GCM never exposes its key, and HKDF-SHA256 output is computationally
37
+ * independent of the AES keystream. A strict reading of NIST SP 800-108
38
+ * prefers these roles be separated, but `K`'s direct AES use is fixed by
39
+ * backward compatibility with every `encr` payload already written.
40
+ *
41
+ * ## Construction
42
+ *
43
+ * An ECIES-style sealed box using the same primitives as HPKE (RFC 9180)
44
+ * base mode with DHKEM(X25519, HKDF-SHA256) and AES-256-GCM, but without the
45
+ * full `LabeledExtract`/`LabeledExpand` suite-ID ceremony:
46
+ *
47
+ * ```
48
+ * ephemeral = X25519 keypair, freshly generated per encryption context
49
+ * sharedSecret = X25519(ephemeralPrivate, recipientPublic)
50
+ * contentKey = HKDF-SHA256(
51
+ * ikm = sharedSecret,
52
+ * salt = zeros(32),
53
+ * info = CONTENT_KEY_INFO ‖ ephemeralPublic ‖ recipientPublic,
54
+ * )
55
+ * ```
56
+ *
57
+ * Binding both public keys into `info` is the security-critical part (it is
58
+ * HPKE's `kem_context`): it prevents key-substitution/unknown-key-share
59
+ * attacks in which an adversary replays a ciphertext as though it had been
60
+ * sealed to a different recipient. Deviating from strict RFC 9180 framing is
61
+ * a deliberate, documented choice — the envelope is versioned via its format
62
+ * prefix and the HKDF labels below, so a conformant profile can be added
63
+ * later as a new version without touching existing payloads.
64
+ *
65
+ * Wire format (the `encp` format prefix is attached by the serialization
66
+ * layer, not by this module):
67
+ *
68
+ * ```
69
+ * [ephemeral public key (32 bytes)][nonce (12 bytes)][ciphertext + GCM tag (16 bytes)]
70
+ * ```
71
+ *
72
+ * ## Nonce discipline
73
+ *
74
+ * One-shot {@link seal} generates a fresh ephemeral keypair — and therefore a
75
+ * fresh content key — for every call, so nonce reuse is impossible.
76
+ *
77
+ * Callers that amortize the KEM across many frames via {@link encapsulate}
78
+ * take on nonce discipline themselves, because the content key then outlives a
79
+ * single message. Two rules apply:
80
+ *
81
+ * 1. Every frame MUST use a fresh random nonce (which `aesGcmEncrypt` does).
82
+ * Never a counter: a counter restarts at zero after a stream reconnect or a
83
+ * durable replay, reusing `(contentKey, nonce)` — which under AES-GCM leaks
84
+ * the plaintext XOR of the two frames and the GCM auth subkey.
85
+ * 2. A writer must not inherit a previous incarnation's content key, so
86
+ * {@link encapsulate} is re-run per writer instance.
87
+ *
88
+ * Nothing in this module enforces either rule; it is the streaming caller's
89
+ * contract.
90
+ */
91
+ /** Length of an X25519 private scalar and public key, in bytes. */
92
+ const X25519_KEY_LENGTH = 32;
93
+ /** Length of the AES-256 content key derived from the shared secret. */
94
+ const CONTENT_KEY_LENGTH = 32;
95
+ /**
96
+ * HKDF `info` label for deriving the per-run X25519 scalar from the per-run
97
+ * key material.
98
+ *
99
+ * Versioned and namespaced so that any future derivation from the same `K`
100
+ * (a second keypair, a MAC key, a different curve) can never collide with
101
+ * this one.
102
+ */
103
+ const SCALAR_INFO = 'workflow/encp/x25519/v1';
104
+ /**
105
+ * HKDF `info` prefix for deriving the AES-256-GCM content key from an X25519
106
+ * shared secret. The ephemeral and recipient public keys are appended to this
107
+ * label to form the full `info` (HPKE's `kem_context`).
108
+ */
109
+ const CONTENT_KEY_INFO = 'workflow/encp/aes256gcm/v1';
110
+ /**
111
+ * DER prefix for an RFC 8410 `PrivateKeyInfo` wrapping a raw X25519 scalar.
112
+ *
113
+ * Web Crypto cannot import a raw X25519 private key (`importKey('raw', ...)`
114
+ * is only defined for public keys on the Secure Curves algorithms), so a
115
+ * derived scalar has to be wrapped in PKCS#8 before it can be used. The
116
+ * structure is fully determined for a 32-byte X25519 key:
117
+ *
118
+ * ```
119
+ * SEQUENCE (46 bytes) 30 2e
120
+ * INTEGER 0 02 01 00
121
+ * SEQUENCE (5 bytes) 30 05
122
+ * OBJECT IDENTIFIER 1.3.101.110 (X25519) 06 03 2b 65 6e
123
+ * OCTET STRING (34 bytes) 04 22
124
+ * OCTET STRING (32 bytes) 04 20
125
+ * <scalar>
126
+ * ```
127
+ */
128
+ const PKCS8_X25519_PREFIX = new Uint8Array([
129
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04,
130
+ 0x22, 0x04, 0x20,
131
+ ]);
132
+ const infoEncoder = new TextEncoder();
133
+ function assertKeyMaterialLength(runKeyMaterial) {
134
+ if (runKeyMaterial.byteLength !== CONTENT_KEY_LENGTH) {
135
+ throw new WorkflowRuntimeError(`Run key material must be exactly ${CONTENT_KEY_LENGTH} bytes, got ${runKeyMaterial.byteLength}`);
136
+ }
137
+ }
138
+ function assertPublicKeyLength(publicKey, label) {
139
+ if (publicKey.byteLength !== X25519_KEY_LENGTH) {
140
+ throw new WorkflowRuntimeError(`${label} must be exactly ${X25519_KEY_LENGTH} bytes, got ${publicKey.byteLength}`);
141
+ }
142
+ }
143
+ /**
144
+ * Derive the per-run X25519 keypair from the run's 32-byte key material.
145
+ *
146
+ * Deterministic: the same key material always yields the same keypair, which
147
+ * is what lets the owning deployment re-derive its private scalar on demand
148
+ * (from `VERCEL_DEPLOYMENT_KEY`) instead of storing it anywhere.
149
+ *
150
+ * @param runKeyMaterial - The 32 bytes returned by `World.getEncryptionKeyForRun()`
151
+ * @returns The run's X25519 scalar and public key
152
+ */
153
+ export async function deriveRunKeyPair(runKeyMaterial) {
154
+ assertKeyMaterialLength(runKeyMaterial);
155
+ const hkdfKey = await globalThis.crypto.subtle.importKey('raw', runKeyMaterial, 'HKDF', false, ['deriveBits']);
156
+ // Zero salt is acceptable per RFC 5869 §3.1: the IKM here is itself HKDF
157
+ // output (or a high-entropy BYOK value), so it is already uniform. The
158
+ // `info` label provides domain separation.
159
+ const scalarBits = await globalThis.crypto.subtle.deriveBits({
160
+ name: 'HKDF',
161
+ hash: 'SHA-256',
162
+ salt: new Uint8Array(32),
163
+ info: infoEncoder.encode(SCALAR_INFO),
164
+ }, hkdfKey, X25519_KEY_LENGTH * 8);
165
+ const scalar = new Uint8Array(scalarBits);
166
+ // Any 32-byte string is a valid X25519 scalar (the low/high bits are
167
+ // clamped during scalar multiplication), so the HKDF output needs no
168
+ // rejection sampling.
169
+ const publicKey = await derivePublicKeyFromScalar(scalar);
170
+ return { scalar, publicKey };
171
+ }
172
+ /**
173
+ * Recover the raw public key for a scalar.
174
+ *
175
+ * Web Crypto exposes no scalar-multiplication primitive, so the scalar is
176
+ * imported as a PKCS#8 private key and its public half read back out of the
177
+ * JWK export (`x`), which the Secure Curves spec defines as the base64url
178
+ * raw public key.
179
+ */
180
+ async function derivePublicKeyFromScalar(scalar) {
181
+ const privateKey = await importScalar(scalar, /* extractable */ true);
182
+ const jwk = await globalThis.crypto.subtle.exportKey('jwk', privateKey);
183
+ if (!jwk.x) {
184
+ throw new WorkflowRuntimeError('X25519 JWK export did not include a public key component ("x")');
185
+ }
186
+ const publicKey = base64UrlToBytes(jwk.x);
187
+ // Guard the one step in this module that trusts an external encoding. A
188
+ // short or malformed value here would otherwise flow onward and fail much
189
+ // later, inside key agreement, with a far less obvious message.
190
+ if (publicKey.byteLength !== X25519_KEY_LENGTH) {
191
+ throw new WorkflowRuntimeError(`X25519 JWK export produced a ${publicKey.byteLength}-byte public key, expected ${X25519_KEY_LENGTH}`);
192
+ }
193
+ return publicKey;
194
+ }
195
+ async function importScalar(scalar, extractable) {
196
+ const pkcs8 = new Uint8Array(PKCS8_X25519_PREFIX.length + scalar.byteLength);
197
+ pkcs8.set(PKCS8_X25519_PREFIX, 0);
198
+ pkcs8.set(scalar, PKCS8_X25519_PREFIX.length);
199
+ return globalThis.crypto.subtle.importKey('pkcs8', pkcs8, { name: 'X25519' }, extractable, ['deriveBits']);
200
+ }
201
+ function importPublicKey(publicKey) {
202
+ return globalThis.crypto.subtle.importKey('raw', publicKey, { name: 'X25519' },
203
+ /* extractable */ true,
204
+ // Public keys carry no usages for X25519 — the private key does the
205
+ // deriving; the public key is only ever an argument to it.
206
+ []);
207
+ }
208
+ const BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
209
+ const BASE64URL_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
210
+ /**
211
+ * Encode bytes as standard (padded) base64.
212
+ *
213
+ * Hand-rolled for the same reason as {@link base64UrlToBytes}: this module
214
+ * runs in the browser (o11y decryption) and inside the workflow VM, so neither
215
+ * `Buffer` nor `btoa` can be assumed. Used for the wire encoding of run public
216
+ * keys, matching the base64 convention already used for `VERCEL_DEPLOYMENT_KEY`
217
+ * and the `run-key` API response.
218
+ */
219
+ export function bytesToBase64(bytes) {
220
+ let out = '';
221
+ for (let i = 0; i < bytes.length; i += 3) {
222
+ const b0 = bytes[i];
223
+ const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
224
+ const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
225
+ out += BASE64_CHARS[(b0 >> 2) & 0x3f];
226
+ out += BASE64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0f)];
227
+ out +=
228
+ i + 1 < bytes.length
229
+ ? BASE64_CHARS[((b1 & 0x0f) << 2) | ((b2 >> 6) & 0x03)]
230
+ : '=';
231
+ out += i + 2 < bytes.length ? BASE64_CHARS[b2 & 0x3f] : '=';
232
+ }
233
+ return out;
234
+ }
235
+ /**
236
+ * Decode standard base64 (padding optional) to bytes.
237
+ *
238
+ * Returns `undefined` for malformed input rather than throwing: callers decode
239
+ * public keys that arrive from storage or over the wire, where a corrupt value
240
+ * should degrade to "this run has no usable public key" (and fall back to the
241
+ * symmetric path) rather than crash a resumption.
242
+ *
243
+ * Validation is strict, because a lenient decoder is worse than a throwing one
244
+ * here — silently returning a short or truncated key makes a corrupt value look
245
+ * *present*, so the caller seals to garbage instead of taking the fallback.
246
+ * Rejected: characters outside the alphabet, a length that cannot describe a
247
+ * whole number of bytes (`length % 4 === 1`), padding anywhere but the end, and
248
+ * a final quantum whose unused low bits are not zero.
249
+ */
250
+ export function base64ToBytes(value) {
251
+ // Strip trailing padding, then require what remains to be padding-free.
252
+ let end = value.length;
253
+ while (end > 0 && value[end - 1] === '=')
254
+ end--;
255
+ const body = value.slice(0, end);
256
+ if (body.includes('='))
257
+ return undefined;
258
+ // 4 chars -> 3 bytes; 3 -> 2; 2 -> 1. A remainder of 1 encodes no byte.
259
+ if (body.length % 4 === 1)
260
+ return undefined;
261
+ // Padding, when present, must bring the total to a multiple of 4.
262
+ if (end !== value.length && value.length % 4 !== 0)
263
+ return undefined;
264
+ let accumulator = 0;
265
+ let bitCount = 0;
266
+ const bytes = [];
267
+ for (let i = 0; i < body.length; i++) {
268
+ const index = BASE64_CHARS.indexOf(body[i]);
269
+ if (index === -1)
270
+ return undefined;
271
+ accumulator = (accumulator << 6) | index;
272
+ bitCount += 6;
273
+ if (bitCount >= 8) {
274
+ bitCount -= 8;
275
+ bytes.push((accumulator >> bitCount) & 0xff);
276
+ }
277
+ }
278
+ // Leftover bits belong to no byte and must be zero in canonical base64.
279
+ if (bitCount > 0 && (accumulator & ((1 << bitCount) - 1)) !== 0) {
280
+ return undefined;
281
+ }
282
+ return new Uint8Array(bytes);
283
+ }
284
+ /**
285
+ * Decode a base64url string (JWK encoding) to bytes.
286
+ *
287
+ * Hand-rolled rather than using `atob` or `Buffer`: this module also runs
288
+ * inside the workflow VM, whose global surface is deliberately minimal and
289
+ * does not include either. The inputs here are fixed-size JWK key components,
290
+ * so a compact decoder is sufficient — it accepts unpadded base64url only,
291
+ * which is what RFC 7515 §2 mandates for JWK members.
292
+ */
293
+ function base64UrlToBytes(value) {
294
+ let accumulator = 0;
295
+ let bitCount = 0;
296
+ const bytes = [];
297
+ for (let i = 0; i < value.length; i++) {
298
+ const char = value[i];
299
+ if (char === '=')
300
+ break;
301
+ const index = BASE64URL_CHARS.indexOf(char);
302
+ if (index === -1) {
303
+ throw new WorkflowRuntimeError(`Invalid base64url character "${char}" in X25519 JWK key component`);
304
+ }
305
+ accumulator = (accumulator << 6) | index;
306
+ bitCount += 6;
307
+ if (bitCount >= 8) {
308
+ bitCount -= 8;
309
+ bytes.push((accumulator >> bitCount) & 0xff);
310
+ }
311
+ }
312
+ return new Uint8Array(bytes);
313
+ }
314
+ /**
315
+ * Derive the AES-256-GCM content key from an X25519 shared secret, binding
316
+ * it to both public keys (HPKE's `kem_context`).
317
+ */
318
+ async function deriveContentKey(sharedSecret, ephemeralPublicKey, recipientPublicKey, usages) {
319
+ const label = infoEncoder.encode(CONTENT_KEY_INFO);
320
+ const info = new Uint8Array(label.length + ephemeralPublicKey.length + recipientPublicKey.length);
321
+ info.set(label, 0);
322
+ info.set(ephemeralPublicKey, label.length);
323
+ info.set(recipientPublicKey, label.length + ephemeralPublicKey.length);
324
+ const hkdfKey = await globalThis.crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false, ['deriveBits']);
325
+ const contentKeyBits = await globalThis.crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(32), info }, hkdfKey, CONTENT_KEY_LENGTH * 8);
326
+ return globalThis.crypto.subtle.importKey('raw', new Uint8Array(contentKeyBits), 'AES-GCM', false,
327
+ // `KeyUsage` is a DOM-lib type that is not in scope under `es2022`; the
328
+ // parameter type is a strict subset of it, so this cast is sound.
329
+ usages);
330
+ }
331
+ /**
332
+ * The writer half of the KEM: generate an ephemeral keypair and derive a
333
+ * content key for a recipient's public key.
334
+ *
335
+ * Use this when many payloads share one KEM operation — i.e. stream frames.
336
+ * The returned `contentKey` can only encrypt, so a stream writer provably
337
+ * cannot read the recipient run's data even by mistake.
338
+ *
339
+ * **Callers own nonce discipline.** Encrypt each frame with a fresh random
340
+ * nonce, and call this function again for every new connection attempt or
341
+ * replay so that a restarted writer never reuses a content key. For one-shot
342
+ * payloads prefer {@link seal}, which handles this automatically.
343
+ *
344
+ * @param recipientPublicKey - The recipient run's raw 32-byte X25519 public key
345
+ * @returns The ephemeral public key to publish alongside the ciphertext, and
346
+ * the encrypt-only content key
347
+ */
348
+ export async function encapsulate(recipientPublicKey) {
349
+ assertPublicKeyLength(recipientPublicKey, 'Recipient public key');
350
+ let recipientKey;
351
+ try {
352
+ recipientKey = await importPublicKey(recipientPublicKey);
353
+ }
354
+ catch (cause) {
355
+ throw new WorkflowRuntimeError(`Invalid X25519 recipient public key: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
356
+ }
357
+ const ephemeral = (await globalThis.crypto.subtle.generateKey({ name: 'X25519' },
358
+ /* extractable */ true, ['deriveBits']));
359
+ const ephemeralPublicKey = new Uint8Array(await globalThis.crypto.subtle.exportKey('raw', ephemeral.publicKey));
360
+ let sharedSecretBits;
361
+ try {
362
+ sharedSecretBits = await globalThis.crypto.subtle.deriveBits({ name: 'X25519', public: recipientKey }, ephemeral.privateKey, X25519_KEY_LENGTH * 8);
363
+ }
364
+ catch (cause) {
365
+ // Web Crypto throws OperationError when the shared secret is all-zero,
366
+ // which happens exactly when the recipient public key is a low-order
367
+ // point. This is the platform giving us HPKE's contributory-behavior
368
+ // check for free.
369
+ throw new WorkflowRuntimeError('X25519 key agreement failed: the recipient public key is not a valid ' +
370
+ 'curve point (low-order point or corrupted key material)', { cause });
371
+ }
372
+ const contentKey = await deriveContentKey(new Uint8Array(sharedSecretBits), ephemeralPublicKey, recipientPublicKey, ['encrypt']);
373
+ return { ephemeralPublicKey, contentKey };
374
+ }
375
+ /**
376
+ * The recipient half of the KEM: recover the content key for a sealed
377
+ * payload from the run's own keypair and the sender's ephemeral public key.
378
+ *
379
+ * @param keyPair - The recipient run's keypair, from {@link deriveRunKeyPair}
380
+ * @param ephemeralPublicKey - The sender's raw 32-byte X25519 public key,
381
+ * read from the head of the sealed envelope
382
+ * @returns A decrypt-only content key
383
+ */
384
+ export async function decapsulate(keyPair, ephemeralPublicKey) {
385
+ if (ephemeralPublicKey.byteLength !== X25519_KEY_LENGTH) {
386
+ throw new RuntimeDecryptionError(`Sealed payload has a malformed ephemeral public key: expected ${X25519_KEY_LENGTH} bytes, got ${ephemeralPublicKey.byteLength}`, {
387
+ context: {
388
+ operation: 'decrypt',
389
+ byteLength: ephemeralPublicKey.byteLength,
390
+ },
391
+ });
392
+ }
393
+ let sharedSecretBits;
394
+ try {
395
+ const [privateKey, senderKey] = await Promise.all([
396
+ importScalar(keyPair.scalar, /* extractable */ false),
397
+ importPublicKey(ephemeralPublicKey),
398
+ ]);
399
+ sharedSecretBits = await globalThis.crypto.subtle.deriveBits({ name: 'X25519', public: senderKey }, privateKey, X25519_KEY_LENGTH * 8);
400
+ }
401
+ catch (cause) {
402
+ throw new RuntimeDecryptionError(`X25519 key agreement failed while opening a sealed payload: ${cause instanceof Error ? cause.message : String(cause)}`, {
403
+ cause,
404
+ context: {
405
+ operation: 'decrypt',
406
+ byteLength: ephemeralPublicKey.byteLength,
407
+ },
408
+ });
409
+ }
410
+ return deriveContentKey(new Uint8Array(sharedSecretBits), ephemeralPublicKey, keyPair.publicKey, ['decrypt']);
411
+ }
412
+ /**
413
+ * Seal a payload to a run's public key.
414
+ *
415
+ * Each call performs its own KEM operation, so every sealed payload gets an
416
+ * independent content key — nonce reuse across calls is impossible by
417
+ * construction.
418
+ *
419
+ * @param recipientPublicKey - The recipient run's raw 32-byte X25519 public key
420
+ * @param data - Plaintext to seal
421
+ * @param aad - Optional additional authenticated data, covered by the GCM tag
422
+ * but not encrypted. Callers pass the recipient's `projectId|runId` so a
423
+ * sealed payload cannot be replayed against a different run.
424
+ * @returns `[ephemeral public key (32)][nonce (12)][ciphertext + tag]`
425
+ */
426
+ export async function seal(recipientPublicKey, data, aad) {
427
+ const { ephemeralPublicKey, contentKey } = await encapsulate(recipientPublicKey);
428
+ const encrypted = await aesGcmEncrypt(contentKey, data, aad);
429
+ const result = new Uint8Array(ephemeralPublicKey.byteLength + encrypted.byteLength);
430
+ result.set(ephemeralPublicKey, 0);
431
+ result.set(encrypted, ephemeralPublicKey.byteLength);
432
+ return result;
433
+ }
434
+ /**
435
+ * Open a payload sealed to this run's public key.
436
+ *
437
+ * @param keyPair - The recipient run's keypair, from {@link deriveRunKeyPair}
438
+ * @param sealed - `[ephemeral public key (32)][nonce (12)][ciphertext + tag]`
439
+ * @param aad - The exact additional authenticated data passed to {@link seal}
440
+ * @returns The decrypted plaintext
441
+ */
442
+ export async function open(keyPair, sealed, aad) {
443
+ // Ephemeral public key + AES-GCM nonce + AES-GCM tag.
444
+ const minLength = X25519_KEY_LENGTH + NONCE_LENGTH + TAG_BYTES;
445
+ if (sealed.byteLength < minLength) {
446
+ throw new RuntimeDecryptionError(`Sealed payload too short: expected at least ${minLength} bytes, got ${sealed.byteLength}`, { context: { operation: 'decrypt', byteLength: sealed.byteLength } });
447
+ }
448
+ const ephemeralPublicKey = sealed.subarray(0, X25519_KEY_LENGTH);
449
+ const encrypted = sealed.subarray(X25519_KEY_LENGTH);
450
+ const contentKey = await decapsulate(keyPair, ephemeralPublicKey);
451
+ return aesGcmDecrypt(contentKey, encrypted, aad);
452
+ }
453
+ /**
454
+ * A writer-side session that amortizes one KEM operation across many sealed
455
+ * payloads — use it for streams, where one-shot {@link seal} would perform a
456
+ * fresh keygen + ECDH + HKDF for every frame.
457
+ *
458
+ * Safety rests on two properties:
459
+ *
460
+ * - Every payload still gets a **fresh random nonce** from `aesGcmEncrypt`, so
461
+ * sharing the content key does not risk `(key, nonce)` reuse. (A counter
462
+ * would: it restarts at zero whenever a writer restarts.)
463
+ * - The session is bound to one writer instance. A reconnect or a durable
464
+ * replay constructs a new session, so a restarted writer never inherits a
465
+ * previous incarnation's content key.
466
+ *
467
+ * The envelope layout is byte-identical to {@link seal}, so a reader cannot
468
+ * tell which was used and needs no matching session.
469
+ */
470
+ export function createSealSession(recipientPublicKey, aad) {
471
+ let encapsulation;
472
+ return {
473
+ async seal(data) {
474
+ // Lazily, so constructing a session for a stream that is never written
475
+ // to costs nothing.
476
+ encapsulation ??= encapsulate(recipientPublicKey);
477
+ const { ephemeralPublicKey, contentKey } = await encapsulation;
478
+ const encrypted = await aesGcmEncrypt(contentKey, data, aad);
479
+ const result = new Uint8Array(ephemeralPublicKey.byteLength + encrypted.byteLength);
480
+ result.set(ephemeralPublicKey, 0);
481
+ result.set(encrypted, ephemeralPublicKey.byteLength);
482
+ return result;
483
+ },
484
+ };
485
+ }
486
+ /**
487
+ * A reader-side session that caches decapsulation per sender.
488
+ *
489
+ * The mirror of {@link createSealSession}: because every frame from one writer
490
+ * carries the same ephemeral public key, this turns an ECDH per frame into an
491
+ * ECDH per writer. Correctness does not depend on the writer having used a
492
+ * session — a stream of independently sealed payloads simply misses the cache
493
+ * on each new ephemeral key.
494
+ *
495
+ * The cache is keyed by the ephemeral public key and holds one entry, which is
496
+ * the common case (one writer per stream). A second writer evicts the first
497
+ * rather than growing without bound.
498
+ */
499
+ export function createOpenSession(keyPair, aad) {
500
+ let cachedSender;
501
+ let cachedKey;
502
+ return {
503
+ async open(sealed) {
504
+ const minLength = X25519_KEY_LENGTH + NONCE_LENGTH + TAG_BYTES;
505
+ if (sealed.byteLength < minLength) {
506
+ throw new RuntimeDecryptionError(`Sealed payload too short: expected at least ${minLength} bytes, got ${sealed.byteLength}`, { context: { operation: 'decrypt', byteLength: sealed.byteLength } });
507
+ }
508
+ const ephemeralPublicKey = sealed.subarray(0, X25519_KEY_LENGTH);
509
+ const encrypted = sealed.subarray(X25519_KEY_LENGTH);
510
+ const sender = keyCacheId(ephemeralPublicKey);
511
+ if (sender !== cachedSender || !cachedKey) {
512
+ cachedSender = sender;
513
+ cachedKey = decapsulate(keyPair, ephemeralPublicKey);
514
+ }
515
+ let contentKey;
516
+ try {
517
+ contentKey = await cachedKey;
518
+ }
519
+ catch (error) {
520
+ // Do not let one bad frame poison the cache for subsequent frames.
521
+ cachedSender = undefined;
522
+ cachedKey = undefined;
523
+ throw error;
524
+ }
525
+ return aesGcmDecrypt(contentKey, encrypted, aad);
526
+ },
527
+ };
528
+ }
529
+ /** Stable cache key for a 32-byte public key. */
530
+ function keyCacheId(publicKey) {
531
+ let id = '';
532
+ for (let i = 0; i < publicKey.length; i++) {
533
+ id += publicKey[i].toString(16).padStart(2, '0');
534
+ }
535
+ return id;
536
+ }
537
+ /**
538
+ * Build the additional authenticated data that binds a sealed payload to a
539
+ * specific run.
540
+ *
541
+ * Mirrors the `info` used for symmetric per-run key derivation so the two
542
+ * schemes agree on what "this run" means.
543
+ *
544
+ * Note that the sealed-box construction already binds a payload to its
545
+ * recipient without any AAD: the content key is derived over
546
+ * `ephemeralPublicKey ‖ recipientPublicKey`, and a recipient public key is
547
+ * unique per (deployment key × project × run). Replaying a sealed payload at
548
+ * a different run therefore fails at key agreement regardless. AAD is
549
+ * available for callers that want an additional, KDF-independent binding —
550
+ * both sides must supply byte-identical values or the payload will not open.
551
+ */
552
+ export function runAad(projectId, runId) {
553
+ return infoEncoder.encode(`${projectId}|${runId}`);
554
+ }
555
+ /**
556
+ * Decode a run's published public key, validating both encoding and length.
557
+ *
558
+ * Returns `undefined` when the value is absent, not valid base64, or not
559
+ * exactly 32 bytes. Callers treat that as "this run has no usable public key"
560
+ * and fall back to the symmetric path, so a corrupt or truncated stored value
561
+ * degrades to the pre-existing behavior instead of failing a resumption.
562
+ */
563
+ export function decodeRunPublicKey(value) {
564
+ if (!value)
565
+ return undefined;
566
+ const bytes = base64ToBytes(value);
567
+ if (!bytes || bytes.byteLength !== X25519_KEY_LENGTH)
568
+ return undefined;
569
+ return bytes;
570
+ }
571
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhbGVkLWJveC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zZWFsZWQtYm94LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hGLE9BQU8sRUFDTCxPQUFPLElBQUksYUFBYSxFQUN4QixPQUFPLElBQUksYUFBYSxFQUV4QixZQUFZLEVBQ1osU0FBUyxHQUNWLE1BQU0saUJBQWlCLENBQUM7QUFFekI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVGRztBQUVILG1FQUFtRTtBQUNuRSxNQUFNLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztBQUU3Qix3RUFBd0U7QUFDeEUsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7QUFFOUI7Ozs7Ozs7R0FPRztBQUNILE1BQU0sV0FBVyxHQUFHLHlCQUF5QixDQUFDO0FBRTlDOzs7O0dBSUc7QUFDSCxNQUFNLGdCQUFnQixHQUFHLDRCQUE0QixDQUFDO0FBRXREOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNILE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxVQUFVLENBQUM7SUFDekMsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSTtJQUM1RSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUk7Q0FDakIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxXQUFXLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQWV0QyxTQUFTLHVCQUF1QixDQUFDLGNBQTBCO0lBQ3pELElBQUksY0FBYyxDQUFDLFVBQVUsS0FBSyxrQkFBa0IsRUFB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Q2hDLEtBQXlCO0lBRXpCLElBQUksQ0FBQyxLQUFLO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDN0IsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25DLElBQUksQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDLFVBQVUsS0FBSyxpQkFBaUI7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUN2RSxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSdW50aW1lRGVjcnlwdGlvbkVycm9yLCBXb3JrZmxvd1J1bnRpbWVFcnJvciB9IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHtcbiAgZGVjcnlwdCBhcyBhZXNHY21EZWNyeXB0LFxuICBlbmNyeXB0IGFzIGFlc0djbUVuY3J5cHQsXG4gIHR5cGUgQ3J5cHRvS2V5LFxuICBOT05DRV9MRU5HVEgsXG4gIFRBR19CWVRFUyxcbn0gZnJvbSAnLi9lbmNyeXB0aW9uLmpzJztcblxuLyoqXG4gKiBCcm93c2VyLWNvbXBhdGlibGUgc2VhbGVkLWJveCAoYXN5bW1ldHJpYykgZW5jcnlwdGlvbiBmb3IgY3Jvc3MtcnVuIHdyaXRlcy5cbiAqXG4gKiAjIyBXaHkgdGhpcyBleGlzdHNcbiAqXG4gKiBUaGUgc3ltbWV0cmljIGBlbmNyYCBwYXRoIHJlcXVpcmVzIHRoZSB3cml0ZXIgdG8gaG9sZCB0aGUgcmVjaXBpZW50IHJ1bidzXG4gKiBrZXkg4oCUIHdoaWNoIGFsc28gZ3JhbnRzIGRlY3J5cHQgY2FwYWJpbGl0eS4gRm9yICpjcm9zcy1ydW4qIHdyaXRlcyAoYSBob29rXG4gKiByZXN1bXB0aW9uIHRhcmdldGluZyBhbm90aGVyIHJ1biwgb3IgYSBjaGlsZCB3b3JrZmxvdyB3cml0aW5nIGludG8gYVxuICogcGFyZW50J3MgZm9yd2FyZGVkIGBXcml0YWJsZVN0cmVhbWApIHRoYXQgaXMgbW9yZSBhdXRob3JpdHkgdGhhbiB0aGUgd3JpdGVyXG4gKiBuZWVkcywgYW5kIG9idGFpbmluZyB0aGUgc3ltbWV0cmljIGtleSBhY3Jvc3MgYSBkZXBsb3ltZW50IGJvdW5kYXJ5IGNvc3RzIGFcbiAqIHJvdW5kIHRyaXAgdG8gdGhlIFZlcmNlbCBBUEkuXG4gKlxuICogQSBzZWFsZWQgYm94IGZpeGVzIGJvdGg6IHRoZSB3cml0ZXIgbmVlZHMgb25seSB0aGUgcmVjaXBpZW50J3MgKipwdWJsaWMqKlxuICoga2V5LCB3aGljaCBpcyBub3Qgc2VjcmV0IGFuZCB0aGVyZWZvcmUgdHJhdmVscyBvbiB0aGUgcnVuIGVudGl0eSAoYW5kIGluXG4gKiBzdHJlYW0gZGVzY3JpcHRvcnMpIGF0IG5vIGNvc3QuIFwiRW5jcnlwdC1vbmx5XCIgc3RvcHMgYmVpbmcgYW4gaG9ub3Itc3lzdGVtXG4gKiBjb252ZW50aW9uIGVuZm9yY2VkIGJ5IGBpbXBvcnRLZXkocmF3LCBbJ2VuY3J5cHQnXSlgIGFuZCBiZWNvbWVzIGFcbiAqIGNyeXB0b2dyYXBoaWMgZ3VhcmFudGVlIOKAlCBhIHdyaXRlciBob2xkaW5nIGp1c3QgdGhlIHB1YmxpYyBrZXkgcHJvdmFibHlcbiAqIGNhbm5vdCByZWFkIGFueXRoaW5nLlxuICpcbiAqICMjIEtleSBoaWVyYXJjaHlcbiAqXG4gKiBCb3RoIGtleXMgZGVzY2VuZCBmcm9tIHRoZSBzYW1lIHBlci1ydW4ga2V5IG1hdGVyaWFsIGBLYCB0aGF0XG4gKiBgV29ybGQuZ2V0RW5jcnlwdGlvbktleUZvclJ1bigpYCBhbHJlYWR5IHJldHVybnMgdG9kYXksIHNvIG5vdGhpbmcgYWJvdXRcbiAqIGtleSBhY3F1aXNpdGlvbiwgdGhlIFdvcmxkIGludGVyZmFjZSwgb3IgdGhlIFZlcmNlbCBBUEkgY2hhbmdlczpcbiAqXG4gKiBgYGBcbiAqIEsgICgzMiBieXRlcywgcGVyLXJ1biwgPSBIS0RGKFZFUkNFTF9ERVBMT1lNRU5UX0tFWSwgXCJwcm9qZWN0SWR8cnVuSWRcIikpXG4gKiDilJzilIDilIAgQUVTLTI1NiBrZXkgPSBLIHVzZWQgZGlyZWN0bHkgICAgICAgICAgICDihpIgJ2VuY3InIGVudmVsb3BlcyAodW5jaGFuZ2VkKVxuICog4pSU4pSA4pSAIFgyNTUxOSBzY2FsYXIgPSBIS0RGKEssIFNDQUxBUl9JTkZPKSAgICAg4oaSICdlbmNwJyBlbnZlbG9wZXNcbiAqICAgICDilJTilIDilIAgcHVibGljIGtleSA9IFgyNTUxOSBiYXNlcG9pbnQgwrcgc2NhbGFyICAgKHB1Ymxpc2hlZCwgbm90IHNlY3JldClcbiAqIGBgYFxuICpcbiAqIGBLYCBpcyB0aGVyZWZvcmUgYm90aCBhbiBBRUFEIGtleSBhbmQgYSBrZXktZGVyaXZhdGlvbiBrZXkuIFRoaXMgaXMgc291bmQ6XG4gKiBBRVMtR0NNIG5ldmVyIGV4cG9zZXMgaXRzIGtleSwgYW5kIEhLREYtU0hBMjU2IG91dHB1dCBpcyBjb21wdXRhdGlvbmFsbHlcbiAqIGluZGVwZW5kZW50IG9mIHRoZSBBRVMga2V5c3RyZWFtLiBBIHN0cmljdCByZWFkaW5nIG9mIE5JU1QgU1AgODAwLTEwOFxuICogcHJlZmVycyB0aGVzZSByb2xlcyBiZSBzZXBhcmF0ZWQsIGJ1dCBgS2AncyBkaXJlY3QgQUVTIHVzZSBpcyBmaXhlZCBieVxuICogYmFja3dhcmQgY29tcGF0aWJpbGl0eSB3aXRoIGV2ZXJ5IGBlbmNyYCBwYXlsb2FkIGFscmVhZHkgd3JpdHRlbi5cbiAqXG4gKiAjIyBDb25zdHJ1Y3Rpb25cbiAqXG4gKiBBbiBFQ0lFUy1zdHlsZSBzZWFsZWQgYm94IHVzaW5nIHRoZSBzYW1lIHByaW1pdGl2ZXMgYXMgSFBLRSAoUkZDIDkxODApXG4gKiBiYXNlIG1vZGUgd2l0aCBESEtFTShYMjU1MTksIEhLREYtU0hBMjU2KSBhbmQgQUVTLTI1Ni1HQ00sIGJ1dCB3aXRob3V0IHRoZVxuICogZnVsbCBgTGFiZWxlZEV4dHJhY3RgL2BMYWJlbGVkRXhwYW5kYCBzdWl0ZS1JRCBjZXJlbW9ueTpcbiAqXG4gKiBgYGBcbiAqIGVwaGVtZXJhbCAgICA9IFgyNTUxOSBrZXlwYWlyLCBmcmVzaGx5IGdlbmVyYXRlZCBwZXIgZW5jcnlwdGlvbiBjb250ZXh0XG4gKiBzaGFyZWRTZWNyZXQgPSBYMjU1MTkoZXBoZW1lcmFsUHJpdmF0ZSwgcmVjaXBpZW50UHVibGljKVxuICogY29udGVudEtleSAgID0gSEtERi1TSEEyNTYoXG4gKiAgICAgICAgICAgICAgICAgIGlrbSAgPSBzaGFyZWRTZWNyZXQsXG4gKiAgICAgICAgICAgICAgICAgIHNhbHQgPSB6ZXJvcygzMiksXG4gKiAgICAgICAgICAgICAgICAgIGluZm8gPSBDT05URU5UX0tFWV9JTkZPIOKAliBlcGhlbWVyYWxQdWJsaWMg4oCWIHJlY2lwaWVudFB1YmxpYyxcbiAqICAgICAgICAgICAgICAgIClcbiAqIGBgYFxuICpcbiAqIEJpbmRpbmcgYm90aCBwdWJsaWMga2V5cyBpbnRvIGBpbmZvYCBpcyB0aGUgc2VjdXJpdHktY3JpdGljYWwgcGFydCAoaXQgaXNcbiAqIEhQS0UncyBga2VtX2NvbnRleHRgKTogaXQgcHJldmVudHMga2V5LXN1YnN0aXR1dGlvbi91bmtub3duLWtleS1zaGFyZVxuICogYXR0YWNrcyBpbiB3aGljaCBhbiBhZHZlcnNhcnkgcmVwbGF5cyBhIGNpcGhlcnRleHQgYXMgdGhvdWdoIGl0IGhhZCBiZWVuXG4gKiBzZWFsZWQgdG8gYSBkaWZmZXJlbnQgcmVjaXBpZW50LiBEZXZpYXRpbmcgZnJvbSBzdHJpY3QgUkZDIDkxODAgZnJhbWluZyBpc1xuICogYSBkZWxpYmVyYXRlLCBkb2N1bWVudGVkIGNob2ljZSDigJQgdGhlIGVudmVsb3BlIGlzIHZlcnNpb25lZCB2aWEgaXRzIGZvcm1hdFxuICogcHJlZml4IGFuZCB0aGUgSEtERiBsYWJlbHMgYmVsb3csIHNvIGEgY29uZm9ybWFudCBwcm9maWxlIGNhbiBiZSBhZGRlZFxuICogbGF0ZXIgYXMgYSBuZXcgdmVyc2lvbiB3aXRob3V0IHRvdWNoaW5nIGV4aXN0aW5nIHBheWxvYWRzLlxuICpcbiAqIFdpcmUgZm9ybWF0ICh0aGUgYGVuY3BgIGZvcm1hdCBwcmVmaXggaXMgYXR0YWNoZWQgYnkgdGhlIHNlcmlhbGl6YXRpb25cbiAqIGxheWVyLCBub3QgYnkgdGhpcyBtb2R1bGUpOlxuICpcbiAqIGBgYFxuICogW2VwaGVtZXJhbCBwdWJsaWMga2V5ICgzMiBieXRlcyldW25vbmNlICgxMiBieXRlcyldW2NpcGhlcnRleHQgKyBHQ00gdGFnICgxNiBieXRlcyldXG4gKiBgYGBcbiAqXG4gKiAjIyBOb25jZSBkaXNjaXBsaW5lXG4gKlxuICogT25lLXNob3Qge0BsaW5rIHNlYWx9IGdlbmVyYXRlcyBhIGZyZXNoIGVwaGVtZXJhbCBrZXlwYWlyIOKAlCBhbmQgdGhlcmVmb3JlIGFcbiAqIGZyZXNoIGNvbnRlbnQga2V5IOKAlCBmb3IgZXZlcnkgY2FsbCwgc28gbm9uY2UgcmV1c2UgaXMgaW1wb3NzaWJsZS5cbiAqXG4gKiBDYWxsZXJzIHRoYXQgYW1vcnRpemUgdGhlIEtFTSBhY3Jvc3MgbWFueSBmcmFtZXMgdmlhIHtAbGluayBlbmNhcHN1bGF0ZX1cbiAqIHRha2Ugb24gbm9uY2UgZGlzY2lwbGluZSB0aGVtc2VsdmVzLCBiZWNhdXNlIHRoZSBjb250ZW50IGtleSB0aGVuIG91dGxpdmVzIGFcbiAqIHNpbmdsZSBtZXNzYWdlLiBUd28gcnVsZXMgYXBwbHk6XG4gKlxuICogMS4gRXZlcnkgZnJhbWUgTVVTVCB1c2UgYSBmcmVzaCByYW5kb20gbm9uY2UgKHdoaWNoIGBhZXNHY21FbmNyeXB0YCBkb2VzKS5cbiAqICAgIE5ldmVyIGEgY291bnRlcjogYSBjb3VudGVyIHJlc3RhcnRzIGF0IHplcm8gYWZ0ZXIgYSBzdHJlYW0gcmVjb25uZWN0IG9yIGFcbiAqICAgIGR1cmFibGUgcmVwbGF5LCByZXVzaW5nIGAoY29udGVudEtleSwgbm9uY2UpYCDigJQgd2hpY2ggdW5kZXIgQUVTLUdDTSBsZWFrc1xuICogICAgdGhlIHBsYWludGV4dCBYT1Igb2YgdGhlIHR3byBmcmFtZXMgYW5kIHRoZSBHQ00gYXV0aCBzdWJrZXkuXG4gKiAyLiBBIHdyaXRlciBtdXN0IG5vdCBpbmhlcml0IGEgcHJldmlvdXMgaW5jYXJuYXRpb24ncyBjb250ZW50IGtleSwgc29cbiAqICAgIHtAbGluayBlbmNhcHN1bGF0ZX0gaXMgcmUtcnVuIHBlciB3cml0ZXIgaW5zdGFuY2UuXG4gKlxuICogTm90aGluZyBpbiB0aGlzIG1vZHVsZSBlbmZvcmNlcyBlaXRoZXIgcnVsZTsgaXQgaXMgdGhlIHN0cmVhbWluZyBjYWxsZXInc1xuICogY29udHJhY3QuXG4gKi9cblxuLyoqIExlbmd0aCBvZiBhbiBYMjU1MTkgcHJpdmF0ZSBzY2FsYXIgYW5kIHB1YmxpYyBrZXksIGluIGJ5dGVzLiAqL1xuY29uc3QgWDI1NTE5X0tFWV9MRU5HVEggPSAzMjtcblxuLyoqIExlbmd0aCBvZiB0aGUgQUVTLTI1NiBjb250ZW50IGtleSBkZXJpdmVkIGZyb20gdGhlIHNoYXJlZCBzZWNyZXQuICovXG5jb25zdCBDT05URU5UX0tFWV9MRU5HVEggPSAzMjtcblxuLyoqXG4gKiBIS0RGIGBpbmZvYCBsYWJlbCBmb3IgZGVyaXZpbmcgdGhlIHBlci1ydW4gWDI1NTE5IHNjYWxhciBmcm9tIHRoZSBwZXItcnVuXG4gKiBrZXkgbWF0ZXJpYWwuXG4gKlxuICogVmVyc2lvbmVkIGFuZCBuYW1lc3BhY2VkIHNvIHRoYXQgYW55IGZ1dHVyZSBkZXJpdmF0aW9uIGZyb20gdGhlIHNhbWUgYEtgXG4gKiAoYSBzZWNvbmQga2V5cGFpciwgYSBNQUMga2V5LCBhIGRpZmZlcmVudCBjdXJ2ZSkgY2FuIG5ldmVyIGNvbGxpZGUgd2l0aFxuICogdGhpcyBvbmUuXG4gKi9cbmNvbnN0IFNDQUxBUl9JTkZPID0gJ3dvcmtmbG93L2VuY3AveDI1NTE5L3YxJztcblxuLyoqXG4gKiBIS0RGIGBpbmZvYCBwcmVmaXggZm9yIGRlcml2aW5nIHRoZSBBRVMtMjU2LUdDTSBjb250ZW50IGtleSBmcm9tIGFuIFgyNTUxOVxuICogc2hhcmVkIHNlY3JldC4gVGhlIGVwaGVtZXJhbCBhbmQgcmVjaXBpZW50IHB1YmxpYyBrZXlzIGFyZSBhcHBlbmRlZCB0byB0aGlzXG4gKiBsYWJlbCB0byBmb3JtIHRoZSBmdWxsIGBpbmZvYCAoSFBLRSdzIGBrZW1fY29udGV4dGApLlxuICovXG5jb25zdCBDT05URU5UX0tFWV9JTkZPID0gJ3dvcmtmbG93L2VuY3AvYWVzMjU2Z2NtL3YxJztcblxuLyoqXG4gKiBERVIgcHJlZml4IGZvciBhbiBSRkMgODQxMCBgUHJpdmF0ZUtleUluZm9gIHdyYXBwaW5nIGEgcmF3IFgyNTUxOSBzY2FsYXIuXG4gKlxuICogV2ViIENyeXB0byBjYW5ub3QgaW1wb3J0IGEgcmF3IFgyNTUxOSBwcml2YXRlIGtleSAoYGltcG9ydEtleSgncmF3JywgLi4uKWBcbiAqIGlzIG9ubHkgZGVmaW5lZCBmb3IgcHVibGljIGtleXMgb24gdGhlIFNlY3VyZSBDdXJ2ZXMgYWxnb3JpdGhtcyksIHNvIGFcbiAqIGRlcml2ZWQgc2NhbGFyIGhhcyB0byBiZSB3cmFwcGVkIGluIFBLQ1MjOCBiZWZvcmUgaXQgY2FuIGJlIHVzZWQuIFRoZVxuICogc3RydWN0dXJlIGlzIGZ1bGx5IGRldGVybWluZWQgZm9yIGEgMzItYnl0ZSBYMjU1MTkga2V5OlxuICpcbiAqIGBgYFxuICogU0VRVUVOQ0UgKDQ2IGJ5dGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAzMCAyZVxuICogICBJTlRFR0VSIDAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwMiAwMSAwMFxuICogICBTRVFVRU5DRSAoNSBieXRlcykgICAgICAgICAgICAgICAgICAgICAgICAzMCAwNVxuICogICAgIE9CSkVDVCBJREVOVElGSUVSIDEuMy4xMDEuMTEwIChYMjU1MTkpICAwNiAwMyAyYiA2NSA2ZVxuICogICBPQ1RFVCBTVFJJTkcgKDM0IGJ5dGVzKSAgICAgICAgICAgICAgICAgICAwNCAyMlxuICogICAgIE9DVEVUIFNUUklORyAoMzIgYnl0ZXMpICAgICAgICAgICAgICAgICAwNCAyMFxuICogICAgICAgPHNjYWxhcj5cbiAqIGBgYFxuICovXG5jb25zdCBQS0NTOF9YMjU1MTlfUFJFRklYID0gbmV3IFVpbnQ4QXJyYXkoW1xuICAweDMwLCAweDJlLCAweDAyLCAweDAxLCAweDAwLCAweDMwLCAweDA1LCAweDA2LCAweDAzLCAweDJiLCAweDY1LCAweDZlLCAweDA0LFxuICAweDIyLCAweDA0LCAweDIwLFxuXSk7XG5cbmNvbnN0IGluZm9FbmNvZGVyID0gbmV3IFRleHRFbmNvZGVyKCk7XG5cbi8qKlxuICogQSBwZXItcnVuIFgyNTUxOSBrZXlwYWlyLCBkZXJpdmVkIGZyb20gdGhlIHJ1bidzIGtleSBtYXRlcmlhbC5cbiAqXG4gKiBDYWxsZXJzIHNob3VsZCBkZXJpdmUgdGhpcyBvbmNlIHBlciBydW4gYW5kIG1lbW9pemUgaXQgYWxvbmdzaWRlIHRoZVxuICogc3ltbWV0cmljIGtleSDigJQgZGVyaXZhdGlvbiBjb3N0cyBzZXZlcmFsIFdlYiBDcnlwdG8gcm91bmQgdHJpcHMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUnVuS2V5UGFpciB7XG4gIC8qKiBSYXcgMzItYnl0ZSBYMjU1MTkgcHJpdmF0ZSBzY2FsYXIuIFNlY3JldC4gKi9cbiAgcmVhZG9ubHkgc2NhbGFyOiBVaW50OEFycmF5O1xuICAvKiogUmF3IDMyLWJ5dGUgWDI1NTE5IHB1YmxpYyBrZXkuIFNhZmUgdG8gcHVibGlzaC4gKi9cbiAgcmVhZG9ubHkgcHVibGljS2V5OiBVaW50OEFycmF5O1xufVxuXG5mdW5jdGlvbiBhc3NlcnRLZXlNYXRlcmlhbExlbmd0aChydW5LZXlNYXRlcmlhbDogVWludDhBcnJheSk6IHZvaWQge1xuICBpZiAocnVuS2V5TWF0ZXJpYWwuYnl0ZUxlbmd0aCAhPT0gQ09OVEVOVF9LRVlfTEVOR1RIKSB7XG4gICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgYFJ1biBrZXkgbWF0ZXJpYWwgbXVzdCBiZSBleGFjdGx5ICR7Q09OVEVOVF9LRVlfTEVOR1RIfSBieXRlcywgZ290ICR7cnVuS2V5TWF0ZXJpYWwuYnl0ZUxlbmd0aH1gXG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBhc3NlcnRQdWJsaWNLZXlMZW5ndGgocHVibGljS2V5OiBVaW50OEFycmF5LCBsYWJlbDogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChwdWJsaWNLZXkuYnl0ZUxlbmd0aCAhPT0gWDI1NTE5X0tFWV9MRU5HVEgpIHtcbiAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICBgJHtsYWJlbH0gbXVzdCBiZSBleGFjdGx5ICR7WDI1NTE5X0tFWV9MRU5HVEh9IGJ5dGVzLCBnb3QgJHtwdWJsaWNLZXkuYnl0ZUxlbmd0aH1gXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIERlcml2ZSB0aGUgcGVyLXJ1biBYMjU1MTkga2V5cGFpciBmcm9tIHRoZSBydW4ncyAzMi1ieXRlIGtleSBtYXRlcmlhbC5cbiAqXG4gKiBEZXRlcm1pbmlzdGljOiB0aGUgc2FtZSBrZXkgbWF0ZXJpYWwgYWx3YXlzIHlpZWxkcyB0aGUgc2FtZSBrZXlwYWlyLCB3aGljaFxuICogaXMgd2hhdCBsZXRzIHRoZSBvd25pbmcgZGVwbG95bWVudCByZS1kZXJpdmUgaXRzIHByaXZhdGUgc2NhbGFyIG9uIGRlbWFuZFxuICogKGZyb20gYFZFUkNFTF9ERVBMT1lNRU5UX0tFWWApIGluc3RlYWQgb2Ygc3RvcmluZyBpdCBhbnl3aGVyZS5cbiAqXG4gKiBAcGFyYW0gcnVuS2V5TWF0ZXJpYWwgLSBUaGUgMzIgYnl0ZXMgcmV0dXJuZWQgYnkgYFdvcmxkLmdldEVuY3J5cHRpb25LZXlGb3JSdW4oKWBcbiAqIEByZXR1cm5zIFRoZSBydW4ncyBYMjU1MTkgc2NhbGFyIGFuZCBwdWJsaWMga2V5XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZXJpdmVSdW5LZXlQYWlyKFxuICBydW5LZXlNYXRlcmlhbDogVWludDhBcnJheVxuKTogUHJvbWlzZTxSdW5LZXlQYWlyPiB7XG4gIGFzc2VydEtleU1hdGVyaWFsTGVuZ3RoKHJ1bktleU1hdGVyaWFsKTtcblxuICBjb25zdCBoa2RmS2V5ID0gYXdhaXQgZ2xvYmFsVGhpcy5jcnlwdG8uc3VidGxlLmltcG9ydEtleShcbiAgICAncmF3JyxcbiAgICBydW5LZXlNYXRlcmlhbCxcbiAgICAnSEtERicsXG4gICAgZmFsc2UsXG4gICAgWydkZXJpdmVCaXRzJ11cbiAgKTtcblxuICAvLyBaZXJvIHNhbHQgaXMgYWNjZXB0YWJsZSBwZXIgUkZDIDU4NjkgwqczLjE6IHRoZSBJS00gaGVyZSBpcyBpdHNlbGYgSEtERlxuICAvLyBvdXRwdXQgKG9yIGEgaGlnaC1lbnRyb3B5IEJZT0sgdmFsdWUpLCBzbyBpdCBpcyBhbHJlYWR5IHVuaWZvcm0uIFRoZVxuICAvLyBgaW5mb2AgbGFiZWwgcHJvdmlkZXMgZG9tYWluIHNlcGFyYXRpb24uXG4gIGNvbnN0IHNjYWxhckJpdHMgPSBhd2FpdCBnbG9iYWxUaGlzLmNyeXB0by5zdWJ0bGUuZGVyaXZlQml0cyhcbiAgICB7XG4gICAgICBuYW1lOiAnSEtERicsXG4gICAgICBoYXNoOiAnU0hBLTI1NicsXG4gICAgICBzYWx0OiBuZXcgVWludDhBcnJheSgzMiksXG4gICAgICBpbmZvOiBpbmZvRW5jb2Rlci5lbmNvZGUoU0NBTEFSX0lORk8pLFxuICAgIH0sXG4gICAgaGtkZktleSxcbiAgICBYMjU1MTlfS0VZX0xFTkdUSCAqIDhcbiAgKTtcbiAgY29uc3Qgc2NhbGFyID0gbmV3IFVpbnQ4QXJyYXkoc2NhbGFyQml0cyk7XG5cbiAgLy8gQW55IDMyLWJ5dGUgc3RyaW5nIGlzIGEgdmFsaWQgWDI1NTE5IHNjYWxhciAodGhlIGxvdy9oaWdoIGJpdHMgYXJlXG4gIC8vIGNsYW1wZWQgZHVyaW5nIHNjYWxhciBtdWx0aXBsaWNhdGlvbiksIHNvIHRoZSBIS0RGIG91dHB1dCBuZWVkcyBub1xuICAvLyByZWplY3Rpb24gc2FtcGxpbmcuXG4gIGNvbnN0IHB1YmxpY0tleSA9IGF3YWl0IGRlcml2ZVB1YmxpY0tleUZyb21TY2FsYXIoc2NhbGFyKTtcbiAgcmV0dXJuIHsgc2NhbGFyLCBwdWJsaWNLZXkgfTtcbn1cblxuLyoqXG4gKiBSZWNvdmVyIHRoZSByYXcgcHVibGljIGtleSBmb3IgYSBzY2FsYXIuXG4gKlxuICogV2ViIENyeXB0byBleHBvc2VzIG5vIHNjYWxhci1tdWx0aXBsaWNhdGlvbiBwcmltaXRpdmUsIHNvIHRoZSBzY2FsYXIgaXNcbiAqIGltcG9ydGVkIGFzIGEgUEtDUyM4IHByaXZhdGUga2V5IGFuZCBpdHMgcHVibGljIGhhbGYgcmVhZCBiYWNrIG91dCBvZiB0aGVcbiAqIEpXSyBleHBvcnQgKGB4YCksIHdoaWNoIHRoZSBTZWN1cmUgQ3VydmVzIHNwZWMgZGVmaW5lcyBhcyB0aGUgYmFzZTY0dXJsXG4gKiByYXcgcHVibGljIGtleS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGVyaXZlUHVibGljS2V5RnJvbVNjYWxhcihcbiAgc2NhbGFyOiBVaW50OEFycmF5XG4pOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgY29uc3QgcHJpdmF0ZUtleSA9IGF3YWl0IGltcG9ydFNjYWxhcihzY2FsYXIsIC8qIGV4dHJhY3RhYmxlICovIHRydWUpO1xuICBjb25zdCBqd2sgPSBhd2FpdCBnbG9iYWxUaGlzLmNyeXB0by5zdWJ0bGUuZXhwb3J0S2V5KCdqd2snLCBwcml2YXRlS2V5KTtcbiAgaWYgKCFqd2sueCkge1xuICAgIHRocm93IG5ldyBXb3JrZmxvd1J1bnRpbWVFcnJvcihcbiAgICAgICdYMjU1MTkgSldLIGV4cG9ydCBkaWQgbm90IGluY2x1ZGUgYSBwdWJsaWMga2V5IGNvbXBvbmVudCAoXCJ4XCIpJ1xuICAgICk7XG4gIH1cbiAgY29uc3QgcHVibGljS2V5ID0gYmFzZTY0VXJsVG9CeXRlcyhqd2sueCk7XG4gIC8vIEd1YXJkIHRoZSBvbmUgc3RlcCBpbiB0aGlzIG1vZHVsZSB0aGF0IHRydXN0cyBhbiBleHRlcm5hbCBlbmNvZGluZy4gQVxuICAvLyBzaG9ydCBvciBtYWxmb3JtZWQgdmFsdWUgaGVyZSB3b3VsZCBvdGhlcndpc2UgZmxvdyBvbndhcmQgYW5kIGZhaWwgbXVjaFxuICAvLyBsYXRlciwgaW5zaWRlIGtleSBhZ3JlZW1lbnQsIHdpdGggYSBmYXIgbGVzcyBvYnZpb3VzIG1lc3NhZ2UuXG4gIGlmIChwdWJsaWNLZXkuYnl0ZUxlbmd0aCAhPT0gWDI1NTE5X0tFWV9MRU5HVEgpIHtcbiAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICBgWDI1NTE5IEpXSyBleHBvcnQgcHJvZHVjZWQgYSAke3B1YmxpY0tleS5ieXRlTGVuZ3RofS1ieXRlIHB1YmxpYyBrZXksIGV4cGVjdGVkICR7WDI1NTE5X0tFWV9MRU5HVEh9YFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHB1YmxpY0tleTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaW1wb3J0U2NhbGFyKFxuICBzY2FsYXI6IFVpbnQ4QXJyYXksXG4gIGV4dHJhY3RhYmxlOiBib29sZWFuXG4pOiBQcm9taXNlPENyeXB0b0tleT4ge1xuICBjb25zdCBwa2NzOCA9IG5ldyBVaW50OEFycmF5KFBLQ1M4X1gyNTUxOV9QUkVGSVgubGVuZ3RoICsgc2NhbGFyLmJ5dGVMZW5ndGgpO1xuICBwa2NzOC5zZXQoUEtDUzhfWDI1NTE5X1BSRUZJWCwgMCk7XG4gIHBrY3M4LnNldChzY2FsYXIsIFBLQ1M4X1gyNTUxOV9QUkVGSVgubGVuZ3RoKTtcbiAgcmV0dXJuIGdsb2JhbFRoaXMuY3J5cHRvLnN1YnRsZS5pbXBvcnRLZXkoXG4gICAgJ3BrY3M4JyxcbiAgICBwa2NzOCxcbiAgICB7IG5hbWU6ICdYMjU1MTknIH0sXG4gICAgZXh0cmFjdGFibGUsXG4gICAgWydkZXJpdmVCaXRzJ11cbiAgKTtcbn1cblxuZnVuY3Rpb24gaW1wb3J0UHVibGljS2V5KHB1YmxpY0tleTogVWludDhBcnJheSk6IFByb21pc2U8Q3J5cHRvS2V5PiB7XG4gIHJldHVybiBnbG9iYWxUaGlzLmNyeXB0by5zdWJ0bGUuaW1wb3J0S2V5KFxuICAgICdyYXcnLFxuICAgIHB1YmxpY0tleSxcbiAgICB7IG5hbWU6ICdYMjU1MTknIH0sXG4gICAgLyogZXh0cmFjdGFibGUgKi8gdHJ1ZSxcbiAgICAvLyBQdWJsaWMga2V5cyBjYXJyeSBubyB1c2FnZXMgZm9yIFgyNTUxOSDigJQgdGhlIHByaXZhdGUga2V5IGRvZXMgdGhlXG4gICAgLy8gZGVyaXZpbmc7IHRoZSBwdWJsaWMga2V5IGlzIG9ubHkgZXZlciBhbiBhcmd1bWVudCB0byBpdC5cbiAgICBbXVxuICApO1xufVxuXG5jb25zdCBCQVNFNjRfQ0hBUlMgPVxuICAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyc7XG5cbmNvbnN0IEJBU0U2NFVSTF9DSEFSUyA9XG4gICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OS1fJztcblxuLyoqXG4gKiBFbmNvZGUgYnl0ZXMgYXMgc3RhbmRhcmQgKHBhZGRlZCkgYmFzZTY0LlxuICpcbiAqIEhhbmQtcm9sbGVkIGZvciB0aGUgc2FtZSByZWFzb24gYXMge0BsaW5rIGJhc2U2NFVybFRvQnl0ZXN9OiB0aGlzIG1vZHVsZVxuICogcnVucyBpbiB0aGUgYnJvd3NlciAobzExeSBkZWNyeXB0aW9uKSBhbmQgaW5zaWRlIHRoZSB3b3JrZmxvdyBWTSwgc28gbmVpdGhlclxuICogYEJ1ZmZlcmAgbm9yIGBidG9hYCBjYW4gYmUgYXNzdW1lZC4gVXNlZCBmb3IgdGhlIHdpcmUgZW5jb2Rpbmcgb2YgcnVuIHB1YmxpY1xuICoga2V5cywgbWF0Y2hpbmcgdGhlIGJhc2U2NCBjb252ZW50aW9uIGFscmVhZHkgdXNlZCBmb3IgYFZFUkNFTF9ERVBMT1lNRU5UX0tFWWBcbiAqIGFuZCB0aGUgYHJ1bi1rZXlgIEFQSSByZXNwb25zZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ5dGVzVG9CYXNlNjQoYnl0ZXM6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xuICBsZXQgb3V0ID0gJyc7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDMpIHtcbiAgICBjb25zdCBiMCA9IGJ5dGVzW2ldO1xuICAgIGNvbnN0IGIxID0gaSArIDEgPCBieXRlcy5sZW5ndGggPyBieXRlc1tpICsgMV0gOiAwO1xuICAgIGNvbnN0IGIyID0gaSArIDIgPCBieXRlcy5sZW5ndGggPyBieXRlc1tpICsgMl0gOiAwO1xuXG4gICAgb3V0ICs9IEJBU0U2NF9DSEFSU1soYjAgPj4gMikgJiAweDNmXTtcbiAgICBvdXQgKz0gQkFTRTY0X0NIQVJTWygoYjAgJiAweDAzKSA8PCA0KSB8ICgoYjEgPj4gNCkgJiAweDBmKV07XG4gICAgb3V0ICs9XG4gICAgICBpICsgMSA8IGJ5dGVzLmxlbmd0aFxuICAgICAgICA/IEJBU0U2NF9DSEFSU1soKGIxICYgMHgwZikgPDwgMikgfCAoKGIyID4+IDYpICYgMHgwMyldXG4gICAgICAgIDogJz0nO1xuICAgIG91dCArPSBpICsgMiA8IGJ5dGVzLmxlbmd0aCA/IEJBU0U2NF9DSEFSU1tiMiAmIDB4M2ZdIDogJz0nO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICogRGVjb2RlIHN0YW5kYXJkIGJhc2U2NCAocGFkZGluZyBvcHRpb25hbCkgdG8gYnl0ZXMuXG4gKlxuICogUmV0dXJucyBgdW5kZWZpbmVkYCBmb3IgbWFsZm9ybWVkIGlucHV0IHJhdGhlciB0aGFuIHRocm93aW5nOiBjYWxsZXJzIGRlY29kZVxuICogcHVibGljIGtleXMgdGhhdCBhcnJpdmUgZnJvbSBzdG9yYWdlIG9yIG92ZXIgdGhlIHdpcmUsIHdoZXJlIGEgY29ycnVwdCB2YWx1ZVxuICogc2hvdWxkIGRlZ3JhZGUgdG8gXCJ0aGlzIHJ1biBoYXMgbm8gdXNhYmxlIHB1YmxpYyBrZXlcIiAoYW5kIGZhbGwgYmFjayB0byB0aGVcbiAqIHN5bW1ldHJpYyBwYXRoKSByYXRoZXIgdGhhbiBjcmFzaCBhIHJlc3VtcHRpb24uXG4gKlxuICogVmFsaWRhdGlvbiBpcyBzdHJpY3QsIGJlY2F1c2UgYSBsZW5pZW50IGRlY29kZXIgaXMgd29yc2UgdGhhbiBhIHRocm93aW5nIG9uZVxuICogaGVyZSDigJQgc2lsZW50bHkgcmV0dXJuaW5nIGEgc2hvcnQgb3IgdHJ1bmNhdGVkIGtleSBtYWtlcyBhIGNvcnJ1cHQgdmFsdWUgbG9va1xuICogKnByZXNlbnQqLCBzbyB0aGUgY2FsbGVyIHNlYWxzIHRvIGdhcmJhZ2UgaW5zdGVhZCBvZiB0YWtpbmcgdGhlIGZhbGxiYWNrLlxuICogUmVqZWN0ZWQ6IGNoYXJhY3RlcnMgb3V0c2lkZSB0aGUgYWxwaGFiZXQsIGEgbGVuZ3RoIHRoYXQgY2Fubm90IGRlc2NyaWJlIGFcbiAqIHdob2xlIG51bWJlciBvZiBieXRlcyAoYGxlbmd0aCAlIDQgPT09IDFgKSwgcGFkZGluZyBhbnl3aGVyZSBidXQgdGhlIGVuZCwgYW5kXG4gKiBhIGZpbmFsIHF1YW50dW0gd2hvc2UgdW51c2VkIGxvdyBiaXRzIGFyZSBub3QgemVyby5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXModmFsdWU6IHN0cmluZyk6IFVpbnQ4QXJyYXkgfCB1bmRlZmluZWQge1xuICAvLyBTdHJpcCB0cmFpbGluZyBwYWRkaW5nLCB0aGVuIHJlcXVpcmUgd2hhdCByZW1haW5zIHRvIGJlIHBhZGRpbmctZnJlZS5cbiAgbGV0IGVuZCA9IHZhbHVlLmxlbmd0aDtcbiAgd2hpbGUgKGVuZCA+IDAgJiYgdmFsdWVbZW5kIC0gMV0gPT09ICc9JykgZW5kLS07XG4gIGNvbnN0IGJvZHkgPSB2YWx1ZS5zbGljZSgwLCBlbmQpO1xuICBpZiAoYm9keS5pbmNsdWRlcygnPScpKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIC8vIDQgY2hhcnMgLT4gMyBieXRlczsgMyAtPiAyOyAyIC0+IDEuIEEgcmVtYWluZGVyIG9mIDEgZW5jb2RlcyBubyBieXRlLlxuICBpZiAoYm9keS5sZW5ndGggJSA0ID09PSAxKSByZXR1cm4gdW5kZWZpbmVkO1xuICAvLyBQYWRkaW5nLCB3aGVuIHByZXNlbnQsIG11c3QgYnJpbmcgdGhlIHRvdGFsIHRvIGEgbXVsdGlwbGUgb2YgNC5cbiAgaWYgKGVuZCAhPT0gdmFsdWUubGVuZ3RoICYmIHZhbHVlLmxlbmd0aCAlIDQgIT09IDApIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgbGV0IGFjY3VtdWxhdG9yID0gMDtcbiAgbGV0IGJpdENvdW50ID0gMDtcbiAgY29uc3QgYnl0ZXM6IG51bWJlcltdID0gW107XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBib2R5Lmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaW5kZXggPSBCQVNFNjRfQ0hBUlMuaW5kZXhPZihib2R5W2ldKTtcbiAgICBpZiAoaW5kZXggPT09IC0xKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGFjY3VtdWxhdG9yID0gKGFjY3VtdWxhdG9yIDw8IDYpIHwgaW5kZXg7XG4gICAgYml0Q291bnQgKz0gNjtcbiAgICBpZiAoYml0Q291bnQgPj0gOCkge1xuICAgICAgYml0Q291bnQgLT0gODtcbiAgICAgIGJ5dGVzLnB1c2goKGFjY3VtdWxhdG9yID4+IGJpdENvdW50KSAmIDB4ZmYpO1xuICAgIH1cbiAgfVxuXG4gIC8vIExlZnRvdmVyIGJpdHMgYmVsb25nIHRvIG5vIGJ5dGUgYW5kIG11c3QgYmUgemVybyBpbiBjYW5vbmljYWwgYmFzZTY0LlxuICBpZiAoYml0Q291bnQgPiAwICYmIChhY2N1bXVsYXRvciAmICgoMSA8PCBiaXRDb3VudCkgLSAxKSkgIT09IDApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGJ5dGVzKTtcbn1cblxuLyoqXG4gKiBEZWNvZGUgYSBiYXNlNjR1cmwgc3RyaW5nIChKV0sgZW5jb2RpbmcpIHRvIGJ5dGVzLlxuICpcbiAqIEhhbmQtcm9sbGVkIHJhdGhlciB0aGFuIHVzaW5nIGBhdG9iYCBvciBgQnVmZmVyYDogdGhpcyBtb2R1bGUgYWxzbyBydW5zXG4gKiBpbnNpZGUgdGhlIHdvcmtmbG93IFZNLCB3aG9zZSBnbG9iYWwgc3VyZmFjZSBpcyBkZWxpYmVyYXRlbHkgbWluaW1hbCBhbmRcbiAqIGRvZXMgbm90IGluY2x1ZGUgZWl0aGVyLiBUaGUgaW5wdXRzIGhlcmUgYXJlIGZpeGVkLXNpemUgSldLIGtleSBjb21wb25lbnRzLFxuICogc28gYSBjb21wYWN0IGRlY29kZXIgaXMgc3VmZmljaWVudCDigJQgaXQgYWNjZXB0cyB1bnBhZGRlZCBiYXNlNjR1cmwgb25seSxcbiAqIHdoaWNoIGlzIHdoYXQgUkZDIDc1MTUgwqcyIG1hbmRhdGVzIGZvciBKV0sgbWVtYmVycy5cbiAqL1xuZnVuY3Rpb24gYmFzZTY0VXJsVG9CeXRlcyh2YWx1ZTogc3RyaW5nKTogVWludDhBcnJheSB7XG4gIGxldCBhY2N1bXVsYXRvciA9IDA7XG4gIGxldCBiaXRDb3VudCA9IDA7XG4gIGNvbnN0IGJ5dGVzOiBudW1iZXJbXSA9IFtdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWUubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBjaGFyID0gdmFsdWVbaV07XG4gICAgaWYgKGNoYXIgPT09ICc9JykgYnJlYWs7XG4gICAgY29uc3QgaW5kZXggPSBCQVNFNjRVUkxfQ0hBUlMuaW5kZXhPZihjaGFyKTtcbiAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIGJhc2U2NHVybCBjaGFyYWN0ZXIgXCIke2NoYXJ9XCIgaW4gWDI1NTE5IEpXSyBrZXkgY29tcG9uZW50YFxuICAgICAgKTtcbiAgICB9XG4gICAgYWNjdW11bGF0b3IgPSAoYWNjdW11bGF0b3IgPDwgNikgfCBpbmRleDtcbiAgICBiaXRDb3VudCArPSA2O1xuICAgIGlmIChiaXRDb3VudCA+PSA4KSB7XG4gICAgICBiaXRDb3VudCAtPSA4O1xuICAgICAgYnl0ZXMucHVzaCgoYWNjdW11bGF0b3IgPj4gYml0Q291bnQpICYgMHhmZik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGJ5dGVzKTtcbn1cblxuLyoqXG4gKiBEZXJpdmUgdGhlIEFFUy0yNTYtR0NNIGNvbnRlbnQga2V5IGZyb20gYW4gWDI1NTE5IHNoYXJlZCBzZWNyZXQsIGJpbmRpbmdcbiAqIGl0IHRvIGJvdGggcHVibGljIGtleXMgKEhQS0UncyBga2VtX2NvbnRleHRgKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGVyaXZlQ29udGVudEtleShcbiAgc2hhcmVkU2VjcmV0OiBVaW50OEFycmF5LFxuICBlcGhlbWVyYWxQdWJsaWNLZXk6IFVpbnQ4QXJyYXksXG4gIHJlY2lwaWVudFB1YmxpY0tleTogVWludDhBcnJheSxcbiAgdXNhZ2VzOiBSZWFkb25seUFycmF5PCdlbmNyeXB0JyB8ICdkZWNyeXB0Jz5cbik6IFByb21pc2U8Q3J5cHRvS2V5PiB7XG4gIGNvbnN0IGxhYmVsID0gaW5mb0VuY29kZXIuZW5jb2RlKENPTlRFTlRfS0VZX0lORk8pO1xuICBjb25zdCBpbmZvID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgbGFiZWwubGVuZ3RoICsgZXBoZW1lcmFsUHVibGljS2V5Lmxlbmd0aCArIHJlY2lwaWVudFB1YmxpY0tleS5sZW5ndGhcbiAgKTtcbiAgaW5mby5zZXQobGFiZWwsIDApO1xuICBpbmZvLnNldChlcGhlbWVyYWxQdWJsaWNLZXksIGxhYmVsLmxlbmd0aCk7XG4gIGluZm8uc2V0KHJlY2lwaWVudFB1YmxpY0tleSwgbGFiZWwubGVuZ3RoICsgZXBoZW1lcmFsUHVibGljS2V5Lmxlbmd0aCk7XG5cbiAgY29uc3QgaGtkZktleSA9IGF3YWl0IGdsb2JhbFRoaXMuY3J5cHRvLnN1YnRsZS5pbXBvcnRLZXkoXG4gICAgJ3JhdycsXG4gICAgc2hhcmVkU2VjcmV0LFxuICAgICdIS0RGJyxcbiAgICBmYWxzZSxcbiAgICBbJ2Rlcml2ZUJpdHMnXVxuICApO1xuICBjb25zdCBjb250ZW50S2V5Qml0cyA9IGF3YWl0IGdsb2JhbFRoaXMuY3J5cHRvLnN1YnRsZS5kZXJpdmVCaXRzKFxuICAgIHsgbmFtZTogJ0hLREYnLCBoYXNoOiAnU0hBLTI1NicsIHNhbHQ6IG5ldyBVaW50OEFycmF5KDMyKSwgaW5mbyB9LFxuICAgIGhrZGZLZXksXG4gICAgQ09OVEVOVF9LRVlfTEVOR1RIICogOFxuICApO1xuXG4gIHJldHVybiBnbG9iYWxUaGlzLmNyeXB0by5zdWJ0bGUuaW1wb3J0S2V5KFxuICAgICdyYXcnLFxuICAgIG5ldyBVaW50OEFycmF5KGNvbnRlbnRLZXlCaXRzKSxcbiAgICAnQUVTLUdDTScsXG4gICAgZmFsc2UsXG4gICAgLy8gYEtleVVzYWdlYCBpcyBhIERPTS1saWIgdHlwZSB0aGF0IGlzIG5vdCBpbiBzY29wZSB1bmRlciBgZXMyMDIyYDsgdGhlXG4gICAgLy8gcGFyYW1ldGVyIHR5cGUgaXMgYSBzdHJpY3Qgc3Vic2V0IG9mIGl0LCBzbyB0aGlzIGNhc3QgaXMgc291bmQuXG4gICAgdXNhZ2VzIGFzICgnZW5jcnlwdCcgfCAnZGVjcnlwdCcpW11cbiAgKTtcbn1cblxuLyoqXG4gKiBUaGUgd3JpdGVyIGhhbGYgb2YgdGhlIEtFTTogZ2VuZXJhdGUgYW4gZXBoZW1lcmFsIGtleXBhaXIgYW5kIGRlcml2ZSBhXG4gKiBjb250ZW50IGtleSBmb3IgYSByZWNpcGllbnQncyBwdWJsaWMga2V5LlxuICpcbiAqIFVzZSB0aGlzIHdoZW4gbWFueSBwYXlsb2FkcyBzaGFyZSBvbmUgS0VNIG9wZXJhdGlvbiDigJQgaS5lLiBzdHJlYW0gZnJhbWVzLlxuICogVGhlIHJldHVybmVkIGBjb250ZW50S2V5YCBjYW4gb25seSBlbmNyeXB0LCBzbyBhIHN0cmVhbSB3cml0ZXIgcHJvdmFibHlcbiAqIGNhbm5vdCByZWFkIHRoZSByZWNpcGllbnQgcnVuJ3MgZGF0YSBldmVuIGJ5IG1pc3Rha2UuXG4gKlxuICogKipDYWxsZXJzIG93biBub25jZSBkaXNjaXBsaW5lLioqIEVuY3J5cHQgZWFjaCBmcmFtZSB3aXRoIGEgZnJlc2ggcmFuZG9tXG4gKiBub25jZSwgYW5kIGNhbGwgdGhpcyBmdW5jdGlvbiBhZ2FpbiBmb3IgZXZlcnkgbmV3IGNvbm5lY3Rpb24gYXR0ZW1wdCBvclxuICogcmVwbGF5IHNvIHRoYXQgYSByZXN0YXJ0ZWQgd3JpdGVyIG5ldmVyIHJldXNlcyBhIGNvbnRlbnQga2V5LiBGb3Igb25lLXNob3RcbiAqIHBheWxvYWRzIHByZWZlciB7QGxpbmsgc2VhbH0sIHdoaWNoIGhhbmRsZXMgdGhpcyBhdXRvbWF0aWNhbGx5LlxuICpcbiAqIEBwYXJhbSByZWNpcGllbnRQdWJsaWNLZXkgLSBUaGUgcmVjaXBpZW50IHJ1bidzIHJhdyAzMi1ieXRlIFgyNTUxOSBwdWJsaWMga2V5XG4gKiBAcmV0dXJucyBUaGUgZXBoZW1lcmFsIHB1YmxpYyBrZXkgdG8gcHVibGlzaCBhbG9uZ3NpZGUgdGhlIGNpcGhlcnRleHQsIGFuZFxuICogICB0aGUgZW5jcnlwdC1vbmx5IGNvbnRlbnQga2V5XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbmNhcHN1bGF0ZShyZWNpcGllbnRQdWJsaWNLZXk6IFVpbnQ4QXJyYXkpOiBQcm9taXNlPHtcbiAgZXBoZW1lcmFsUHVibGljS2V5OiBVaW50OEFycmF5O1xuICBjb250ZW50S2V5OiBDcnlwdG9LZXk7XG59PiB7XG4gIGFzc2VydFB1YmxpY0tleUxlbmd0aChyZWNpcGllbnRQdWJsaWNLZXksICdSZWNpcGllbnQgcHVibGljIGtleScpO1xuXG4gIGxldCByZWNpcGllbnRLZXk6IENyeXB0b0tleTtcbiAgdHJ5IHtcbiAgICByZWNpcGllbnRLZXkgPSBhd2FpdCBpbXBvcnRQdWJsaWNLZXkocmVjaXBpZW50UHVibGljS2V5KTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICB0aHJvdyBuZXcgV29ya2Zsb3dSdW50aW1lRXJyb3IoXG4gICAgICBgSW52YWxpZCBYMjU1MTkgcmVjaXBpZW50IHB1YmxpYyBrZXk6ICR7Y2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm1lc3NhZ2UgOiBTdHJpbmcoY2F1c2UpfWAsXG4gICAgICB7IGNhdXNlIH1cbiAgICApO1xuICB9XG5cbiAgY29uc3QgZXBoZW1lcmFsID0gKGF3YWl0IGdsb2JhbFRoaXMuY3J5cHRvLnN1YnRsZS5nZW5lcmF0ZUtleShcbiAgICB7IG5hbWU6ICdYMjU1MTknIH0sXG4gICAgLyogZXh0cmFjdGFibGUgKi8gdHJ1ZSxcbiAgICBbJ2Rlcml2ZUJpdHMnXVxuICApKSBhcyB7IHByaXZhdGVLZXk6IENyeXB0b0tleTsgcHVibGljS2V5OiBDcnlwdG9LZXkgfTtcblxuICBjb25zdCBlcGhlbWVyYWxQdWJsaWNLZXkgPSBuZXcgVWludDhBcnJheShcbiAgICBhd2FpdCBnbG9iYWxUaGlzLmNyeXB0by5zdWJ0bGUuZXhwb3J0S2V5KCdyYXcnLCBlcGhlbWVyYWwucHVibGljS2V5KVxuICApO1xuXG4gIGxldCBzaGFyZWRTZWNyZXRCaXRzOiBBcnJheUJ1ZmZlcjtcbiAgdHJ5IHtcbiAgICBzaGFyZWRTZWNyZXRCaXRzID0gYXdhaXQgZ2xvYmFsVGhpcy5jcnlwdG8uc3VidGxlLmRlcml2ZUJpdHMoXG4gICAgICB7IG5hbWU6ICdYMjU1MTknLCBwdWJsaWM6IHJlY2lwaWVudEtleSB9LFxuICAgICAgZXBoZW1lcmFsLnByaXZhdGVLZXksXG4gICAgICBYMjU1MTlfS0VZX0xFTkdUSCAqIDhcbiAgICApO1xuICB9IGNhdGNoIChjYXVzZSkge1xuICAgIC8vIFdlYiBDcnlwdG8gdGhyb3dzIE9wZXJhdGlvbkVycm9yIHdoZW4gdGhlIHNoYXJlZCBzZWNyZXQgaXMgYWxsLXplcm8sXG4gICAgLy8gd2hpY2ggaGFwcGVucyBleGFjdGx5IHdoZW4gdGhlIHJlY2lwaWVudCBwdWJsaWMga2V5IGlzIGEgbG93LW9yZGVyXG4gICAgLy8gcG9pbnQuIFRoaXMgaXMgdGhlIHBsYXRmb3JtIGdpdmluZyB1cyBIUEtFJ3MgY29udHJpYnV0b3J5LWJlaGF2aW9yXG4gICAgLy8gY2hlY2sgZm9yIGZyZWUuXG4gICAgdGhyb3cgbmV3IFdvcmtmbG93UnVudGltZUVycm9yKFxuICAgICAgJ1gyNTUxOSBrZXkgYWdyZWVtZW50IGZhaWxlZDogdGhlIHJlY2lwaWVudCBwdWJsaWMga2V5IGlzIG5vdCBhIHZhbGlkICcgK1xuICAgICAgICAnY3VydmUgcG9pbnQgKGxvdy1vcmRlciBwb2ludCBvciBjb3JydXB0ZWQga2V5IG1hdGVyaWFsKScsXG4gICAgICB7IGNhdXNlIH1cbiAgICApO1xuICB9XG5cbiAgY29uc3QgY29udGVudEtleSA9IGF3YWl0IGRlcml2ZUNvbnRlbnRLZXkoXG4gICAgbmV3IFVpbnQ4QXJyYXkoc2hhcmVkU2VjcmV0Qml0cyksXG4gICAgZXBoZW1lcmFsUHVibGljS2V5LFxuICAgIHJlY2lwaWVudFB1YmxpY0tleSxcbiAgICBbJ2VuY3J5cHQnXVxuICApO1xuXG4gIHJldHVybiB7IGVwaGVtZXJhbFB1YmxpY0tleSwgY29udGVudEtleSB9O1xufVxuXG4vKipcbiAqIFRoZSByZWNpcGllbnQgaGFsZiBvZiB0aGUgS0VNOiByZWNvdmVyIHRoZSBjb250ZW50IGtleSBmb3IgYSBzZWFsZWRcbiAqIHBheWxvYWQgZnJvbSB0aGUgcnVuJ3Mgb3duIGtleXBhaXIgYW5kIHRoZSBzZW5kZXIncyBlcGhlbWVyYWwgcHVibGljIGtleS5cbiAqXG4gKiBAcGFyYW0ga2V5UGFpciAtIFRoZSByZWNpcGllbnQgcnVuJ3Mga2V5cGFpciwgZnJvbSB7QGxpbmsgZGVyaXZlUnVuS2V5UGFpcn1cbiAqIEBwYXJhbSBlcGhlbWVyYWxQdWJsaWNLZXkgLSBUaGUgc2VuZGVyJ3MgcmF3IDMyLWJ5dGUgWDI1NTE5IHB1YmxpYyBrZXksXG4gKiAgIHJlYWQgZnJvbSB0aGUgaGVhZCBvZiB0aGUgc2VhbGVkIGVudmVsb3BlXG4gKiBAcmV0dXJucyBBIGRlY3J5cHQtb25seSBjb250ZW50IGtleVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVjYXBzdWxhdGUoXG4gIGtleVBhaXI6IFJ1bktleVBhaXIsXG4gIGVwaGVtZXJhbFB1YmxpY0tleTogVWludDhBcnJheVxuKTogUHJvbWlzZTxDcnlwdG9LZXk+IHtcbiAgaWYgKGVwaGVtZXJhbFB1YmxpY0tleS5ieXRlTGVuZ3RoICE9PSBYMjU1MTlfS0VZX0xFTkdUSCkge1xuICAgIHRocm93IG5ldyBSdW50aW1lRGVjcnlwdGlvbkVycm9yKFxuICAgICAgYFNlYWxlZCBwYXlsb2FkIGhhcyBhIG1hbGZvcm1lZCBlcGhlbWVyYWwgcHVibGljIGtleTogZXhwZWN0ZWQgJHtYMjU1MTlfS0VZX0xFTkdUSH0gYnl0ZXMsIGdvdCAke2VwaGVtZXJhbFB1YmxpY0tleS5ieXRlTGVuZ3RofWAsXG4gICAgICB7XG4gICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICBvcGVyYXRpb246ICdkZWNyeXB0JyxcbiAgICAgICAgICBieXRlTGVuZ3RoOiBlcGhlbWVyYWxQdWJsaWNLZXkuYnl0ZUxlbmd0aCxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgbGV0IHNoYXJlZFNlY3JldEJpdHM6IEFycmF5QnVmZmVyO1xuICB0cnkge1xuICAgIGNvbnN0IFtwcml2YXRlS2V5LCBzZW5kZXJLZXldID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgaW1wb3J0U2NhbGFyKGtleVBhaXIuc2NhbGFyLCAvKiBleHRyYWN0YWJsZSAqLyBmYWxzZSksXG4gICAgICBpbXBvcnRQdWJsaWNLZXkoZXBoZW1lcmFsUHVibGljS2V5KSxcbiAgICBdKTtcbiAgICBzaGFyZWRTZWNyZXRCaXRzID0gYXdhaXQgZ2xvYmFsVGhpcy5jcnlwdG8uc3VidGxlLmRlcml2ZUJpdHMoXG4gICAgICB7IG5hbWU6ICdYMjU1MTknLCBwdWJsaWM6IHNlbmRlcktleSB9LFxuICAgICAgcHJpdmF0ZUtleSxcbiAgICAgIFgyNTUxOV9LRVlfTEVOR1RIICogOFxuICAgICk7XG4gIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgdGhyb3cgbmV3IFJ1bnRpbWVEZWNyeXB0aW9uRXJyb3IoXG4gICAgICBgWDI1NTE5IGtleSBhZ3JlZW1lbnQgZmFpbGVkIHdoaWxlIG9wZW5pbmcgYSBzZWFsZWQgcGF5bG9hZDogJHtjYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gY2F1c2UubWVzc2FnZSA6IFN0cmluZyhjYXVzZSl9YCxcbiAgICAgIHtcbiAgICAgICAgY2F1c2UsXG4gICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICBvcGVyYXRpb246ICdkZWNyeXB0JyxcbiAgICAgICAgICBieXRlTGVuZ3RoOiBlcGhlbWVyYWxQdWJsaWNLZXkuYnl0ZUxlbmd0aCxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIGRlcml2ZUNvbnRlbnRLZXkoXG4gICAgbmV3IFVpbnQ4QXJyYXkoc2hhcmVkU2VjcmV0Qml0cyksXG4gICAgZXBoZW1lcmFsUHVibGljS2V5LFxuICAgIGtleVBhaXIucHVibGljS2V5LFxuICAgIFsnZGVjcnlwdCddXG4gICk7XG59XG5cbi8qKlxuICogU2VhbCBhIHBheWxvYWQgdG8gYSBydW4ncyBwdWJsaWMga2V5LlxuICpcbiAqIEVhY2ggY2FsbCBwZXJmb3JtcyBpdHMgb3duIEtFTSBvcGVyYXRpb24sIHNvIGV2ZXJ5IHNlYWxlZCBwYXlsb2FkIGdldHMgYW5cbiAqIGluZGVwZW5kZW50IGNvbnRlbnQga2V5IOKAlCBub25jZSByZXVzZSBhY3Jvc3MgY2FsbHMgaXMgaW1wb3NzaWJsZSBieVxuICogY29uc3RydWN0aW9uLlxuICpcbiAqIEBwYXJhbSByZWNpcGllbnRQdWJsaWNLZXkgLSBUaGUgcmVjaXBpZW50IHJ1bidzIHJhdyAzMi1ieXRlIFgyNTUxOSBwdWJsaWMga2V5XG4gKiBAcGFyYW0gZGF0YSAtIFBsYWludGV4dCB0byBzZWFsXG4gKiBAcGFyYW0gYWFkIC0gT3B0aW9uYWwgYWRkaXRpb25hbCBhdXRoZW50aWNhdGVkIGRhdGEsIGNvdmVyZWQgYnkgdGhlIEdDTSB0YWdcbiAqICAgYnV0IG5vdCBlbmNyeXB0ZWQuIENhbGxlcnMgcGFzcyB0aGUgcmVjaXBpZW50J3MgYHByb2plY3RJZHxydW5JZGAgc28gYVxuICogICBzZWFsZWQgcGF5bG9hZCBjYW5ub3QgYmUgcmVwbGF5ZWQgYWdhaW5zdCBhIGRpZmZlcmVudCBydW4uXG4gKiBAcmV0dXJucyBgW2VwaGVtZXJhbCBwdWJsaWMga2V5ICgzMildW25vbmNlICgxMildW2NpcGhlcnRleHQgKyB0YWddYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VhbChcbiAgcmVjaXBpZW50UHVibGljS2V5OiBVaW50OEFycmF5LFxuICBkYXRhOiBVaW50OEFycmF5LFxuICBhYWQ/OiBVaW50OEFycmF5XG4pOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgY29uc3QgeyBlcGhlbWVyYWxQdWJsaWNLZXksIGNvbnRlbnRLZXkgfSA9XG4gICAgYXdhaXQgZW5jYXBzdWxhdGUocmVjaXBpZW50UHVibGljS2V5KTtcbiAgY29uc3QgZW5jcnlwdGVkID0gYXdhaXQgYWVzR2NtRW5jcnlwdChjb250ZW50S2V5LCBkYXRhLCBhYWQpO1xuXG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KFxuICAgIGVwaGVtZXJhbFB1YmxpY0tleS5ieXRlTGVuZ3RoICsgZW5jcnlwdGVkLmJ5dGVMZW5ndGhcbiAgKTtcbiAgcmVzdWx0LnNldChlcGhlbWVyYWxQdWJsaWNLZXksIDApO1xuICByZXN1bHQuc2V0KGVuY3J5cHRlZCwgZXBoZW1lcmFsUHVibGljS2V5LmJ5dGVMZW5ndGgpO1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIE9wZW4gYSBwYXlsb2FkIHNlYWxlZCB0byB0aGlzIHJ1bidzIHB1YmxpYyBrZXkuXG4gKlxuICogQHBhcmFtIGtleVBhaXIgLSBUaGUgcmVjaXBpZW50IHJ1bidzIGtleXBhaXIsIGZyb20ge0BsaW5rIGRlcml2ZVJ1bktleVBhaXJ9XG4gKiBAcGFyYW0gc2VhbGVkIC0gYFtlcGhlbWVyYWwgcHVibGljIGtleSAoMzIpXVtub25jZSAoMTIpXVtjaXBoZXJ0ZXh0ICsgdGFnXWBcbiAqIEBwYXJhbSBhYWQgLSBUaGUgZXhhY3QgYWRkaXRpb25hbCBhdXRoZW50aWNhdGVkIGRhdGEgcGFzc2VkIHRvIHtAbGluayBzZWFsfVxuICogQHJldHVybnMgVGhlIGRlY3J5cHRlZCBwbGFpbnRleHRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG9wZW4oXG4gIGtleVBhaXI6IFJ1bktleVBhaXIsXG4gIHNlYWxlZDogVWludDhBcnJheSxcbiAgYWFkPzogVWludDhBcnJheVxuKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIC8vIEVwaGVtZXJhbCBwdWJsaWMga2V5ICsgQUVTLUdDTSBub25jZSArIEFFUy1HQ00gdGFnLlxuICBjb25zdCBtaW5MZW5ndGggPSBYMjU1MTlfS0VZX0xFTkdUSCArIE5PTkNFX0xFTkdUSCArIFRBR19CWVRFUztcbiAgaWYgKHNlYWxlZC5ieXRlTGVuZ3RoIDwgbWluTGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJ1bnRpbWVEZWNyeXB0aW9uRXJyb3IoXG4gICAgICBgU2VhbGVkIHBheWxvYWQgdG9vIHNob3J0OiBleHBlY3RlZCBhdCBsZWFzdCAke21pbkxlbmd0aH0gYnl0ZXMsIGdvdCAke3NlYWxlZC5ieXRlTGVuZ3RofWAsXG4gICAgICB7IGNvbnRleHQ6IHsgb3BlcmF0aW9uOiAnZGVjcnlwdCcsIGJ5dGVMZW5ndGg6IHNlYWxlZC5ieXRlTGVuZ3RoIH0gfVxuICAgICk7XG4gIH1cblxuICBjb25zdCBlcGhlbWVyYWxQdWJsaWNLZXkgPSBzZWFsZWQuc3ViYXJyYXkoMCwgWDI1NTE5X0tFWV9MRU5HVEgpO1xuICBjb25zdCBlbmNyeXB0ZWQgPSBzZWFsZWQuc3ViYXJyYXkoWDI1NTE5X0tFWV9MRU5HVEgpO1xuICBjb25zdCBjb250ZW50S2V5ID0gYXdhaXQgZGVjYXBzdWxhdGUoa2V5UGFpciwgZXBoZW1lcmFsUHVibGljS2V5KTtcbiAgcmV0dXJuIGFlc0djbURlY3J5cHQoY29udGVudEtleSwgZW5jcnlwdGVkLCBhYWQpO1xufVxuXG4vKipcbiAqIEEgd3JpdGVyLXNpZGUgc2Vzc2lvbiB0aGF0IGFtb3J0aXplcyBvbmUgS0VNIG9wZXJhdGlvbiBhY3Jvc3MgbWFueSBzZWFsZWRcbiAqIHBheWxvYWRzIOKAlCB1c2UgaXQgZm9yIHN0cmVhbXMsIHdoZXJlIG9uZS1zaG90IHtAbGluayBzZWFsfSB3b3VsZCBwZXJmb3JtIGFcbiAqIGZyZXNoIGtleWdlbiArIEVDREggKyBIS0RGIGZvciBldmVyeSBmcmFtZS5cbiAqXG4gKiBTYWZldHkgcmVzdHMgb24gdHdvIHByb3BlcnRpZXM6XG4gKlxuICogLSBFdmVyeSBwYXlsb2FkIHN0aWxsIGdldHMgYSAqKmZyZXNoIHJhbmRvbSBub25jZSoqIGZyb20gYGFlc0djbUVuY3J5cHRgLCBzb1xuICogICBzaGFyaW5nIHRoZSBjb250ZW50IGtleSBkb2VzIG5vdCByaXNrIGAoa2V5LCBub25jZSlgIHJldXNlLiAoQSBjb3VudGVyXG4gKiAgIHdvdWxkOiBpdCByZXN0YXJ0cyBhdCB6ZXJvIHdoZW5ldmVyIGEgd3JpdGVyIHJlc3RhcnRzLilcbiAqIC0gVGhlIHNlc3Npb24gaXMgYm91bmQgdG8gb25lIHdyaXRlciBpbnN0YW5jZS4gQSByZWNvbm5lY3Qgb3IgYSBkdXJhYmxlXG4gKiAgIHJlcGxheSBjb25zdHJ1Y3RzIGEgbmV3IHNlc3Npb24sIHNvIGEgcmVzdGFydGVkIHdyaXRlciBuZXZlciBpbmhlcml0cyBhXG4gKiAgIHByZXZpb3VzIGluY2FybmF0aW9uJ3MgY29udGVudCBrZXkuXG4gKlxuICogVGhlIGVudmVsb3BlIGxheW91dCBpcyBieXRlLWlkZW50aWNhbCB0byB7QGxpbmsgc2VhbH0sIHNvIGEgcmVhZGVyIGNhbm5vdFxuICogdGVsbCB3aGljaCB3YXMgdXNlZCBhbmQgbmVlZHMgbm8gbWF0Y2hpbmcgc2Vzc2lvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNlYWxTZXNzaW9uKFxuICByZWNpcGllbnRQdWJsaWNLZXk6IFVpbnQ4QXJyYXksXG4gIGFhZD86IFVpbnQ4QXJyYXlcbik6IHsgc2VhbChkYXRhOiBVaW50OEFycmF5KTogUHJvbWlzZTxVaW50OEFycmF5PiB9IHtcbiAgbGV0IGVuY2Fwc3VsYXRpb246XG4gICAgfCBQcm9taXNlPHsgZXBoZW1lcmFsUHVibGljS2V5OiBVaW50OEFycmF5OyBjb250ZW50S2V5OiBDcnlwdG9LZXkgfT5cbiAgICB8IHVuZGVmaW5lZDtcblxuICByZXR1cm4ge1xuICAgIGFzeW5jIHNlYWwoZGF0YTogVWludDhBcnJheSk6IFByb21pc2U8VWludDhBcnJheT4ge1xuICAgICAgLy8gTGF6aWx5LCBzbyBjb25zdHJ1Y3RpbmcgYSBzZXNzaW9uIGZvciBhIHN0cmVhbSB0aGF0IGlzIG5ldmVyIHdyaXR0ZW5cbiAgICAgIC8vIHRvIGNvc3RzIG5vdGhpbmcuXG4gICAgICBlbmNhcHN1bGF0aW9uID8/PSBlbmNhcHN1bGF0ZShyZWNpcGllbnRQdWJsaWNLZXkpO1xuICAgICAgY29uc3QgeyBlcGhlbWVyYWxQdWJsaWNLZXksIGNvbnRlbnRLZXkgfSA9IGF3YWl0IGVuY2Fwc3VsYXRpb247XG4gICAgICBjb25zdCBlbmNyeXB0ZWQgPSBhd2FpdCBhZXNHY21FbmNyeXB0KGNvbnRlbnRLZXksIGRhdGEsIGFhZCk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KFxuICAgICAgICBlcGhlbWVyYWxQdWJsaWNLZXkuYnl0ZUxlbmd0aCArIGVuY3J5cHRlZC5ieXRlTGVuZ3RoXG4gICAgICApO1xuICAgICAgcmVzdWx0LnNldChlcGhlbWVyYWxQdWJsaWNLZXksIDApO1xuICAgICAgcmVzdWx0LnNldChlbmNyeXB0ZWQsIGVwaGVtZXJhbFB1YmxpY0tleS5ieXRlTGVuZ3RoKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBBIHJlYWRlci1zaWRlIHNlc3Npb24gdGhhdCBjYWNoZXMgZGVjYXBzdWxhdGlvbiBwZXIgc2VuZGVyLlxuICpcbiAqIFRoZSBtaXJyb3Igb2Yge0BsaW5rIGNyZWF0ZVNlYWxTZXNzaW9ufTogYmVjYXVzZSBldmVyeSBmcmFtZSBmcm9tIG9uZSB3cml0ZXJcbiAqIGNhcnJpZXMgdGhlIHNhbWUgZXBoZW1lcmFsIHB1YmxpYyBrZXksIHRoaXMgdHVybnMgYW4gRUNESCBwZXIgZnJhbWUgaW50byBhblxuICogRUNESCBwZXIgd3JpdGVyLiBDb3JyZWN0bmVzcyBkb2VzIG5vdCBkZXBlbmQgb24gdGhlIHdyaXRlciBoYXZpbmcgdXNlZCBhXG4gKiBzZXNzaW9uIOKAlCBhIHN0cmVhbSBvZiBpbmRlcGVuZGVudGx5IHNlYWxlZCBwYXlsb2FkcyBzaW1wbHkgbWlzc2VzIHRoZSBjYWNoZVxuICogb24gZWFjaCBuZXcgZXBoZW1lcmFsIGtleS5cbiAqXG4gKiBUaGUgY2FjaGUgaXMga2V5ZWQgYnkgdGhlIGVwaGVtZXJhbCBwdWJsaWMga2V5IGFuZCBob2xkcyBvbmUgZW50cnksIHdoaWNoIGlzXG4gKiB0aGUgY29tbW9uIGNhc2UgKG9uZSB3cml0ZXIgcGVyIHN0cmVhbSkuIEEgc2Vjb25kIHdyaXRlciBldmljdHMgdGhlIGZpcnN0XG4gKiByYXRoZXIgdGhhbiBncm93aW5nIHdpdGhvdXQgYm91bmQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVPcGVuU2Vzc2lvbihcbiAga2V5UGFpcjogUnVuS2V5UGFpcixcbiAgYWFkPzogVWludDhBcnJheVxuKTogeyBvcGVuKHNlYWxlZDogVWludDhBcnJheSk6IFByb21pc2U8VWludDhBcnJheT4gfSB7XG4gIGxldCBjYWNoZWRTZW5kZXI6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IGNhY2hlZEtleTogUHJvbWlzZTxDcnlwdG9LZXk+IHwgdW5kZWZpbmVkO1xuXG4gIHJldHVybiB7XG4gICAgYXN5bmMgb3BlbihzZWFsZWQ6IFVpbnQ4QXJyYXkpOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgICAgIGNvbnN0IG1pbkxlbmd0aCA9IFgyNTUxOV9LRVlfTEVOR1RIICsgTk9OQ0VfTEVOR1RIICsgVEFHX0JZVEVTO1xuICAgICAgaWYgKHNlYWxlZC5ieXRlTGVuZ3RoIDwgbWluTGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBSdW50aW1lRGVjcnlwdGlvbkVycm9yKFxuICAgICAgICAgIGBTZWFsZWQgcGF5bG9hZCB0b28gc2hvcnQ6IGV4cGVjdGVkIGF0IGxlYXN0ICR7bWluTGVuZ3RofSBieXRlcywgZ290ICR7c2VhbGVkLmJ5dGVMZW5ndGh9YCxcbiAgICAgICAgICB7IGNvbnRleHQ6IHsgb3BlcmF0aW9uOiAnZGVjcnlwdCcsIGJ5dGVMZW5ndGg6IHNlYWxlZC5ieXRlTGVuZ3RoIH0gfVxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlcGhlbWVyYWxQdWJsaWNLZXkgPSBzZWFsZWQuc3ViYXJyYXkoMCwgWDI1NTE5X0tFWV9MRU5HVEgpO1xuICAgICAgY29uc3QgZW5jcnlwdGVkID0gc2VhbGVkLnN1YmFycmF5KFgyNTUxOV9LRVlfTEVOR1RIKTtcblxuICAgICAgY29uc3Qgc2VuZGVyID0ga2V5Q2FjaGVJZChlcGhlbWVyYWxQdWJsaWNLZXkpO1xuICAgICAgaWYgKHNlbmRlciAhPT0gY2FjaGVkU2VuZGVyIHx8ICFjYWNoZWRLZXkpIHtcbiAgICAgICAgY2FjaGVkU2VuZGVyID0gc2VuZGVyO1xuICAgICAgICBjYWNoZWRLZXkgPSBkZWNhcHN1bGF0ZShrZXlQYWlyLCBlcGhlbWVyYWxQdWJsaWNLZXkpO1xuICAgICAgfVxuXG4gICAgICBsZXQgY29udGVudEtleTogQ3J5cHRvS2V5O1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29udGVudEtleSA9IGF3YWl0IGNhY2hlZEtleTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIERvIG5vdCBsZXQgb25lIGJhZCBmcmFtZSBwb2lzb24gdGhlIGNhY2hlIGZvciBzdWJzZXF1ZW50IGZyYW1lcy5cbiAgICAgICAgY2FjaGVkU2VuZGVyID0gdW5kZWZpbmVkO1xuICAgICAgICBjYWNoZWRLZXkgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYWVzR2NtRGVjcnlwdChjb250ZW50S2V5LCBlbmNyeXB0ZWQsIGFhZCk7XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqIFN0YWJsZSBjYWNoZSBrZXkgZm9yIGEgMzItYnl0ZSBwdWJsaWMga2V5LiAqL1xuZnVuY3Rpb24ga2V5Q2FjaGVJZChwdWJsaWNLZXk6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xuICBsZXQgaWQgPSAnJztcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBwdWJsaWNLZXkubGVuZ3RoOyBpKyspIHtcbiAgICBpZCArPSBwdWJsaWNLZXlbaV0udG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsICcwJyk7XG4gIH1cbiAgcmV0dXJuIGlkO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBhZGRpdGlvbmFsIGF1dGhlbnRpY2F0ZWQgZGF0YSB0aGF0IGJpbmRzIGEgc2VhbGVkIHBheWxvYWQgdG8gYVxuICogc3BlY2lmaWMgcnVuLlxuICpcbiAqIE1pcnJvcnMgdGhlIGBpbmZvYCB1c2VkIGZvciBzeW1tZXRyaWMgcGVyLXJ1biBrZXkgZGVyaXZhdGlvbiBzbyB0aGUgdHdvXG4gKiBzY2hlbWVzIGFncmVlIG9uIHdoYXQgXCJ0aGlzIHJ1blwiIG1lYW5zLlxuICpcbiAqIE5vdGUgdGhhdCB0aGUgc2VhbGVkLWJveCBjb25zdHJ1Y3Rpb24gYWxyZWFkeSBiaW5kcyBhIHBheWxvYWQgdG8gaXRzXG4gKiByZWNpcGllbnQgd2l0aG91dCBhbnkgQUFEOiB0aGUgY29udGVudCBrZXkgaXMgZGVyaXZlZCBvdmVyXG4gKiBgZXBoZW1lcmFsUHVibGljS2V5IOKAliByZWNpcGllbnRQdWJsaWNLZXlgLCBhbmQgYSByZWNpcGllbnQgcHVibGljIGtleSBpc1xuICogdW5pcXVlIHBlciAoZGVwbG95bWVudCBrZXkgw5cgcHJvamVjdCDDlyBydW4pLiBSZXBsYXlpbmcgYSBzZWFsZWQgcGF5bG9hZCBhdFxuICogYSBkaWZmZXJlbnQgcnVuIHRoZXJlZm9yZSBmYWlscyBhdCBrZXkgYWdyZWVtZW50IHJlZ2FyZGxlc3MuIEFBRCBpc1xuICogYXZhaWxhYmxlIGZvciBjYWxsZXJzIHRoYXQgd2FudCBhbiBhZGRpdGlvbmFsLCBLREYtaW5kZXBlbmRlbnQgYmluZGluZyDigJRcbiAqIGJvdGggc2lkZXMgbXVzdCBzdXBwbHkgYnl0ZS1pZGVudGljYWwgdmFsdWVzIG9yIHRoZSBwYXlsb2FkIHdpbGwgbm90IG9wZW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5BYWQocHJvamVjdElkOiBzdHJpbmcsIHJ1bklkOiBzdHJpbmcpOiBVaW50OEFycmF5IHtcbiAgcmV0dXJuIGluZm9FbmNvZGVyLmVuY29kZShgJHtwcm9qZWN0SWR9fCR7cnVuSWR9YCk7XG59XG5cbi8qKlxuICogRGVjb2RlIGEgcnVuJ3MgcHVibGlzaGVkIHB1YmxpYyBrZXksIHZhbGlkYXRpbmcgYm90aCBlbmNvZGluZyBhbmQgbGVuZ3RoLlxuICpcbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiB0aGUgdmFsdWUgaXMgYWJzZW50LCBub3QgdmFsaWQgYmFzZTY0LCBvciBub3RcbiAqIGV4YWN0bHkgMzIgYnl0ZXMuIENhbGxlcnMgdHJlYXQgdGhhdCBhcyBcInRoaXMgcnVuIGhhcyBubyB1c2FibGUgcHVibGljIGtleVwiXG4gKiBhbmQgZmFsbCBiYWNrIHRvIHRoZSBzeW1tZXRyaWMgcGF0aCwgc28gYSBjb3JydXB0IG9yIHRydW5jYXRlZCBzdG9yZWQgdmFsdWVcbiAqIGRlZ3JhZGVzIHRvIHRoZSBwcmUtZXhpc3RpbmcgYmVoYXZpb3IgaW5zdGVhZCBvZiBmYWlsaW5nIGEgcmVzdW1wdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZVJ1blB1YmxpY0tleShcbiAgdmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZFxuKTogVWludDhBcnJheSB8IHVuZGVmaW5lZCB7XG4gIGlmICghdmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGJ5dGVzID0gYmFzZTY0VG9CeXRlcyh2YWx1ZSk7XG4gIGlmICghYnl0ZXMgfHwgYnl0ZXMuYnl0ZUxlbmd0aCAhPT0gWDI1NTE5X0tFWV9MRU5HVEgpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiBieXRlcztcbn1cbiJdfQ==