@dbx-tools/tunnel 0.6.60 → 0.6.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -56
- package/index.ts +6 -3
- package/lib/index.d.ts +6 -3
- package/lib/index.js +5 -3
- package/lib/src/{app.d.ts → code-email.d.ts} +10 -61
- package/lib/src/code-email.js +108 -0
- package/lib/src/gate.d.ts +60 -0
- package/lib/src/gate.js +196 -0
- package/lib/src/interceptor.d.ts +4 -4
- package/lib/src/interceptor.js +5 -5
- package/lib/src/plugin.d.ts +57 -3
- package/lib/src/plugin.js +77 -6
- package/lib/src/send-code.d.ts +28 -0
- package/lib/src/send-code.js +68 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -7
- package/src/code-email.ts +118 -0
- package/src/gate.ts +241 -0
- package/src/interceptor.ts +4 -4
- package/src/plugin.ts +136 -6
- package/src/send-code.ts +112 -0
- package/lib/src/app.js +0 -258
- package/lib/src/proxy.d.ts +0 -49
- package/lib/src/proxy.js +0 -247
- package/src/app.ts +0 -292
- package/src/proxy.ts +0 -299
package/lib/src/plugin.js
CHANGED
|
@@ -18,18 +18,37 @@
|
|
|
18
18
|
import { Plugin, toPlugin } from "@databricks/appkit";
|
|
19
19
|
import { brand, env, log, object, string } from "@dbx-tools/shared-core";
|
|
20
20
|
import { looksLikeEmail, matchesAllowlist } from "./allowlist.js";
|
|
21
|
-
import { ALLOW_ENV, BRAND_NAME_ENV, CODE_TTL_ENV, MESSAGE_ENV, SESSION_TTL_ENV, SUBJECT_ENV, } from "./env.js";
|
|
21
|
+
import { ALLOW_ENV, BRAND_NAME_ENV, CODE_TTL_ENV, FORWARD_HEADERS_ENV, INSECURE_ENV, MESSAGE_ENV, PUBLIC_DOMAIN_ENV, SESSION_TTL_ENV, SUBJECT_ENV, } from "./env.js";
|
|
22
|
+
import { mountGate } from "./gate.js";
|
|
22
23
|
import { CodeStore, signSession, verifySession } from "./otp.js";
|
|
23
24
|
import { RateLimiter } from "./rate-limit.js";
|
|
25
|
+
import { ensureEmailAvailable, sendCode as defaultSendCode } from "./send-code.js";
|
|
24
26
|
import { KEY_TTL_SECONDS, resolveSessionCutoff, signingKey } from "./signing-key.js";
|
|
25
27
|
const logger = log.logger("tunnel:auth");
|
|
28
|
+
function serverApplication(context) {
|
|
29
|
+
const server = context.getPlugins().get("server");
|
|
30
|
+
const application = server?.serverApplication;
|
|
31
|
+
return application &&
|
|
32
|
+
typeof application.get === "function" &&
|
|
33
|
+
typeof application.post === "function" &&
|
|
34
|
+
typeof application.use === "function"
|
|
35
|
+
? application
|
|
36
|
+
: undefined;
|
|
37
|
+
}
|
|
38
|
+
export function mountGateOnContext(context, options) {
|
|
39
|
+
const application = serverApplication(context);
|
|
40
|
+
if (application) {
|
|
41
|
+
mountGate(options, (method, path, handler) => application[method](path, handler), (path, handler) => application.use(path, handler));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
mountGate(options, (method, path, handler) => context.addRoute(method, path, handler), (path, handler) => context.addMiddleware(path, handler));
|
|
45
|
+
}
|
|
26
46
|
const DEFAULTS = {
|
|
27
47
|
subject: "Your verification code",
|
|
28
48
|
// The repo-wide brand context's display name, NOT a hardcoded product string:
|
|
29
49
|
// this name is what the recipient reads in the code email, so it has to be the
|
|
30
50
|
// same identity the rest of the app presents. A host with its own
|
|
31
|
-
// `branding/brand.yaml` overrides it by passing `brandName
|
|
32
|
-
// {@link startGateApp}, which resolves the on-disk context); the shared default
|
|
51
|
+
// `branding/brand.yaml` overrides it by passing `brandName`; the shared default
|
|
33
52
|
// is the fallback when nothing is configured.
|
|
34
53
|
brandName: brand.defaultBrandContext.name,
|
|
35
54
|
message: "Your verification code is:",
|
|
@@ -53,9 +72,21 @@ export function resolveAuthGateConfig(config) {
|
|
|
53
72
|
codeTtlSeconds: env.positiveInt(config.codeTtlSeconds, CODE_TTL_ENV, DEFAULTS.codeTtlSeconds),
|
|
54
73
|
maxAttempts: config.maxAttempts ?? DEFAULTS.maxAttempts,
|
|
55
74
|
sessionCutoffMs: resolveSessionCutoff(config.sessionCutoff),
|
|
75
|
+
publicDomain: env.string(config.publicDomain, PUBLIC_DOMAIN_ENV) ?? undefined,
|
|
76
|
+
forwardHeaders: [
|
|
77
|
+
...string.parseList(config.forwardHeaders),
|
|
78
|
+
...string.parseList(env.text(FORWARD_HEADERS_ENV)),
|
|
79
|
+
],
|
|
80
|
+
insecure: env.boolean(config.insecure, INSECURE_ENV) ?? false,
|
|
56
81
|
};
|
|
57
82
|
}
|
|
58
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* AppKit plugin owning the email-OTP gate. On `setup()` it registers the login
|
|
85
|
+
* routes (`/api/email/auth/*`) and a gating middleware on the app's OWN Express
|
|
86
|
+
* server via `this.context`, so a public portr caller must prove an email before
|
|
87
|
+
* reaching the app's `/api/*` - see `./gate`. Front-door (platform) traffic and
|
|
88
|
+
* other local callers pass through untouched (the gate keys on the `Host` header).
|
|
89
|
+
*/
|
|
59
90
|
export class AuthGatePlugin extends Plugin {
|
|
60
91
|
static manifest = {
|
|
61
92
|
name: "authGate",
|
|
@@ -77,12 +108,52 @@ export class AuthGatePlugin extends Plugin {
|
|
|
77
108
|
// cache that cannot hold it (and the resulting "sessions won't survive a
|
|
78
109
|
// restart" warning) shows up in the startup log, not hours later.
|
|
79
110
|
const { cutoffMs } = await signingKey(this.resolved.sessionCutoffMs);
|
|
111
|
+
if (this.resolved.insecure) {
|
|
112
|
+
logger.warn("insecure mode - the tunnel runs OPEN with no email-OTP gate");
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// `server()` is deferred, so it does not exist during this plugin's setup.
|
|
116
|
+
// At `setup:complete` the Express app exists but has not injected plugin
|
|
117
|
+
// routes or static handling yet, which is the one point the gate can mount
|
|
118
|
+
// ahead of every protected route.
|
|
119
|
+
this.context?.onLifecycle("setup:complete", async () => {
|
|
120
|
+
this.mountGateRoutes();
|
|
121
|
+
// Fail fast once the sibling email plugin has primed its transport: a
|
|
122
|
+
// gate that cannot email a code lets nobody in.
|
|
123
|
+
await ensureEmailAvailable();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
80
126
|
logger.info("ready", {
|
|
81
127
|
patterns: this.resolved.allow.length,
|
|
82
128
|
sessionTtlSeconds: this.resolved.sessionTtlSeconds,
|
|
129
|
+
publicDomain: this.resolved.publicDomain ?? null,
|
|
130
|
+
insecure: this.resolved.insecure,
|
|
83
131
|
...object.optional("sessionCutoff", cutoffMs > 0 ? new Date(cutoffMs).toISOString() : null),
|
|
84
132
|
});
|
|
85
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Register the login routes (`/api/email/auth/*`) and the gating middleware on
|
|
136
|
+
* the app's OWN Express server. At `setup:complete`, the deferred server plugin
|
|
137
|
+
* has constructed its Express app but has not injected plugin routes or static
|
|
138
|
+
* handling, so direct registration puts the gate first. The context's buffered
|
|
139
|
+
* route API remains a fallback for compatible non-standard server plugins.
|
|
140
|
+
*/
|
|
141
|
+
mountGateRoutes() {
|
|
142
|
+
const context = this.context;
|
|
143
|
+
if (!context) {
|
|
144
|
+
logger.warn("no plugin context - the OTP gate cannot mount its routes");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
mountGateOnContext(context, {
|
|
148
|
+
gate: this.exports(),
|
|
149
|
+
publicDomain: this.resolved.publicDomain,
|
|
150
|
+
forwardHeaders: this.resolved.forwardHeaders,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** The code sender: the configured `sendCode`, else the shared-transport default. */
|
|
154
|
+
get sendCode() {
|
|
155
|
+
return this.config.sendCode ?? defaultSendCode;
|
|
156
|
+
}
|
|
86
157
|
exports() {
|
|
87
158
|
return {
|
|
88
159
|
sessionTtlSeconds: this.resolved.sessionTtlSeconds,
|
|
@@ -106,7 +177,7 @@ export class AuthGatePlugin extends Plugin {
|
|
|
106
177
|
if (looksLikeEmail(address) && matchesAllowlist(address, this.resolved.allow)) {
|
|
107
178
|
const code = await this.codes.issue(address);
|
|
108
179
|
try {
|
|
109
|
-
await this.
|
|
180
|
+
await this.sendCode(address, code, {
|
|
110
181
|
subject: this.resolved.subject,
|
|
111
182
|
brandName: this.resolved.brandName,
|
|
112
183
|
message: this.resolved.message,
|
|
@@ -135,4 +206,4 @@ export class AuthGatePlugin extends Plugin {
|
|
|
135
206
|
}
|
|
136
207
|
/** Factory: `authGate({ allow, subject, ... })` for an AppKit `plugins` array. */
|
|
137
208
|
export const authGate = toPlugin(AuthGatePlugin);
|
|
138
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUE4QyxNQUFNLG9CQUFvQixDQUFDO0FBQ2xHLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFekUsT0FBTyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsY0FBYyxFQUNkLFlBQVksRUFDWixXQUFXLEVBQ1gsZUFBZSxFQUNmLFdBQVcsR0FDWixNQUFNLFVBQVUsQ0FBQztBQUNsQixPQUFPLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxlQUFlLEVBQUUsb0JBQW9CLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFckYsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQXdGekMsTUFBTSxRQUFRLEdBQUc7SUFDZixPQUFPLEVBQUUsd0JBQXdCO0lBQ2pDLDhFQUE4RTtJQUM5RSwrRUFBK0U7SUFDL0Usa0VBQWtFO0lBQ2xFLGlFQUFpRTtJQUNqRSxnRkFBZ0Y7SUFDaEYsOENBQThDO0lBQzlDLFNBQVMsRUFBRSxLQUFLLENBQUMsbUJBQW1CLENBQUMsSUFBSTtJQUN6QyxPQUFPLEVBQUUsNEJBQTRCO0lBQ3JDLHVFQUF1RTtJQUN2RSxpQkFBaUIsRUFBRSxlQUFlO0lBQ2xDLGNBQWMsRUFBRSxHQUFHO0lBQ25CLFdBQVcsRUFBRSxD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LEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDaEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3RDLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMxRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssSUFBSTtZQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDbkYsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLFNBQVMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUM3QyxPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO0lBQzFGLENBQUM7O0FBR0gsa0ZBQWtGO0FBQ2xGLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGBhdXRoR2F0ZSgpYCAtIHRoZSBBcHBLaXQgcGx1Z2luIGJlaGluZCB0aGUgdHVubmVsJ3MgZW1haWwtT1RQIGdhdGUuXG4gKlxuICogSXQgaGFzIE5PIHJvdXRlcyBvZiBpdHMgb3duOiB0aGUgdHVubmVsIFBST1hZIChub3QgYW4gSFRUUCBzZXJ2ZXIpIGNhbGxzIHRoZVxuICogaGFuZGxlcnMgdGhpcyBwbHVnaW4gZXhwb3NlcyB2aWEge0BsaW5rIEF1dGhHYXRlUGx1Z2luLmV4cG9ydHN9LiBUaGUgcGx1Z2luXG4gKiBvd25zIHRoZSBhbGxvdy1saXN0LCB0aGUgcGVyLWVtYWlsL3Blci1JUCByYXRlIGxpbWl0ZXJzLCB0aGUgQ2FjaGVNYW5hZ2VyLWJhY2tlZFxuICogb25lLXRpbWUtY29kZSBzdG9yZSwgYW5kIHRoZSBzZXNzaW9uIEpXVC4gYGNyZWF0ZUFwcGAgKHdpdGggbm8gYHNlcnZlcigpYCkgaXNcbiAqIHVzZWQgb25seSB0byBhdXRvLWluaXQgYENhY2hlTWFuYWdlcmAgKyBwcmltZSB0aGUgc2libGluZyBgZW1haWxgIHRyYW5zcG9ydDtcbiAqIHRoaXMgcGx1Z2luIGlzIHdoZXJlIHRoZSBnYXRlIGxvZ2ljIGxpdmVzLlxuICpcbiAqIE9wdGlvbnMgY29tZSBmcm9tIENMSSBmbGFncyBPUiBlbnYsIHdpdGggc2Vuc2libGUgZGVmYXVsdHMgLSBzZWVcbiAqIHtAbGluayByZXNvbHZlQXV0aEdhdGVDb25maWd9LiBUaGUgb25lIHJ1bnRpbWUgZGVwZW5kZW5jeSB0aGUgcGx1Z2luIGNhbid0XG4gKiByZXNvbHZlIGl0c2VsZiBpcyBIT1cgdG8gZW1haWwgdGhlIGNvZGUsIHNvIGl0IHRha2VzIGEgYHNlbmRDb2RlYCBjYWxsYmFjayB0aGVcbiAqIGFwcCB3aXJlcyB0byB0aGUgZW1haWwgcGx1Z2luLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBQbHVnaW4sIHRvUGx1Z2luLCB0eXBlIEJhc2VQbHVnaW5Db25maWcsIHR5cGUgUGx1Z2luTWFuaWZlc3QgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBicmFuZCwgZW52LCBsb2csIG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgQXV0aFN0YXR1cyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1lbWFpbFwiO1xuaW1wb3J0IHsgbG9va3NMaWtlRW1haWwsIG1hdGNoZXNBbGxvd2xpc3QgfSBmcm9tIFwiLi9hbGxvd2xpc3QudHNcIjtcbmltcG9ydCB7XG4gIEFMTE9XX0VOVixcbiAgQlJBTkRfTkFNRV9FTlYsXG4gIENPREVfVFRMX0VOVixcbiAgTUVTU0FHRV9FTlYsXG4gIFNFU1NJT05fVFRMX0VOVixcbiAgU1VCSkVDVF9FTlYsXG59IGZyb20gXCIuL2Vudi50c1wiO1xuaW1wb3J0IHsgQ29kZVN0b3JlLCBzaWduU2Vzc2lvbiwgdmVyaWZ5U2Vzc2lvbiB9IGZyb20gXCIuL290cC50c1wiO1xuaW1wb3J0IHsgUmF0ZUxpbWl0ZXIgfSBmcm9tIFwiLi9yYXRlLWxpbWl0LnRzXCI7XG5pbXBvcnQgeyBLRVlfVFRMX1NFQ09ORFMsIHJlc29sdmVTZXNzaW9uQ3V0b2ZmLCBzaWduaW5nS2V5IH0gZnJvbSBcIi4vc2lnbmluZy1rZXkudHNcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcInR1bm5lbDphdXRoXCIpO1xuXG4vKiogT3B0aW9ucyBmb3IgdGhlIHtAbGluayBhdXRoR2F0ZX0gcGx1Z2luIChhbGwgcmVzb2x2YWJsZSBmcm9tIGVudiAtIHNlZSBiZWxvdykuICovXG5leHBvcnQgaW50ZXJmYWNlIEF1dGhHYXRlQ29uZmlnIGV4dGVuZHMgQmFzZVBsdWdpbkNvbmZpZyB7XG4gIC8qKiBBbGxvdy1saXN0IHBhdHRlcm5zIChkb21haW4gLyBnbG9iIC8gYC9yZWdleC9gKS4gRW1wdHkgPSBhbGxvdyBub2JvZHkuIEVudiBUVU5ORUxfQVVUSF9BTExPVy4gKi9cbiAgYWxsb3c/OiBzdHJpbmcgfCBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIFN1YmplY3QgbGluZSBmb3IgdGhlIGNvZGUgZW1haWwuIEVudiBUVU5ORUxfQVVUSF9TVUJKRUNULlxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBcIllvdXIgdmVyaWZpY2F0aW9uIGNvZGVcIi4gVGhlIHdvcmRpbmcgb2YgdGhlIHN1YmplY3QgYW5kXG4gICAqIHtAbGluayBtZXNzYWdlfSBpcyBkZWxpYmVyYXRlbHkgdGhlIGNvbnZlbnRpb25hbCBwaHJhc2luZyByYXRoZXIgdGhhblxuICAgKiBhbnl0aGluZyBicmFuZGVkOiBpT1MsIEdtYWlsLCBPdXRsb29rLCBhbmQgQW5kcm9pZCBhbGwgZGV0ZWN0IGEgb25lLXRpbWVcbiAgICogY29kZSBmcm9tIHRoaXMgc2hhcGUgYW5kIG9mZmVyIHRvIGF1dG9maWxsIGl0LCBhbmQgYSBub3ZlbCBwaHJhc2luZyBpcyB3aGF0XG4gICAqIGJyZWFrcyB0aGF0IGRldGVjdGlvbi5cbiAgICpcbiAgICogVGhpcyBpcyB0aGUgc3ViamVjdCBURU1QTEFURSwgbm90IHRoZSBsaXRlcmFsIGxpbmUgc2VudDogdGhlIGNvZGUgaXMgc3BsaWNlZFxuICAgKiBpbnRvIGl0IChgXCIxMjM0NTYgaXMgeW91ciB2ZXJpZmljYXRpb24gY29kZVwiYCkgYmVjYXVzZSBhIHB1c2ggbm90aWZpY2F0aW9uXG4gICAqIHNob3dzIG9ubHkgdGhlIHN1YmplY3QgYW5kIHByZWhlYWRlciwgYW5kIHRoYXQgbm90aWZpY2F0aW9uIGlzIHdoYXQgbW9iaWxlXG4gICAqIGF1dG9maWxsIHJlYWRzLiBTZWUgYGNvZGVFbWFpbFN1YmplY3RgIGluIGAuL2FwcC50c2AuXG4gICAqL1xuICBzdWJqZWN0Pzogc3RyaW5nO1xuICAvKipcbiAgICogRGlzcGxheSBuYW1lIHVzZWQgaW4gdGhlIGNvZGUgZW1haWwgY29weS4gRW52IFRVTk5FTF9BVVRIX0JSQU5EX05BTUUuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIHRoZSBicmFuZCBjb250ZXh0J3MgYG5hbWVgIC0gdGhlIGFwcCdzIG93biBgYnJhbmRpbmcvYnJhbmQueWFtbGBcbiAgICogd2hlbiBpdCBoYXMgb25lLCBlbHNlIHRoZSBkYngtdG9vbHMgZGVmYXVsdC4gU2V0IHRoaXMgb25seSB0byBvdmVycmlkZSB0aGVcbiAgICogYnJhbmQgZm9yIHRoaXMgZ2F0ZS5cbiAgICovXG4gIGJyYW5kTmFtZT86IHN0cmluZztcbiAgLyoqXG4gICAqIExpbmUgc2hvd24gaW1tZWRpYXRlbHkgYWJvdmUgdGhlIGNvZGUgaW4gdGhlIGVtYWlsLiBFbnYgVFVOTkVMX0FVVEhfTUVTU0FHRS5cbiAgICpcbiAgICogS2VlcCB0aGUgY29kZSBvbiBpdHMgT1dOIGxpbmUgZGlyZWN0bHkgYWZ0ZXIgdGhpcyB0ZXh0IC0gdGhhdCBhZGphY2VuY3kgaXNcbiAgICogd2hhdCB0aGUgcGxhdGZvcm0gY29kZS1kZXRlY3Rpb24gaGV1cmlzdGljcyBrZXkgb24uXG4gICAqL1xuICBtZXNzYWdlPzogc3RyaW5nO1xuICAvKipcbiAgICogU2Vzc2lvbiBsaWZldGltZSAoc2Vjb25kcykuIEVudiBUVU5ORUxfQVVUSF9TRVNTSU9OX1RUTC4gRGVmYXVsdCAyNTkyMDAwICgzMGQpLlxuICAgKlxuICAgKiBNYXRjaGVkIHRvIHRoZSBjYWNoZS1iYWNrZWQgc2lnbmluZyBrZXkncyBvd24gMzAtZGF5IFRUTCAoc2VlXG4gICAqIGAuL3NpZ25pbmcta2V5LnRzYCk6IHRoZSBjb29raWUgYW5kIHRoZSBrZXkgdGhhdCB2YWxpZGF0ZXMgaXQgc2hvdWxkIGV4cGlyZVxuICAgKiB0b2dldGhlciwgb3Igb25lIHNpbGVudGx5IG91dGxpdmVzIHRoZSBvdGhlci5cbiAgICovXG4gIHNlc3Npb25UdGxTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogT25lLXRpbWUtY29kZSBsaWZldGltZSAoc2Vjb25kcykuIEVudiBUVU5ORUxfQVVUSF9DT0RFX1RUTC4gRGVmYXVsdCA2MDAgKDEwbSkuICovXG4gIGNvZGVUdGxTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogTWF4IHZlcmlmeSBhdHRlbXB0cyBwZXIgaXNzdWVkIGNvZGUuIERlZmF1bHQgNS4gKi9cbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBGb3JjZS1jbGVhciBjdXRvZmY6IGV2ZXJ5IHNlc3Npb24gaXNzdWVkIEJFRk9SRSBpdCBzdG9wcyB2ZXJpZnlpbmcsIHNvIG1vdmluZ1xuICAgKiBpdCBmb3J3YXJkIHNpZ25zIGV2ZXJ5b25lIG91dC4gRW52IFRVTk5FTF9BVVRIX1NFU1NJT05fQ1VUT0ZGLlxuICAgKlxuICAgKiBBbnl0aGluZyBgb2JqZWN0LnRvRGF0ZWAgYWNjZXB0czogYSBgRGF0ZWAsIGAyMDI2LTA4LTAyYCwgYW4gSVNPIGluc3RhbnQsXG4gICAqIGVwb2NoIHNlY29uZHMvbWlsbGlzLCBvciBhIHJlbGF0aXZlIGR1cmF0aW9uIChgLTMwZGAsIGA3IGRheXMgYWdvYCkuIFVuc2V0XG4gICAqIG1lYW5zIG5vIGN1dG9mZi5cbiAgICovXG4gIHNlc3Npb25DdXRvZmY/OiBzdHJpbmcgfCBudW1iZXIgfCBEYXRlO1xuICAvKiogRGVsaXZlciBhIGNvZGUgdG8gYW4gYWRkcmVzcy4gV2lyZWQgYnkgdGhlIGFwcCB0byB0aGUgZW1haWwgcGx1Z2luLiAqL1xuICBzZW5kQ29kZT86IChlbWFpbDogc3RyaW5nLCBjb2RlOiBzdHJpbmcsIG9wdHM6IFNlbmRDb2RlT3B0aW9ucykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqIEJyYW5kaW5nL21lc3NhZ2luZyBwYXNzZWQgdG8ge0BsaW5rIEF1dGhHYXRlQ29uZmlnLnNlbmRDb2RlfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VuZENvZGVPcHRpb25zIHtcbiAgc3ViamVjdDogc3RyaW5nO1xuICBicmFuZE5hbWU6IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICAvKipcbiAgICogTGlmZXRpbWUgb2YgdGhlIGNvZGUgYmVpbmcgc2VudCwgaW4gc2Vjb25kcyAtIHRoZSBSRVNPTFZFRFxuICAgKiB7QGxpbmsgQXV0aEdhdGVDb25maWcuY29kZVR0bFNlY29uZHN9LCBzbyB0aGUgZW1haWwgY2FuIHN0YXRlIHRoZSByZWFsXG4gICAqIGV4cGlyeSAoXCJUaGlzIGNvZGUgZXhwaXJlcyBpbiAxMCBtaW51dGVzXCIpIGluc3RlYWQgb2YgYSB2YWd1ZSBcInNob3J0bHlcIlxuICAgKiB0aGF0IGRyaWZ0cyBmcm9tIHRoZSBjb25maWd1cmVkIFRUTC5cbiAgICovXG4gIGNvZGVUdGxTZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKiBSZXNvbHZlZCBnYXRlIGNvbmZpZyB3aXRoIGVudiBmYWxsYmFja3MgKyBkZWZhdWx0cyBhcHBsaWVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZEF1dGhHYXRlQ29uZmlnIHtcbiAgYWxsb3c6IHN0cmluZ1tdO1xuICBzdWJqZWN0OiBzdHJpbmc7XG4gIGJyYW5kTmFtZTogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIHNlc3Npb25UdGxTZWNvbmRzOiBudW1iZXI7XG4gIGNvZGVUdGxTZWNvbmRzOiBudW1iZXI7XG4gIG1heEF0dGVtcHRzOiBudW1iZXI7XG4gIC8qKiBGb3JjZS1jbGVhciBjdXRvZmYgaW4gZXBvY2ggbXM7IGAwYCB3aGVuIHVuc2V0LiAqL1xuICBzZXNzaW9uQ3V0b2ZmTXM6IG51bWJlcjtcbn1cblxuY29uc3QgREVGQVVMVFMgPSB7XG4gIHN1YmplY3Q6IFwiWW91ciB2ZXJpZmljYXRpb24gY29kZVwiLFxuICAvLyBUaGUgcmVwby13aWRlIGJyYW5kIGNvbnRleHQncyBkaXNwbGF5IG5hbWUsIE5PVCBhIGhhcmRjb2RlZCBwcm9kdWN0IHN0cmluZzpcbiAgLy8gdGhpcyBuYW1lIGlzIHdoYXQgdGhlIHJlY2lwaWVudCByZWFkcyBpbiB0aGUgY29kZSBlbWFpbCwgc28gaXQgaGFzIHRvIGJlIHRoZVxuICAvLyBzYW1lIGlkZW50aXR5IHRoZSByZXN0IG9mIHRoZSBhcHAgcHJlc2VudHMuIEEgaG9zdCB3aXRoIGl0cyBvd25cbiAgLy8gYGJyYW5kaW5nL2JyYW5kLnlhbWxgIG92ZXJyaWRlcyBpdCBieSBwYXNzaW5nIGBicmFuZE5hbWVgIChzZWVcbiAgLy8ge0BsaW5rIHN0YXJ0R2F0ZUFwcH0sIHdoaWNoIHJlc29sdmVzIHRoZSBvbi1kaXNrIGNvbnRleHQpOyB0aGUgc2hhcmVkIGRlZmF1bHRcbiAgLy8gaXMgdGhlIGZhbGxiYWNrIHdoZW4gbm90aGluZyBpcyBjb25maWd1cmVkLlxuICBicmFuZE5hbWU6IGJyYW5kLmRlZmF1bHRCcmFuZENvbnRleHQubmFtZSxcbiAgbWVzc2FnZTogXCJZb3VyIHZlcmlmaWNhdGlvbiBjb2RlIGlzOlwiLFxuICAvLyAzMCBkYXlzLCB0aGUgc2FtZSB3aW5kb3cgdGhlIGNhY2hlLWJhY2tlZCBzaWduaW5nIGtleSBpcyBzdG9yZWQgZm9yLlxuICBzZXNzaW9uVHRsU2Vjb25kczogS0VZX1RUTF9TRUNPTkRTLFxuICBjb2RlVHRsU2Vjb25kczogNjAwLFxuICBtYXhBdHRlbXB0czogNSxcbn07XG5cbi8qKiBNZXJnZSB7QGxpbmsgQXV0aEdhdGVDb25maWd9IG92ZXIgZW52IG92ZXIgZGVmYXVsdHMgaW50byBhIHJlc29sdmVkIGNvbmZpZy4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQXV0aEdhdGVDb25maWcoY29uZmlnOiBBdXRoR2F0ZUNvbmZpZyk6IFJlc29sdmVkQXV0aEdhdGVDb25maWcge1xuICByZXR1cm4ge1xuICAgIC8vIEJvdGggc291cmNlcyBhcmUgdW5pb25lZCByYXRoZXIgdGhhbiBvbmUgb3ZlcnJpZGluZzogYSBkZXBsb3ltZW50LXdpZGVcbiAgICAvLyBUVU5ORUxfQVVUSF9BTExPVyBhbmQgYSBwZXItaW52b2NhdGlvbiBgLS1hbGxvd2Agc2hvdWxkIGJvdGggZ3JhbnQgYWNjZXNzLlxuICAgIC8vIEhlbmNlIGBwYXJzZUxpc3RgIG9uIGVhY2ggcmF0aGVyIHRoYW4gYGVudi5saXN0YCwgd2hpY2ggc3RvcHMgYXQgdGhlIGZpcnN0XG4gICAgLy8gc291cmNlIHRoYXQgeWllbGRzIGFueXRoaW5nLlxuICAgIGFsbG93OiBbLi4uc3RyaW5nLnBhcnNlTGlzdChjb25maWcuYWxsb3cpLCAuLi5zdHJpbmcucGFyc2VMaXN0KGVudi50ZXh0KEFMTE9XX0VOVikpXSxcbiAgICBzdWJqZWN0OiBlbnYuc3RyaW5nKGNvbmZpZy5zdWJqZWN0LCBTVUJKRUNUX0VOVikgPz8gREVGQVVMVFMuc3ViamVjdCxcbiAgICBicmFuZE5hbWU6IGVudi5zdHJpbmcoY29uZmlnLmJyYW5kTmFtZSwgQlJBTkRfTkFNRV9FTlYpID8/IERFRkFVTFRTLmJyYW5kTmFtZSxcbiAgICBtZXNzYWdlOiBlbnYuc3RyaW5nKGNvbmZpZy5tZXNzYWdlLCBNRVNTQUdFX0VOVikgPz8gREVGQVVMVFMubWVzc2FnZSxcbiAgICBzZXNzaW9uVHRsU2Vjb25kczogZW52LnBvc2l0aXZlSW50KFxuICAgICAgY29uZmlnLnNlc3Npb25UdGxTZWNvbmRzLFxuICAgICAgU0VTU0lPTl9UVExfRU5WLFxuICAgICAgREVGQVVMVFMuc2Vzc2lvblR0bFNlY29uZHMsXG4gICAgKSxcbiAgICBjb2RlVHRsU2Vjb25kczogZW52LnBvc2l0aXZlSW50KGNvbmZpZy5jb2RlVHRsU2Vjb25kcywgQ09ERV9UVExfRU5WLCBERUZBVUxUUy5jb2RlVHRsU2Vjb25kcyksXG4gICAgbWF4QXR0ZW1wdHM6IGNvbmZpZy5tYXhBdHRlbXB0cyA/PyBERUZBVUxUUy5tYXhBdHRlbXB0cyxcbiAgICBzZXNzaW9uQ3V0b2ZmTXM6IHJlc29sdmVTZXNzaW9uQ3V0b2ZmKGNvbmZpZy5zZXNzaW9uQ3V0b2ZmKSxcbiAgfTtcbn1cblxuLyoqIFRoZSBoYW5kbGVycyB0aGUgcHJveHkgY2FsbHMgaW4tcHJvY2VzcyAocmV0dXJuZWQgYnkge0BsaW5rIEF1dGhHYXRlUGx1Z2luLmV4cG9ydHN9KS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0aEdhdGVBcGkge1xuICAvKiogSGFuZGxlIGEgY29kZSByZXF1ZXN0LiBBbHdheXMgcmVzb2x2ZXMgYHsgb2s6IHRydWUgfWAgKGFudGktZW51bWVyYXRpb24pLiAqL1xuICByZXF1ZXN0KGVtYWlsOiBzdHJpbmcsIGlwOiBzdHJpbmcpOiBQcm9taXNlPHsgb2s6IHRydWU7IHJldHJ5QWZ0ZXI/OiBudW1iZXIgfT47XG4gIC8qKiBIYW5kbGUgYSBjb2RlIHZlcmlmaWNhdGlvbi4gT24gc3VjY2VzcyByZXR1cm5zIHRoZSBzZXNzaW9uIHRva2VuIHRvIGNvb2tpZS4gKi9cbiAgdmVyaWZ5KFxuICAgIGVtYWlsOiBzdHJpbmcsXG4gICAgY29kZTogc3RyaW5nLFxuICAgIGlwOiBzdHJpbmcsXG4gICk6IFByb21pc2U8eyBvazogYm9vbGVhbjsgdG9rZW4/OiBzdHJpbmc7IHJldHJ5QWZ0ZXI/OiBudW1iZXIgfT47XG4gIC8qKiBSZXNvbHZlIHRoZSBhdXRoZW50aWNhdGVkIGVtYWlsIGZvciBhIHNlc3Npb24gdG9rZW4sIG9yIHVuZGVmaW5lZC4gKi9cbiAgc2Vzc2lvbih0b2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+O1xuICAvKiogU2Vzc2lvbiBUVEwgaW4gc2Vjb25kcyAoZm9yIHRoZSBjb29raWUgTWF4LUFnZSkuICovXG4gIHJlYWRvbmx5IHNlc3Npb25UdGxTZWNvbmRzOiBudW1iZXI7XG4gIC8qKiBUaGUgZ2F0ZSBzdGF0dXMgcGF5bG9hZCAoYGVuYWJsZWRgIGlzIGFsd2F5cyB0cnVlIHdoZW4gdGhpcyBwbHVnaW4gcnVucykuICovXG4gIHN0YXR1cyh0b2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxBdXRoU3RhdHVzPjtcbn1cblxuLyoqIEFwcEtpdCBwbHVnaW4gb3duaW5nIHRoZSBlbWFpbC1PVFAgZ2F0ZSdzIGxvZ2ljIChubyBIVFRQIHJvdXRlczsgcHJveHktZHJpdmVuKS4gKi9cbmV4cG9ydCBjbGFzcyBBdXRoR2F0ZVBsdWdpbiBleHRlbmRzIFBsdWdpbjxBdXRoR2F0ZUNvbmZpZz4ge1xuICBzdGF0aWMgbWFuaWZlc3QgPSB7XG4gICAgbmFtZTogXCJhdXRoR2F0ZVwiLFxuICAgIGRpc3BsYXlOYW1lOiBcIkF1dGggR2F0ZVwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIkVtYWlsIG9uZS10aW1lLXBhc3N3b3JkIGFjY2VzcyBnYXRlIGZvciBhIHB1YmxpYyB0dW5uZWwuXCIsXG4gICAgc3RhYmlsaXR5OiBcImJldGFcIixcbiAgICByZXNvdXJjZXM6IHsgcmVxdWlyZWQ6IFtdLCBvcHRpb25hbDogW10gfSxcbiAgfSBzYXRpc2ZpZXMgUGx1Z2luTWFuaWZlc3Q8XCJhdXRoR2F0ZVwiPjtcblxuICBwcml2YXRlIHJlc29sdmVkITogUmVzb2x2ZWRBdXRoR2F0ZUNvbmZpZztcbiAgcHJpdmF0ZSBjb2RlcyE6IENvZGVTdG9yZTtcbiAgLy8gUmVxdWVzdGluZyBhIGNvZGUgaXMgZW1haWwtc3BhbS1wcm9uZTsgdmVyaWZ5aW5nIGlzIGEgYnJ1dGUtZm9yY2Ugc3VyZmFjZS5cbiAgLy8gUGVyLWVtYWlsIEFORCBwZXItSVAgc28gbmVpdGhlciBheGlzIGFsb25lIGlzIGEgYnlwYXNzLlxuICBwcml2YXRlIHJlYWRvbmx5IHJlcXVlc3RMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKDUsIDE1ICogNjAgKiAxMDAwKTtcbiAgcHJpdmF0ZSByZWFkb25seSB2ZXJpZnlMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKDEwLCAxNSAqIDYwICogMTAwMCk7XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc2V0dXAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5yZXNvbHZlZCA9IHJlc29sdmVBdXRoR2F0ZUNvbmZpZyh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5jb2RlcyA9IG5ldyBDb2RlU3RvcmUodGhpcy5yZXNvbHZlZC5jb2RlVHRsU2Vjb25kcywgdGhpcy5yZXNvbHZlZC5tYXhBdHRlbXB0cyk7XG4gICAgLy8gUmVzb2x2ZSB0aGUgc2lnbmluZyBrZXkgSEVSRSByYXRoZXIgdGhhbiBsYXppbHkgb24gdGhlIGZpcnN0IHNpZ24taW4sIHNvIGFcbiAgICAvLyBjYWNoZSB0aGF0IGNhbm5vdCBob2xkIGl0IChhbmQgdGhlIHJlc3VsdGluZyBcInNlc3Npb25zIHdvbid0IHN1cnZpdmUgYVxuICAgIC8vIHJlc3RhcnRcIiB3YXJuaW5nKSBzaG93cyB1cCBpbiB0aGUgc3RhcnR1cCBsb2csIG5vdCBob3VycyBsYXRlci5cbiAgICBjb25zdCB7IGN1dG9mZk1zIH0gPSBhd2FpdCBzaWduaW5nS2V5KHRoaXMucmVzb2x2ZWQuc2Vzc2lvbkN1dG9mZk1zKTtcbiAgICBsb2dnZXIuaW5mbyhcInJlYWR5XCIsIHtcbiAgICAgIHBhdHRlcm5zOiB0aGlzLnJlc29sdmVkLmFsbG93Lmxlbmd0aCxcbiAgICAgIHNlc3Npb25UdGxTZWNvbmRzOiB0aGlzLnJlc29sdmVkLnNlc3Npb25UdGxTZWNvbmRzLFxuICAgICAgLi4ub2JqZWN0Lm9wdGlvbmFsKFwic2Vzc2lvbkN1dG9mZlwiLCBjdXRvZmZNcyA+IDAgPyBuZXcgRGF0ZShjdXRvZmZNcykudG9JU09TdHJpbmcoKSA6IG51bGwpLFxuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZXhwb3J0cygpOiBBdXRoR2F0ZUFwaSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlc3Npb25UdGxTZWNvbmRzOiB0aGlzLnJlc29sdmVkLnNlc3Npb25UdGxTZWNvbmRzLFxuICAgICAgcmVxdWVzdDogKGVtYWlsLCBpcCkgPT4gdGhpcy5oYW5kbGVSZXF1ZXN0KGVtYWlsLCBpcCksXG4gICAgICB2ZXJpZnk6IChlbWFpbCwgY29kZSwgaXApID0+IHRoaXMuaGFuZGxlVmVyaWZ5KGVtYWlsLCBjb2RlLCBpcCksXG4gICAgICBzZXNzaW9uOiAodG9rZW4pID0+IHZlcmlmeVNlc3Npb24odG9rZW4pLFxuICAgICAgc3RhdHVzOiBhc3luYyAodG9rZW4pID0+ICh7XG4gICAgICAgIGF1dGhlbnRpY2F0ZWQ6IEJvb2xlYW4oYXdhaXQgdmVyaWZ5U2Vzc2lvbih0b2tlbikpLFxuICAgICAgICBlbWFpbDogKGF3YWl0IHZlcmlmeVNlc3Npb24odG9rZW4pKSA/PyB1bmRlZmluZWQsXG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICB9KSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVSZXF1ZXN0KFxuICAgIGVtYWlsOiBzdHJpbmcsXG4gICAgaXA6IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IG9rOiB0cnVlOyByZXRyeUFmdGVyPzogbnVtYmVyIH0+IHtcbiAgICBjb25zdCBhZGRyZXNzID0gZW1haWwudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gICAgY29uc3QgYnlJcCA9IHRoaXMucmVxdWVzdExpbWl0ZXIuaGl0KGBpcDoke2lwfWApO1xuICAgIGNvbnN0IGJ5RW1haWwgPSB0aGlzLnJlcXVlc3RMaW1pdGVyLmhpdChgZW1haWw6JHthZGRyZXNzfWApO1xuICAgIGlmICghYnlJcC5hbGxvd2VkIHx8ICFieUVtYWlsLmFsbG93ZWQpIHtcbiAgICAgIHJldHVybiB7IG9rOiB0cnVlLCByZXRyeUFmdGVyOiBieUlwLnJldHJ5QWZ0ZXIgPz8gYnlFbWFpbC5yZXRyeUFmdGVyIH07XG4gICAgfVxuICAgIGlmIChsb29rc0xpa2VFbWFpbChhZGRyZXNzKSAmJiBtYXRjaGVzQWxsb3dsaXN0KGFkZHJlc3MsIHRoaXMucmVzb2x2ZWQuYWxsb3cpKSB7XG4gICAgICBjb25zdCBjb2RlID0gYXdhaXQgdGhpcy5jb2Rlcy5pc3N1ZShhZGRyZXNzKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuY29uZmlnLnNlbmRDb2RlPy4oYWRkcmVzcywgY29kZSwge1xuICAgICAgICAgIHN1YmplY3Q6IHRoaXMucmVzb2x2ZWQuc3ViamVjdCxcbiAgICAgICAgICBicmFuZE5hbWU6IHRoaXMucmVzb2x2ZWQuYnJhbmROYW1lLFxuICAgICAgICAgIG1lc3NhZ2U6IHRoaXMucmVzb2x2ZWQubWVzc2FnZSxcbiAgICAgICAgICBjb2RlVHRsU2Vjb25kczogdGhpcy5yZXNvbHZlZC5jb2RlVHRsU2Vjb25kcyxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byBzZW5kIE9UUCBlbWFpbFwiLCB7IGVycm9yIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4geyBvazogdHJ1ZSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVWZXJpZnkoXG4gICAgZW1haWw6IHN0cmluZyxcbiAgICBjb2RlOiBzdHJpbmcsXG4gICAgaXA6IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IG9rOiBib29sZWFuOyB0b2tlbj86IHN0cmluZzsgcmV0cnlBZnRlcj86IG51bWJlciB9PiB7XG4gICAgY29uc3QgYWRkcmVzcyA9IGVtYWlsLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IGJ5SXAgPSB0aGlzLnZlcmlmeUxpbWl0ZXIuaGl0KGBpcDoke2lwfWApO1xuICAgIGNvbnN0IGJ5RW1haWwgPSB0aGlzLnZlcmlmeUxpbWl0ZXIuaGl0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgaWYgKCFieUlwLmFsbG93ZWQgfHwgIWJ5RW1haWwuYWxsb3dlZCkge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCByZXRyeUFmdGVyOiBieUlwLnJldHJ5QWZ0ZXIgPz8gYnlFbWFpbC5yZXRyeUFmdGVyIH07XG4gICAgfVxuICAgIGlmICgoYXdhaXQgdGhpcy5jb2Rlcy52ZXJpZnkoYWRkcmVzcywgY29kZS50cmltKCkpKSAhPT0gXCJva1wiKSByZXR1cm4geyBvazogZmFsc2UgfTtcbiAgICB0aGlzLnJlcXVlc3RMaW1pdGVyLnJlc2V0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgdGhpcy52ZXJpZnlMaW1pdGVyLnJlc2V0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgcmV0dXJuIHsgb2s6IHRydWUsIHRva2VuOiBhd2FpdCBzaWduU2Vzc2lvbihhZGRyZXNzLCB0aGlzLnJlc29sdmVkLnNlc3Npb25UdGxTZWNvbmRzKSB9O1xuICB9XG59XG5cbi8qKiBGYWN0b3J5OiBgYXV0aEdhdGUoeyBhbGxvdywgc3ViamVjdCwgLi4uIH0pYCBmb3IgYW4gQXBwS2l0IGBwbHVnaW5zYCBhcnJheS4gKi9cbmV4cG9ydCBjb25zdCBhdXRoR2F0ZSA9IHRvUGx1Z2luKEF1dGhHYXRlUGx1Z2luKTtcbiJdfQ==
|
|
209
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUE4QyxNQUFNLG9CQUFvQixDQUFDO0FBQ2xHLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHekUsT0FBTyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsY0FBYyxFQUNkLFlBQVksRUFDWixtQkFBbUIsRUFDbkIsWUFBWSxFQUNaLFdBQVcsRUFDWCxpQkFBaUIsRUFDakIsZUFBZSxFQUNmLFdBQVcsR0FDWixNQUFNLFVBQVUsQ0FBQztBQUNsQixPQUFPLEVBQUUsU0FBUyxFQUFvQixNQUFNLFdBQVcsQ0FBQztBQUN4RCxPQUFPLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxRQUFRLElBQUksZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVyRixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0FBY3pDLFNBQVMsaUJBQWlCLENBQUMsT0FBeUI7SUFDbEQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQ29CLENBQUM7SUFDckUsTUFBTSxXQUFXLEdBQUcsTUFBTSxFQUFFLGlCQUFpQixDQUFDO0lBQzlDLE9BQU8sV0FBVztRQUNoQixPQUFPLFdBQVcsQ0FBQyxHQUFHLEtBQUssVUFBVTtRQUNyQyxPQUFPLFdBQVcsQ0FBQyxJQUFJLEtBQUssVUFBVTtRQUN0QyxPQUFPLFdBQVcsQ0FBQyxHQUFHLEtBQUssVUFBVTtRQUNyQyxDQUFDLENBQUUsV0FBcUM7UUFDeEMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNoQixDQUFDO0FBRUQsTUFBTSxVQUFVLGtCQUFrQixDQUFDLE9BQXlCLEVBQUUsT0FBb0I7SUFDaEYsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDL0MsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUNoQixTQUFTLENBQ1AsT0FBTyxFQUNQLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQzdELENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQ2xELENBQUM7UUFDRixPQUFPO0lBQ1QsQ0FBQztJQUNELFNBQVMsQ0FDUCxPQUFPLEVBQ1AsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxFQUNsRSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUN4RCxDQUFDO0FBQ0osQ0FBQztBQXFIRCxNQUFNLFFBQVEsR0FBRztJQUNmLE9BQU8sRUFBRSx3QkFBd0I7SUFDakMsOEVBQThFO0lBQzlFLCtFQUErRTtJQUMvRSxrRUFBa0U7SUFDbEUsZ0ZBQWdGO0lBQ2hGLDhDQUE4QztJQUM5QyxTQUFTLEVBQUUsS0FBSyxDQUFDLG1CQUFtQixDQUFDLElBQUk7SUFDekMsT0FBTyxFQUFFLDRCQUE0QjtJQUNyQyx1RUFBdUU7SUFDdkUsaUJBQWlCLEVBQUUsZUFBZTtJQUNsQyxjQUFjLEVBQUUsR0FBRztJQUNuQixXQUFXLEVBQUUsQ0FBQztDQUNmLENBQUM7QUFFRixrRkFBa0Y7QUFDbEYsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE1BQXNCO0lBQzFELE9BQU87UUFDTCx5RUFBeUU7UUFDekUsNkVBQTZFO1FBQzdFLDZFQUE2RTtRQUM3RSwrQkFBK0I7UUFDL0IsS0FBSyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQ3BGLE9BQU8sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLElBQUksUUFBUSxDQUFDLE9BQU87UUFDcEUsU0FBUyxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsSUFBSSxRQUFRLENBQUMsU0FBUztRQUM3RSxPQUFPLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxPQUFPO1FBQ3BFLGlCQUFpQixFQUFFLEdBQUcsQ0FBQyxXQUFXLENBQ2hDLE1BQU0sQ0FBQyxpQkFBaUIsRUFDeEIsZUFBZSxFQUNmLFFBQVEsQ0FBQyxpQkFBaUIsQ0FDM0I7UUFDRCxjQUFjLEVBQUUsR0FBRyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsY0FBYyxFQUFFLFlBQVksRUFBRSxRQUFRLENBQUMsY0FBYyxDQUFDO1FBQzdGLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVyxJQUFJLFFBQVEsQ0FBQyxXQUFXO1FBQ3ZELGVBQWUsRUFBRSxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDO1FBQzNELFlBQVksRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLEVBQUUsaUJBQWlCLENBQUMsSUFBSSxTQUFTO1FBQzdFLGNBQWMsRUFBRTtZQUNkLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDO1lBQzFDLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7U0FDbkQ7UUFDRCxRQUFRLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxJQUFJLEtBQUs7S0FDOUQsQ0FBQztBQUNKLENBQUM7QUFvQkQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGNBQWUsU0FBUSxNQUFzQjtJQUN4RCxNQUFNLENBQUMsUUFBUSxHQUFHO1FBQ2hCLElBQUksRUFBRSxVQUFVO1FBQ2hCLFdBQVcsRUFBRSxXQUFXO1FBQ3hCLFdBQVcsRUFBRSwwREFBMEQ7UUFDdkUsU0FBUyxFQUFFLE1BQU07UUFDakIsU0FBUyxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFO0tBQ0wsQ0FBQztJQUUvQixRQUFRLENBQTBCO0lBQ2xDLEtBQUssQ0FBYTtJQUMxQiw2RUFBNkU7SUFDN0UsMERBQTBEO0lBQ3pDLGNBQWMsR0FBRyxJQUFJLFdBQVcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUNwRCxhQUFhLEdBQUcsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFFNUQsS0FBSyxDQUFDLEtBQUs7UUFDbEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3BGLDZFQUE2RTtRQUM3RSx5RUFBeUU7UUFDekUsa0VBQWtFO1FBQ2xFLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRXJFLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLDZEQUE2RCxDQUFDLENBQUM7UUFDN0UsQ0FBQzthQUFNLENBQUM7WUFDTiwyRUFBMkU7WUFDM0UseUVBQXlFO1lBQ3pFLDJFQUEyRTtZQUMzRSxrQ0FBa0M7WUFDbEMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxJQUFJLEVBQUU7Z0JBQ3JELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDdkIsc0VBQXNFO2dCQUN0RSxnREFBZ0Q7Z0JBQ2hELE1BQU0sb0JBQW9CLEVBQUUsQ0FBQztZQUMvQixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNuQixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsTUFBTTtZQUNwQyxpQkFBaUIsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLGlCQUFpQjtZQUNsRCxZQUFZLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLElBQUksSUFBSTtZQUNoRCxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRO1lBQ2hDLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUUsUUFBUSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztTQUM1RixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssZUFBZTtRQUNyQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQzdCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNiLE1BQU0sQ0FBQyxJQUFJLENBQUMsMERBQTBELENBQUMsQ0FBQztZQUN4RSxPQUFPO1FBQ1QsQ0FBQztRQUNELGtCQUFrQixDQUFDLE9BQU8sRUFBRTtZQUMxQixJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNwQixZQUFZLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZO1lBQ3hDLGNBQWMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWM7U0FDN0MsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELHFGQUFxRjtJQUNyRixJQUFZLFFBQVE7UUFDbEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxlQUFlLENBQUM7SUFDakQsQ0FBQztJQUVRLE9BQU87UUFDZCxPQUFPO1lBQ0wsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUI7WUFDbEQsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQ3JELE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQy9ELE9BQU8sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQztZQUN4QyxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDeEIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxNQUFNLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDbEQsS0FBSyxFQUFFLENBQUMsTUFBTSxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxTQUFTO2dCQUNoRCxPQUFPLEVBQUUsSUFBSTthQUNkLENBQUM7U0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxhQUFhLENBQ3pCLEtBQWEsRUFDYixFQUFVO1FBRVYsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxTQUFTLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDNUQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdEMsT0FBTyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLElBQUksT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3pFLENBQUM7UUFDRCxJQUFJLGNBQWMsQ0FBQyxPQUFPLENBQUMsSUFBSSxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzlFLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDO2dCQUNILE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFO29CQUNqQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPO29CQUM5QixTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTO29CQUNsQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPO29CQUM5QixjQUFjLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjO2lCQUM3QyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsSUFBSSxDQUFDLDBCQUEwQixFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNyRCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVPLEtBQUssQ0FBQyxZQUFZLENBQ3hCLEtBQWEsRUFDYixJQUFZLEVBQ1osRUFBVTtRQUVWLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUMzQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDaEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3RDLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVSxJQUFJLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMxRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssSUFBSTtZQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDbkYsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLFNBQVMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUM3QyxPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO0lBQzFGLENBQUM7O0FBR0gsa0ZBQWtGO0FBQ2xGLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGBhdXRoR2F0ZSgpYCAtIHRoZSBBcHBLaXQgcGx1Z2luIGJlaGluZCB0aGUgdHVubmVsJ3MgZW1haWwtT1RQIGdhdGUuXG4gKlxuICogSXQgaGFzIE5PIHJvdXRlcyBvZiBpdHMgb3duOiB0aGUgdHVubmVsIFBST1hZIChub3QgYW4gSFRUUCBzZXJ2ZXIpIGNhbGxzIHRoZVxuICogaGFuZGxlcnMgdGhpcyBwbHVnaW4gZXhwb3NlcyB2aWEge0BsaW5rIEF1dGhHYXRlUGx1Z2luLmV4cG9ydHN9LiBUaGUgcGx1Z2luXG4gKiBvd25zIHRoZSBhbGxvdy1saXN0LCB0aGUgcGVyLWVtYWlsL3Blci1JUCByYXRlIGxpbWl0ZXJzLCB0aGUgQ2FjaGVNYW5hZ2VyLWJhY2tlZFxuICogb25lLXRpbWUtY29kZSBzdG9yZSwgYW5kIHRoZSBzZXNzaW9uIEpXVC4gYGNyZWF0ZUFwcGAgKHdpdGggbm8gYHNlcnZlcigpYCkgaXNcbiAqIHVzZWQgb25seSB0byBhdXRvLWluaXQgYENhY2hlTWFuYWdlcmAgKyBwcmltZSB0aGUgc2libGluZyBgZW1haWxgIHRyYW5zcG9ydDtcbiAqIHRoaXMgcGx1Z2luIGlzIHdoZXJlIHRoZSBnYXRlIGxvZ2ljIGxpdmVzLlxuICpcbiAqIE9wdGlvbnMgY29tZSBmcm9tIENMSSBmbGFncyBPUiBlbnYsIHdpdGggc2Vuc2libGUgZGVmYXVsdHMgLSBzZWVcbiAqIHtAbGluayByZXNvbHZlQXV0aEdhdGVDb25maWd9LiBUaGUgb25lIHJ1bnRpbWUgZGVwZW5kZW5jeSB0aGUgcGx1Z2luIGNhbid0XG4gKiByZXNvbHZlIGl0c2VsZiBpcyBIT1cgdG8gZW1haWwgdGhlIGNvZGUsIHNvIGl0IHRha2VzIGEgYHNlbmRDb2RlYCBjYWxsYmFjayB0aGVcbiAqIGFwcCB3aXJlcyB0byB0aGUgZW1haWwgcGx1Z2luLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBQbHVnaW4sIHRvUGx1Z2luLCB0eXBlIEJhc2VQbHVnaW5Db25maWcsIHR5cGUgUGx1Z2luTWFuaWZlc3QgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBicmFuZCwgZW52LCBsb2csIG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgQXV0aFN0YXR1cyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1lbWFpbFwiO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0SGFuZGxlciB9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgeyBsb29rc0xpa2VFbWFpbCwgbWF0Y2hlc0FsbG93bGlzdCB9IGZyb20gXCIuL2FsbG93bGlzdC50c1wiO1xuaW1wb3J0IHtcbiAgQUxMT1dfRU5WLFxuICBCUkFORF9OQU1FX0VOVixcbiAgQ09ERV9UVExfRU5WLFxuICBGT1JXQVJEX0hFQURFUlNfRU5WLFxuICBJTlNFQ1VSRV9FTlYsXG4gIE1FU1NBR0VfRU5WLFxuICBQVUJMSUNfRE9NQUlOX0VOVixcbiAgU0VTU0lPTl9UVExfRU5WLFxuICBTVUJKRUNUX0VOVixcbn0gZnJvbSBcIi4vZW52LnRzXCI7XG5pbXBvcnQgeyBtb3VudEdhdGUsIHR5cGUgR2F0ZU9wdGlvbnMgfSBmcm9tIFwiLi9nYXRlLnRzXCI7XG5pbXBvcnQgeyBDb2RlU3RvcmUsIHNpZ25TZXNzaW9uLCB2ZXJpZnlTZXNzaW9uIH0gZnJvbSBcIi4vb3RwLnRzXCI7XG5pbXBvcnQgeyBSYXRlTGltaXRlciB9IGZyb20gXCIuL3JhdGUtbGltaXQudHNcIjtcbmltcG9ydCB7IGVuc3VyZUVtYWlsQXZhaWxhYmxlLCBzZW5kQ29kZSBhcyBkZWZhdWx0U2VuZENvZGUgfSBmcm9tIFwiLi9zZW5kLWNvZGUudHNcIjtcbmltcG9ydCB7IEtFWV9UVExfU0VDT05EUywgcmVzb2x2ZVNlc3Npb25DdXRvZmYsIHNpZ25pbmdLZXkgfSBmcm9tIFwiLi9zaWduaW5nLWtleS50c1wiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwidHVubmVsOmF1dGhcIik7XG5cbmludGVyZmFjZSBHYXRlU2VydmVyQXBwbGljYXRpb24ge1xuICBnZXQocGF0aDogc3RyaW5nLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlcik6IHVua25vd247XG4gIHBvc3QocGF0aDogc3RyaW5nLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlcik6IHVua25vd247XG4gIHVzZShwYXRoOiBzdHJpbmcsIGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyKTogdW5rbm93bjtcbn1cblxuaW50ZXJmYWNlIEdhdGVNb3VudENvbnRleHQge1xuICBhZGRSb3V0ZShtZXRob2Q6IHN0cmluZywgcGF0aDogc3RyaW5nLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlcik6IHZvaWQ7XG4gIGFkZE1pZGRsZXdhcmUocGF0aDogc3RyaW5nLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlcik6IHZvaWQ7XG4gIGdldFBsdWdpbnMoKTogUmVhZG9ubHlNYXA8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuZnVuY3Rpb24gc2VydmVyQXBwbGljYXRpb24oY29udGV4dDogR2F0ZU1vdW50Q29udGV4dCk6IEdhdGVTZXJ2ZXJBcHBsaWNhdGlvbiB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHNlcnZlciA9IGNvbnRleHQuZ2V0UGx1Z2lucygpLmdldChcInNlcnZlclwiKSBhc1xuICAgIHsgc2VydmVyQXBwbGljYXRpb24/OiBQYXJ0aWFsPEdhdGVTZXJ2ZXJBcHBsaWNhdGlvbj4gfSB8IHVuZGVmaW5lZDtcbiAgY29uc3QgYXBwbGljYXRpb24gPSBzZXJ2ZXI/LnNlcnZlckFwcGxpY2F0aW9uO1xuICByZXR1cm4gYXBwbGljYXRpb24gJiZcbiAgICB0eXBlb2YgYXBwbGljYXRpb24uZ2V0ID09PSBcImZ1bmN0aW9uXCIgJiZcbiAgICB0eXBlb2YgYXBwbGljYXRpb24ucG9zdCA9PT0gXCJmdW5jdGlvblwiICYmXG4gICAgdHlwZW9mIGFwcGxpY2F0aW9uLnVzZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgPyAoYXBwbGljYXRpb24gYXMgR2F0ZVNlcnZlckFwcGxpY2F0aW9uKVxuICAgIDogdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbW91bnRHYXRlT25Db250ZXh0KGNvbnRleHQ6IEdhdGVNb3VudENvbnRleHQsIG9wdGlvbnM6IEdhdGVPcHRpb25zKTogdm9pZCB7XG4gIGNvbnN0IGFwcGxpY2F0aW9uID0gc2VydmVyQXBwbGljYXRpb24oY29udGV4dCk7XG4gIGlmIChhcHBsaWNhdGlvbikge1xuICAgIG1vdW50R2F0ZShcbiAgICAgIG9wdGlvbnMsXG4gICAgICAobWV0aG9kLCBwYXRoLCBoYW5kbGVyKSA9PiBhcHBsaWNhdGlvblttZXRob2RdKHBhdGgsIGhhbmRsZXIpLFxuICAgICAgKHBhdGgsIGhhbmRsZXIpID0+IGFwcGxpY2F0aW9uLnVzZShwYXRoLCBoYW5kbGVyKSxcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuICBtb3VudEdhdGUoXG4gICAgb3B0aW9ucyxcbiAgICAobWV0aG9kLCBwYXRoLCBoYW5kbGVyKSA9PiBjb250ZXh0LmFkZFJvdXRlKG1ldGhvZCwgcGF0aCwgaGFuZGxlciksXG4gICAgKHBhdGgsIGhhbmRsZXIpID0+IGNvbnRleHQuYWRkTWlkZGxld2FyZShwYXRoLCBoYW5kbGVyKSxcbiAgKTtcbn1cblxuLyoqIE9wdGlvbnMgZm9yIHRoZSB7QGxpbmsgYXV0aEdhdGV9IHBsdWdpbiAoYWxsIHJlc29sdmFibGUgZnJvbSBlbnYgLSBzZWUgYmVsb3cpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoR2F0ZUNvbmZpZyBleHRlbmRzIEJhc2VQbHVnaW5Db25maWcge1xuICAvKiogQWxsb3ctbGlzdCBwYXR0ZXJucyAoZG9tYWluIC8gZ2xvYiAvIGAvcmVnZXgvYCkuIEVtcHR5ID0gYWxsb3cgbm9ib2R5LiBFbnYgVFVOTkVMX0FVVEhfQUxMT1cuICovXG4gIGFsbG93Pzogc3RyaW5nIHwgc3RyaW5nW107XG4gIC8qKlxuICAgKiBTdWJqZWN0IGxpbmUgZm9yIHRoZSBjb2RlIGVtYWlsLiBFbnYgVFVOTkVMX0FVVEhfU1VCSkVDVC5cbiAgICpcbiAgICogRGVmYXVsdHMgdG8gXCJZb3VyIHZlcmlmaWNhdGlvbiBjb2RlXCIuIFRoZSB3b3JkaW5nIG9mIHRoZSBzdWJqZWN0IGFuZFxuICAgKiB7QGxpbmsgbWVzc2FnZX0gaXMgZGVsaWJlcmF0ZWx5IHRoZSBjb252ZW50aW9uYWwgcGhyYXNpbmcgcmF0aGVyIHRoYW5cbiAgICogYW55dGhpbmcgYnJhbmRlZDogaU9TLCBHbWFpbCwgT3V0bG9vaywgYW5kIEFuZHJvaWQgYWxsIGRldGVjdCBhIG9uZS10aW1lXG4gICAqIGNvZGUgZnJvbSB0aGlzIHNoYXBlIGFuZCBvZmZlciB0byBhdXRvZmlsbCBpdCwgYW5kIGEgbm92ZWwgcGhyYXNpbmcgaXMgd2hhdFxuICAgKiBicmVha3MgdGhhdCBkZXRlY3Rpb24uXG4gICAqXG4gICAqIFRoaXMgaXMgdGhlIHN1YmplY3QgVEVNUExBVEUsIG5vdCB0aGUgbGl0ZXJhbCBsaW5lIHNlbnQ6IHRoZSBjb2RlIGlzIHNwbGljZWRcbiAgICogaW50byBpdCAoYFwiMTIzNDU2IGlzIHlvdXIgdmVyaWZpY2F0aW9uIGNvZGVcImApIGJlY2F1c2UgYSBwdXNoIG5vdGlmaWNhdGlvblxuICAgKiBzaG93cyBvbmx5IHRoZSBzdWJqZWN0IGFuZCBwcmVoZWFkZXIsIGFuZCB0aGF0IG5vdGlmaWNhdGlvbiBpcyB3aGF0IG1vYmlsZVxuICAgKiBhdXRvZmlsbCByZWFkcy4gU2VlIGBjb2RlRW1haWxTdWJqZWN0YCBpbiBgLi9hcHAudHNgLlxuICAgKi9cbiAgc3ViamVjdD86IHN0cmluZztcbiAgLyoqXG4gICAqIERpc3BsYXkgbmFtZSB1c2VkIGluIHRoZSBjb2RlIGVtYWlsIGNvcHkuIEVudiBUVU5ORUxfQVVUSF9CUkFORF9OQU1FLlxuICAgKlxuICAgKiBEZWZhdWx0cyB0byB0aGUgYnJhbmQgY29udGV4dCdzIGBuYW1lYCAtIHRoZSBhcHAncyBvd24gYGJyYW5kaW5nL2JyYW5kLnlhbWxgXG4gICAqIHdoZW4gaXQgaGFzIG9uZSwgZWxzZSB0aGUgZGJ4LXRvb2xzIGRlZmF1bHQuIFNldCB0aGlzIG9ubHkgdG8gb3ZlcnJpZGUgdGhlXG4gICAqIGJyYW5kIGZvciB0aGlzIGdhdGUuXG4gICAqL1xuICBicmFuZE5hbWU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBMaW5lIHNob3duIGltbWVkaWF0ZWx5IGFib3ZlIHRoZSBjb2RlIGluIHRoZSBlbWFpbC4gRW52IFRVTk5FTF9BVVRIX01FU1NBR0UuXG4gICAqXG4gICAqIEtlZXAgdGhlIGNvZGUgb24gaXRzIE9XTiBsaW5lIGRpcmVjdGx5IGFmdGVyIHRoaXMgdGV4dCAtIHRoYXQgYWRqYWNlbmN5IGlzXG4gICAqIHdoYXQgdGhlIHBsYXRmb3JtIGNvZGUtZGV0ZWN0aW9uIGhldXJpc3RpY3Mga2V5IG9uLlxuICAgKi9cbiAgbWVzc2FnZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFNlc3Npb24gbGlmZXRpbWUgKHNlY29uZHMpLiBFbnYgVFVOTkVMX0FVVEhfU0VTU0lPTl9UVEwuIERlZmF1bHQgMjU5MjAwMCAoMzBkKS5cbiAgICpcbiAgICogTWF0Y2hlZCB0byB0aGUgY2FjaGUtYmFja2VkIHNpZ25pbmcga2V5J3Mgb3duIDMwLWRheSBUVEwgKHNlZVxuICAgKiBgLi9zaWduaW5nLWtleS50c2ApOiB0aGUgY29va2llIGFuZCB0aGUga2V5IHRoYXQgdmFsaWRhdGVzIGl0IHNob3VsZCBleHBpcmVcbiAgICogdG9nZXRoZXIsIG9yIG9uZSBzaWxlbnRseSBvdXRsaXZlcyB0aGUgb3RoZXIuXG4gICAqL1xuICBzZXNzaW9uVHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqIE9uZS10aW1lLWNvZGUgbGlmZXRpbWUgKHNlY29uZHMpLiBFbnYgVFVOTkVMX0FVVEhfQ09ERV9UVEwuIERlZmF1bHQgNjAwICgxMG0pLiAqL1xuICBjb2RlVHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqIE1heCB2ZXJpZnkgYXR0ZW1wdHMgcGVyIGlzc3VlZCBjb2RlLiBEZWZhdWx0IDUuICovXG4gIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICAvKipcbiAgICogRm9yY2UtY2xlYXIgY3V0b2ZmOiBldmVyeSBzZXNzaW9uIGlzc3VlZCBCRUZPUkUgaXQgc3RvcHMgdmVyaWZ5aW5nLCBzbyBtb3ZpbmdcbiAgICogaXQgZm9yd2FyZCBzaWducyBldmVyeW9uZSBvdXQuIEVudiBUVU5ORUxfQVVUSF9TRVNTSU9OX0NVVE9GRi5cbiAgICpcbiAgICogQW55dGhpbmcgYG9iamVjdC50b0RhdGVgIGFjY2VwdHM6IGEgYERhdGVgLCBgMjAyNi0wOC0wMmAsIGFuIElTTyBpbnN0YW50LFxuICAgKiBlcG9jaCBzZWNvbmRzL21pbGxpcywgb3IgYSByZWxhdGl2ZSBkdXJhdGlvbiAoYC0zMGRgLCBgNyBkYXlzIGFnb2ApLiBVbnNldFxuICAgKiBtZWFucyBubyBjdXRvZmYuXG4gICAqL1xuICBzZXNzaW9uQ3V0b2ZmPzogc3RyaW5nIHwgbnVtYmVyIHwgRGF0ZTtcbiAgLyoqXG4gICAqIERlbGl2ZXIgYSBjb2RlIHRvIGFuIGFkZHJlc3MuIERlZmF1bHRzIHRvIHNlbmRpbmcgdGhyb3VnaCB0aGUgaG9zdCBhcHAnc1xuICAgKiBzaGFyZWQgYEBkYngtdG9vbHMvZW1haWxgIHRyYW5zcG9ydCAoc2VlIGAuL3NlbmQtY29kZWApOyBvdmVycmlkZSB0byB3aXJlIGFcbiAgICogZGlmZmVyZW50IGRlbGl2ZXJ5IHBhdGguXG4gICAqL1xuICBzZW5kQ29kZT86IChlbWFpbDogc3RyaW5nLCBjb2RlOiBzdHJpbmcsIG9wdHM6IFNlbmRDb2RlT3B0aW9ucykgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqXG4gICAqIFRoZSBwdWJsaWMgYDxzdWJkb21haW4+LjxzZXJ2ZXI+YCB0aGF0IGlkZW50aWZpZXMgcG9ydHIgdHJhZmZpYyBieSBpdHMgYEhvc3RgXG4gICAqIGhlYWRlci4gT25seSByZXF1ZXN0cyB3aG9zZSBgSG9zdGAgbWF0Y2hlcyB0aGlzIGFyZSBnYXRlZDsgZXZlcnl0aGluZyBlbHNlXG4gICAqICh0aGUgcGxhdGZvcm0gZnJvbnQgZG9vciwgb3RoZXIgbG9jYWwgY2FsbGVycykgcGFzc2VzIHRocm91Z2guIEVudlxuICAgKiBgVFVOTkVMX1BVQkxJQ19ET01BSU5gLiBXaGVuIGFic2VudCwgdGhlIGdhdGUgaXMgaW5lcnQgKG5vdGhpbmcgaXMgdHVubmVsXG4gICAqIHRyYWZmaWMpLlxuICAgKi9cbiAgcHVibGljRG9tYWluPzogc3RyaW5nO1xuICAvKipcbiAgICogRXh0cmEgYHgtYCByZXF1ZXN0IGhlYWRlcnMgdHVubmVsIHRyYWZmaWMgbWF5IGZvcndhcmQgKGxpdGVyYWwgLyBnbG9iIC9cbiAgICogYC9yZWdleC9gKSwgdW5pb25lZCB3aXRoIHRoZSBidWlsdC1pbiBhbGxvdy1saXN0LiBFbnYgYFRVTk5FTF9GT1JXQVJEX0hFQURFUlNgLlxuICAgKi9cbiAgZm9yd2FyZEhlYWRlcnM/OiBzdHJpbmcgfCBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIFJ1biBPUEVOIHdpdGggbm8gZ2F0ZSAoZW52IGBUVU5ORUxfSU5TRUNVUkU9dHJ1ZWApLiBUaGUgbG9naW4gcm91dGVzIGFuZCBnYXRlXG4gICAqIG1pZGRsZXdhcmUgYXJlIG5vdCBtb3VudGVkLCBhbmQgdGhlIFNNVFAgZmFpbC1mYXN0IGlzIHNraXBwZWQuIFVzZSBvbmx5IHdoZW5cbiAgICogdGhlIHR1bm5lbCBpcyBkZWxpYmVyYXRlbHkgcHVibGljLlxuICAgKi9cbiAgaW5zZWN1cmU/OiBib29sZWFuO1xufVxuXG4vKiogQnJhbmRpbmcvbWVzc2FnaW5nIHBhc3NlZCB0byB7QGxpbmsgQXV0aEdhdGVDb25maWcuc2VuZENvZGV9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZW5kQ29kZU9wdGlvbnMge1xuICBzdWJqZWN0OiBzdHJpbmc7XG4gIGJyYW5kTmFtZTogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBMaWZldGltZSBvZiB0aGUgY29kZSBiZWluZyBzZW50LCBpbiBzZWNvbmRzIC0gdGhlIFJFU09MVkVEXG4gICAqIHtAbGluayBBdXRoR2F0ZUNvbmZpZy5jb2RlVHRsU2Vjb25kc30sIHNvIHRoZSBlbWFpbCBjYW4gc3RhdGUgdGhlIHJlYWxcbiAgICogZXhwaXJ5IChcIlRoaXMgY29kZSBleHBpcmVzIGluIDEwIG1pbnV0ZXNcIikgaW5zdGVhZCBvZiBhIHZhZ3VlIFwic2hvcnRseVwiXG4gICAqIHRoYXQgZHJpZnRzIGZyb20gdGhlIGNvbmZpZ3VyZWQgVFRMLlxuICAgKi9cbiAgY29kZVR0bFNlY29uZHM6IG51bWJlcjtcbn1cblxuLyoqIFJlc29sdmVkIGdhdGUgY29uZmlnIHdpdGggZW52IGZhbGxiYWNrcyArIGRlZmF1bHRzIGFwcGxpZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkQXV0aEdhdGVDb25maWcge1xuICBhbGxvdzogc3RyaW5nW107XG4gIHN1YmplY3Q6IHN0cmluZztcbiAgYnJhbmROYW1lOiBzdHJpbmc7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgc2Vzc2lvblR0bFNlY29uZHM6IG51bWJlcjtcbiAgY29kZVR0bFNlY29uZHM6IG51bWJlcjtcbiAgbWF4QXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIEZvcmNlLWNsZWFyIGN1dG9mZiBpbiBlcG9jaCBtczsgYDBgIHdoZW4gdW5zZXQuICovXG4gIHNlc3Npb25DdXRvZmZNczogbnVtYmVyO1xuICAvKiogUHVibGljIGRvbWFpbiB0aGF0IGlkZW50aWZpZXMgcG9ydHIgdHJhZmZpYyBieSBgSG9zdGA7IGB1bmRlZmluZWRgID0gaW5lcnQuICovXG4gIHB1YmxpY0RvbWFpbj86IHN0cmluZztcbiAgLyoqIEV4dHJhIGB4LWAgaGVhZGVycyB0dW5uZWwgdHJhZmZpYyBtYXkgZm9yd2FyZCAodW5pb25lZCB3aXRoIHRoZSBkZWZhdWx0cykuICovXG4gIGZvcndhcmRIZWFkZXJzOiBzdHJpbmdbXTtcbiAgLyoqIFJ1biBPUEVOIHdpdGggbm8gZ2F0ZS4gKi9cbiAgaW5zZWN1cmU6IGJvb2xlYW47XG59XG5cbmNvbnN0IERFRkFVTFRTID0ge1xuICBzdWJqZWN0OiBcIllvdXIgdmVyaWZpY2F0aW9uIGNvZGVcIixcbiAgLy8gVGhlIHJlcG8td2lkZSBicmFuZCBjb250ZXh0J3MgZGlzcGxheSBuYW1lLCBOT1QgYSBoYXJkY29kZWQgcHJvZHVjdCBzdHJpbmc6XG4gIC8vIHRoaXMgbmFtZSBpcyB3aGF0IHRoZSByZWNpcGllbnQgcmVhZHMgaW4gdGhlIGNvZGUgZW1haWwsIHNvIGl0IGhhcyB0byBiZSB0aGVcbiAgLy8gc2FtZSBpZGVudGl0eSB0aGUgcmVzdCBvZiB0aGUgYXBwIHByZXNlbnRzLiBBIGhvc3Qgd2l0aCBpdHMgb3duXG4gIC8vIGBicmFuZGluZy9icmFuZC55YW1sYCBvdmVycmlkZXMgaXQgYnkgcGFzc2luZyBgYnJhbmROYW1lYDsgdGhlIHNoYXJlZCBkZWZhdWx0XG4gIC8vIGlzIHRoZSBmYWxsYmFjayB3aGVuIG5vdGhpbmcgaXMgY29uZmlndXJlZC5cbiAgYnJhbmROYW1lOiBicmFuZC5kZWZhdWx0QnJhbmRDb250ZXh0Lm5hbWUsXG4gIG1lc3NhZ2U6IFwiWW91ciB2ZXJpZmljYXRpb24gY29kZSBpczpcIixcbiAgLy8gMzAgZGF5cywgdGhlIHNhbWUgd2luZG93IHRoZSBjYWNoZS1iYWNrZWQgc2lnbmluZyBrZXkgaXMgc3RvcmVkIGZvci5cbiAgc2Vzc2lvblR0bFNlY29uZHM6IEtFWV9UVExfU0VDT05EUyxcbiAgY29kZVR0bFNlY29uZHM6IDYwMCxcbiAgbWF4QXR0ZW1wdHM6IDUsXG59O1xuXG4vKiogTWVyZ2Uge0BsaW5rIEF1dGhHYXRlQ29uZmlnfSBvdmVyIGVudiBvdmVyIGRlZmF1bHRzIGludG8gYSByZXNvbHZlZCBjb25maWcuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUF1dGhHYXRlQ29uZmlnKGNvbmZpZzogQXV0aEdhdGVDb25maWcpOiBSZXNvbHZlZEF1dGhHYXRlQ29uZmlnIHtcbiAgcmV0dXJuIHtcbiAgICAvLyBCb3RoIHNvdXJjZXMgYXJlIHVuaW9uZWQgcmF0aGVyIHRoYW4gb25lIG92ZXJyaWRpbmc6IGEgZGVwbG95bWVudC13aWRlXG4gICAgLy8gVFVOTkVMX0FVVEhfQUxMT1cgYW5kIGEgcGVyLWludm9jYXRpb24gYC0tYWxsb3dgIHNob3VsZCBib3RoIGdyYW50IGFjY2Vzcy5cbiAgICAvLyBIZW5jZSBgcGFyc2VMaXN0YCBvbiBlYWNoIHJhdGhlciB0aGFuIGBlbnYubGlzdGAsIHdoaWNoIHN0b3BzIGF0IHRoZSBmaXJzdFxuICAgIC8vIHNvdXJjZSB0aGF0IHlpZWxkcyBhbnl0aGluZy5cbiAgICBhbGxvdzogWy4uLnN0cmluZy5wYXJzZUxpc3QoY29uZmlnLmFsbG93KSwgLi4uc3RyaW5nLnBhcnNlTGlzdChlbnYudGV4dChBTExPV19FTlYpKV0sXG4gICAgc3ViamVjdDogZW52LnN0cmluZyhjb25maWcuc3ViamVjdCwgU1VCSkVDVF9FTlYpID8/IERFRkFVTFRTLnN1YmplY3QsXG4gICAgYnJhbmROYW1lOiBlbnYuc3RyaW5nKGNvbmZpZy5icmFuZE5hbWUsIEJSQU5EX05BTUVfRU5WKSA/PyBERUZBVUxUUy5icmFuZE5hbWUsXG4gICAgbWVzc2FnZTogZW52LnN0cmluZyhjb25maWcubWVzc2FnZSwgTUVTU0FHRV9FTlYpID8/IERFRkFVTFRTLm1lc3NhZ2UsXG4gICAgc2Vzc2lvblR0bFNlY29uZHM6IGVudi5wb3NpdGl2ZUludChcbiAgICAgIGNvbmZpZy5zZXNzaW9uVHRsU2Vjb25kcyxcbiAgICAgIFNFU1NJT05fVFRMX0VOVixcbiAgICAgIERFRkFVTFRTLnNlc3Npb25UdGxTZWNvbmRzLFxuICAgICksXG4gICAgY29kZVR0bFNlY29uZHM6IGVudi5wb3NpdGl2ZUludChjb25maWcuY29kZVR0bFNlY29uZHMsIENPREVfVFRMX0VOViwgREVGQVVMVFMuY29kZVR0bFNlY29uZHMpLFxuICAgIG1heEF0dGVtcHRzOiBjb25maWcubWF4QXR0ZW1wdHMgPz8gREVGQVVMVFMubWF4QXR0ZW1wdHMsXG4gICAgc2Vzc2lvbkN1dG9mZk1zOiByZXNvbHZlU2Vzc2lvbkN1dG9mZihjb25maWcuc2Vzc2lvbkN1dG9mZiksXG4gICAgcHVibGljRG9tYWluOiBlbnYuc3RyaW5nKGNvbmZpZy5wdWJsaWNEb21haW4sIFBVQkxJQ19ET01BSU5fRU5WKSA/PyB1bmRlZmluZWQsXG4gICAgZm9yd2FyZEhlYWRlcnM6IFtcbiAgICAgIC4uLnN0cmluZy5wYXJzZUxpc3QoY29uZmlnLmZvcndhcmRIZWFkZXJzKSxcbiAgICAgIC4uLnN0cmluZy5wYXJzZUxpc3QoZW52LnRleHQoRk9SV0FSRF9IRUFERVJTX0VOVikpLFxuICAgIF0sXG4gICAgaW5zZWN1cmU6IGVudi5ib29sZWFuKGNvbmZpZy5pbnNlY3VyZSwgSU5TRUNVUkVfRU5WKSA/PyBmYWxzZSxcbiAgfTtcbn1cblxuLyoqIFRoZSBoYW5kbGVycyB0aGUgZ2F0ZSBtaWRkbGV3YXJlIGNhbGxzIGluLXByb2Nlc3MgKHJldHVybmVkIGJ5IHtAbGluayBBdXRoR2F0ZVBsdWdpbi5leHBvcnRzfSkuICovXG5leHBvcnQgaW50ZXJmYWNlIEF1dGhHYXRlQXBpIHtcbiAgLyoqIEhhbmRsZSBhIGNvZGUgcmVxdWVzdC4gQWx3YXlzIHJlc29sdmVzIGB7IG9rOiB0cnVlIH1gIChhbnRpLWVudW1lcmF0aW9uKS4gKi9cbiAgcmVxdWVzdChlbWFpbDogc3RyaW5nLCBpcDogc3RyaW5nKTogUHJvbWlzZTx7IG9rOiB0cnVlOyByZXRyeUFmdGVyPzogbnVtYmVyIH0+O1xuICAvKiogSGFuZGxlIGEgY29kZSB2ZXJpZmljYXRpb24uIE9uIHN1Y2Nlc3MgcmV0dXJucyB0aGUgc2Vzc2lvbiB0b2tlbiB0byBjb29raWUuICovXG4gIHZlcmlmeShcbiAgICBlbWFpbDogc3RyaW5nLFxuICAgIGNvZGU6IHN0cmluZyxcbiAgICBpcDogc3RyaW5nLFxuICApOiBQcm9taXNlPHsgb2s6IGJvb2xlYW47IHRva2VuPzogc3RyaW5nOyByZXRyeUFmdGVyPzogbnVtYmVyIH0+O1xuICAvKiogUmVzb2x2ZSB0aGUgYXV0aGVudGljYXRlZCBlbWFpbCBmb3IgYSBzZXNzaW9uIHRva2VuLCBvciB1bmRlZmluZWQuICovXG4gIHNlc3Npb24odG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPjtcbiAgLyoqIFNlc3Npb24gVFRMIGluIHNlY29uZHMgKGZvciB0aGUgY29va2llIE1heC1BZ2UpLiAqL1xuICByZWFkb25seSBzZXNzaW9uVHRsU2Vjb25kczogbnVtYmVyO1xuICAvKiogVGhlIGdhdGUgc3RhdHVzIHBheWxvYWQgKGBlbmFibGVkYCBpcyBhbHdheXMgdHJ1ZSB3aGVuIHRoaXMgcGx1Z2luIHJ1bnMpLiAqL1xuICBzdGF0dXModG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCk6IFByb21pc2U8QXV0aFN0YXR1cz47XG59XG5cbi8qKlxuICogQXBwS2l0IHBsdWdpbiBvd25pbmcgdGhlIGVtYWlsLU9UUCBnYXRlLiBPbiBgc2V0dXAoKWAgaXQgcmVnaXN0ZXJzIHRoZSBsb2dpblxuICogcm91dGVzIChgL2FwaS9lbWFpbC9hdXRoLypgKSBhbmQgYSBnYXRpbmcgbWlkZGxld2FyZSBvbiB0aGUgYXBwJ3MgT1dOIEV4cHJlc3NcbiAqIHNlcnZlciB2aWEgYHRoaXMuY29udGV4dGAsIHNvIGEgcHVibGljIHBvcnRyIGNhbGxlciBtdXN0IHByb3ZlIGFuIGVtYWlsIGJlZm9yZVxuICogcmVhY2hpbmcgdGhlIGFwcCdzIGAvYXBpLypgIC0gc2VlIGAuL2dhdGVgLiBGcm9udC1kb29yIChwbGF0Zm9ybSkgdHJhZmZpYyBhbmRcbiAqIG90aGVyIGxvY2FsIGNhbGxlcnMgcGFzcyB0aHJvdWdoIHVudG91Y2hlZCAodGhlIGdhdGUga2V5cyBvbiB0aGUgYEhvc3RgIGhlYWRlcikuXG4gKi9cbmV4cG9ydCBjbGFzcyBBdXRoR2F0ZVBsdWdpbiBleHRlbmRzIFBsdWdpbjxBdXRoR2F0ZUNvbmZpZz4ge1xuICBzdGF0aWMgbWFuaWZlc3QgPSB7XG4gICAgbmFtZTogXCJhdXRoR2F0ZVwiLFxuICAgIGRpc3BsYXlOYW1lOiBcIkF1dGggR2F0ZVwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIkVtYWlsIG9uZS10aW1lLXBhc3N3b3JkIGFjY2VzcyBnYXRlIGZvciBhIHB1YmxpYyB0dW5uZWwuXCIsXG4gICAgc3RhYmlsaXR5OiBcImJldGFcIixcbiAgICByZXNvdXJjZXM6IHsgcmVxdWlyZWQ6IFtdLCBvcHRpb25hbDogW10gfSxcbiAgfSBzYXRpc2ZpZXMgUGx1Z2luTWFuaWZlc3Q8XCJhdXRoR2F0ZVwiPjtcblxuICBwcml2YXRlIHJlc29sdmVkITogUmVzb2x2ZWRBdXRoR2F0ZUNvbmZpZztcbiAgcHJpdmF0ZSBjb2RlcyE6IENvZGVTdG9yZTtcbiAgLy8gUmVxdWVzdGluZyBhIGNvZGUgaXMgZW1haWwtc3BhbS1wcm9uZTsgdmVyaWZ5aW5nIGlzIGEgYnJ1dGUtZm9yY2Ugc3VyZmFjZS5cbiAgLy8gUGVyLWVtYWlsIEFORCBwZXItSVAgc28gbmVpdGhlciBheGlzIGFsb25lIGlzIGEgYnlwYXNzLlxuICBwcml2YXRlIHJlYWRvbmx5IHJlcXVlc3RMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKDUsIDE1ICogNjAgKiAxMDAwKTtcbiAgcHJpdmF0ZSByZWFkb25seSB2ZXJpZnlMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKDEwLCAxNSAqIDYwICogMTAwMCk7XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc2V0dXAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5yZXNvbHZlZCA9IHJlc29sdmVBdXRoR2F0ZUNvbmZpZyh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5jb2RlcyA9IG5ldyBDb2RlU3RvcmUodGhpcy5yZXNvbHZlZC5jb2RlVHRsU2Vjb25kcywgdGhpcy5yZXNvbHZlZC5tYXhBdHRlbXB0cyk7XG4gICAgLy8gUmVzb2x2ZSB0aGUgc2lnbmluZyBrZXkgSEVSRSByYXRoZXIgdGhhbiBsYXppbHkgb24gdGhlIGZpcnN0IHNpZ24taW4sIHNvIGFcbiAgICAvLyBjYWNoZSB0aGF0IGNhbm5vdCBob2xkIGl0IChhbmQgdGhlIHJlc3VsdGluZyBcInNlc3Npb25zIHdvbid0IHN1cnZpdmUgYVxuICAgIC8vIHJlc3RhcnRcIiB3YXJuaW5nKSBzaG93cyB1cCBpbiB0aGUgc3RhcnR1cCBsb2csIG5vdCBob3VycyBsYXRlci5cbiAgICBjb25zdCB7IGN1dG9mZk1zIH0gPSBhd2FpdCBzaWduaW5nS2V5KHRoaXMucmVzb2x2ZWQuc2Vzc2lvbkN1dG9mZk1zKTtcblxuICAgIGlmICh0aGlzLnJlc29sdmVkLmluc2VjdXJlKSB7XG4gICAgICBsb2dnZXIud2FybihcImluc2VjdXJlIG1vZGUgLSB0aGUgdHVubmVsIHJ1bnMgT1BFTiB3aXRoIG5vIGVtYWlsLU9UUCBnYXRlXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBgc2VydmVyKClgIGlzIGRlZmVycmVkLCBzbyBpdCBkb2VzIG5vdCBleGlzdCBkdXJpbmcgdGhpcyBwbHVnaW4ncyBzZXR1cC5cbiAgICAgIC8vIEF0IGBzZXR1cDpjb21wbGV0ZWAgdGhlIEV4cHJlc3MgYXBwIGV4aXN0cyBidXQgaGFzIG5vdCBpbmplY3RlZCBwbHVnaW5cbiAgICAgIC8vIHJvdXRlcyBvciBzdGF0aWMgaGFuZGxpbmcgeWV0LCB3aGljaCBpcyB0aGUgb25lIHBvaW50IHRoZSBnYXRlIGNhbiBtb3VudFxuICAgICAgLy8gYWhlYWQgb2YgZXZlcnkgcHJvdGVjdGVkIHJvdXRlLlxuICAgICAgdGhpcy5jb250ZXh0Py5vbkxpZmVjeWNsZShcInNldHVwOmNvbXBsZXRlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgdGhpcy5tb3VudEdhdGVSb3V0ZXMoKTtcbiAgICAgICAgLy8gRmFpbCBmYXN0IG9uY2UgdGhlIHNpYmxpbmcgZW1haWwgcGx1Z2luIGhhcyBwcmltZWQgaXRzIHRyYW5zcG9ydDogYVxuICAgICAgICAvLyBnYXRlIHRoYXQgY2Fubm90IGVtYWlsIGEgY29kZSBsZXRzIG5vYm9keSBpbi5cbiAgICAgICAgYXdhaXQgZW5zdXJlRW1haWxBdmFpbGFibGUoKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGxvZ2dlci5pbmZvKFwicmVhZHlcIiwge1xuICAgICAgcGF0dGVybnM6IHRoaXMucmVzb2x2ZWQuYWxsb3cubGVuZ3RoLFxuICAgICAgc2Vzc2lvblR0bFNlY29uZHM6IHRoaXMucmVzb2x2ZWQuc2Vzc2lvblR0bFNlY29uZHMsXG4gICAgICBwdWJsaWNEb21haW46IHRoaXMucmVzb2x2ZWQucHVibGljRG9tYWluID8/IG51bGwsXG4gICAgICBpbnNlY3VyZTogdGhpcy5yZXNvbHZlZC5pbnNlY3VyZSxcbiAgICAgIC4uLm9iamVjdC5vcHRpb25hbChcInNlc3Npb25DdXRvZmZcIiwgY3V0b2ZmTXMgPiAwID8gbmV3IERhdGUoY3V0b2ZmTXMpLnRvSVNPU3RyaW5nKCkgOiBudWxsKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciB0aGUgbG9naW4gcm91dGVzIChgL2FwaS9lbWFpbC9hdXRoLypgKSBhbmQgdGhlIGdhdGluZyBtaWRkbGV3YXJlIG9uXG4gICAqIHRoZSBhcHAncyBPV04gRXhwcmVzcyBzZXJ2ZXIuIEF0IGBzZXR1cDpjb21wbGV0ZWAsIHRoZSBkZWZlcnJlZCBzZXJ2ZXIgcGx1Z2luXG4gICAqIGhhcyBjb25zdHJ1Y3RlZCBpdHMgRXhwcmVzcyBhcHAgYnV0IGhhcyBub3QgaW5qZWN0ZWQgcGx1Z2luIHJvdXRlcyBvciBzdGF0aWNcbiAgICogaGFuZGxpbmcsIHNvIGRpcmVjdCByZWdpc3RyYXRpb24gcHV0cyB0aGUgZ2F0ZSBmaXJzdC4gVGhlIGNvbnRleHQncyBidWZmZXJlZFxuICAgKiByb3V0ZSBBUEkgcmVtYWlucyBhIGZhbGxiYWNrIGZvciBjb21wYXRpYmxlIG5vbi1zdGFuZGFyZCBzZXJ2ZXIgcGx1Z2lucy5cbiAgICovXG4gIHByaXZhdGUgbW91bnRHYXRlUm91dGVzKCk6IHZvaWQge1xuICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgaWYgKCFjb250ZXh0KSB7XG4gICAgICBsb2dnZXIud2FybihcIm5vIHBsdWdpbiBjb250ZXh0IC0gdGhlIE9UUCBnYXRlIGNhbm5vdCBtb3VudCBpdHMgcm91dGVzXCIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBtb3VudEdhdGVPbkNvbnRleHQoY29udGV4dCwge1xuICAgICAgZ2F0ZTogdGhpcy5leHBvcnRzKCksXG4gICAgICBwdWJsaWNEb21haW46IHRoaXMucmVzb2x2ZWQucHVibGljRG9tYWluLFxuICAgICAgZm9yd2FyZEhlYWRlcnM6IHRoaXMucmVzb2x2ZWQuZm9yd2FyZEhlYWRlcnMsXG4gICAgfSk7XG4gIH1cblxuICAvKiogVGhlIGNvZGUgc2VuZGVyOiB0aGUgY29uZmlndXJlZCBgc2VuZENvZGVgLCBlbHNlIHRoZSBzaGFyZWQtdHJhbnNwb3J0IGRlZmF1bHQuICovXG4gIHByaXZhdGUgZ2V0IHNlbmRDb2RlKCk6IE5vbk51bGxhYmxlPEF1dGhHYXRlQ29uZmlnW1wic2VuZENvZGVcIl0+IHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuc2VuZENvZGUgPz8gZGVmYXVsdFNlbmRDb2RlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZXhwb3J0cygpOiBBdXRoR2F0ZUFwaSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlc3Npb25UdGxTZWNvbmRzOiB0aGlzLnJlc29sdmVkLnNlc3Npb25UdGxTZWNvbmRzLFxuICAgICAgcmVxdWVzdDogKGVtYWlsLCBpcCkgPT4gdGhpcy5oYW5kbGVSZXF1ZXN0KGVtYWlsLCBpcCksXG4gICAgICB2ZXJpZnk6IChlbWFpbCwgY29kZSwgaXApID0+IHRoaXMuaGFuZGxlVmVyaWZ5KGVtYWlsLCBjb2RlLCBpcCksXG4gICAgICBzZXNzaW9uOiAodG9rZW4pID0+IHZlcmlmeVNlc3Npb24odG9rZW4pLFxuICAgICAgc3RhdHVzOiBhc3luYyAodG9rZW4pID0+ICh7XG4gICAgICAgIGF1dGhlbnRpY2F0ZWQ6IEJvb2xlYW4oYXdhaXQgdmVyaWZ5U2Vzc2lvbih0b2tlbikpLFxuICAgICAgICBlbWFpbDogKGF3YWl0IHZlcmlmeVNlc3Npb24odG9rZW4pKSA/PyB1bmRlZmluZWQsXG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICB9KSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVSZXF1ZXN0KFxuICAgIGVtYWlsOiBzdHJpbmcsXG4gICAgaXA6IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IG9rOiB0cnVlOyByZXRyeUFmdGVyPzogbnVtYmVyIH0+IHtcbiAgICBjb25zdCBhZGRyZXNzID0gZW1haWwudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gICAgY29uc3QgYnlJcCA9IHRoaXMucmVxdWVzdExpbWl0ZXIuaGl0KGBpcDoke2lwfWApO1xuICAgIGNvbnN0IGJ5RW1haWwgPSB0aGlzLnJlcXVlc3RMaW1pdGVyLmhpdChgZW1haWw6JHthZGRyZXNzfWApO1xuICAgIGlmICghYnlJcC5hbGxvd2VkIHx8ICFieUVtYWlsLmFsbG93ZWQpIHtcbiAgICAgIHJldHVybiB7IG9rOiB0cnVlLCByZXRyeUFmdGVyOiBieUlwLnJldHJ5QWZ0ZXIgPz8gYnlFbWFpbC5yZXRyeUFmdGVyIH07XG4gICAgfVxuICAgIGlmIChsb29rc0xpa2VFbWFpbChhZGRyZXNzKSAmJiBtYXRjaGVzQWxsb3dsaXN0KGFkZHJlc3MsIHRoaXMucmVzb2x2ZWQuYWxsb3cpKSB7XG4gICAgICBjb25zdCBjb2RlID0gYXdhaXQgdGhpcy5jb2Rlcy5pc3N1ZShhZGRyZXNzKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZENvZGUoYWRkcmVzcywgY29kZSwge1xuICAgICAgICAgIHN1YmplY3Q6IHRoaXMucmVzb2x2ZWQuc3ViamVjdCxcbiAgICAgICAgICBicmFuZE5hbWU6IHRoaXMucmVzb2x2ZWQuYnJhbmROYW1lLFxuICAgICAgICAgIG1lc3NhZ2U6IHRoaXMucmVzb2x2ZWQubWVzc2FnZSxcbiAgICAgICAgICBjb2RlVHRsU2Vjb25kczogdGhpcy5yZXNvbHZlZC5jb2RlVHRsU2Vjb25kcyxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byBzZW5kIE9UUCBlbWFpbFwiLCB7IGVycm9yIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4geyBvazogdHJ1ZSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVWZXJpZnkoXG4gICAgZW1haWw6IHN0cmluZyxcbiAgICBjb2RlOiBzdHJpbmcsXG4gICAgaXA6IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IG9rOiBib29sZWFuOyB0b2tlbj86IHN0cmluZzsgcmV0cnlBZnRlcj86IG51bWJlciB9PiB7XG4gICAgY29uc3QgYWRkcmVzcyA9IGVtYWlsLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IGJ5SXAgPSB0aGlzLnZlcmlmeUxpbWl0ZXIuaGl0KGBpcDoke2lwfWApO1xuICAgIGNvbnN0IGJ5RW1haWwgPSB0aGlzLnZlcmlmeUxpbWl0ZXIuaGl0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgaWYgKCFieUlwLmFsbG93ZWQgfHwgIWJ5RW1haWwuYWxsb3dlZCkge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCByZXRyeUFmdGVyOiBieUlwLnJldHJ5QWZ0ZXIgPz8gYnlFbWFpbC5yZXRyeUFmdGVyIH07XG4gICAgfVxuICAgIGlmICgoYXdhaXQgdGhpcy5jb2Rlcy52ZXJpZnkoYWRkcmVzcywgY29kZS50cmltKCkpKSAhPT0gXCJva1wiKSByZXR1cm4geyBvazogZmFsc2UgfTtcbiAgICB0aGlzLnJlcXVlc3RMaW1pdGVyLnJlc2V0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgdGhpcy52ZXJpZnlMaW1pdGVyLnJlc2V0KGBlbWFpbDoke2FkZHJlc3N9YCk7XG4gICAgcmV0dXJuIHsgb2s6IHRydWUsIHRva2VuOiBhd2FpdCBzaWduU2Vzc2lvbihhZGRyZXNzLCB0aGlzLnJlc29sdmVkLnNlc3Npb25UdGxTZWNvbmRzKSB9O1xuICB9XG59XG5cbi8qKiBGYWN0b3J5OiBgYXV0aEdhdGUoeyBhbGxvdywgc3ViamVjdCwgLi4uIH0pYCBmb3IgYW4gQXBwS2l0IGBwbHVnaW5zYCBhcnJheS4gKi9cbmV4cG9ydCBjb25zdCBhdXRoR2F0ZSA9IHRvUGx1Z2luKEF1dGhHYXRlUGx1Z2luKTtcbiJdfQ==
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default `sendCode` for the {@link AuthGatePlugin}: deliver the OTP through
|
|
3
|
+
* the host app's ALREADY-PRIMED `@dbx-tools/email` transport, as the system
|
|
4
|
+
* sender (a verification code is machine-generated and unanswerable, so it must
|
|
5
|
+
* not arrive from a person's address inviting a reply).
|
|
6
|
+
*
|
|
7
|
+
* `@dbx-tools/email` is an OPTIONAL dependency of the tunnel - a tunnel used
|
|
8
|
+
* without the gate needs no mail. So it is imported LAZILY here; a missing module
|
|
9
|
+
* surfaces only when a gate actually tries to send a code, and
|
|
10
|
+
* {@link ensureEmailAvailable} turns that into a clear fail-fast at boot.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { AuthGateConfig } from "./plugin.ts";
|
|
15
|
+
/**
|
|
16
|
+
* Fail fast when the gate cannot deliver codes: the optional email module must be
|
|
17
|
+
* importable AND configured for SMTP (real delivery). `mode: "file"` (outbox) or a
|
|
18
|
+
* throwing runtime means no code reaches a real inbox, so a gate on that config
|
|
19
|
+
* would silently admit nobody. Called from the plugin's `setup:complete` unless
|
|
20
|
+
* insecure.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureEmailAvailable(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* The default code sender: render the OTP email (code in the subject + preheader
|
|
25
|
+
* for mobile autofill; see `codeEmailSubject`) and send it through the shared
|
|
26
|
+
* transport as the system sender.
|
|
27
|
+
*/
|
|
28
|
+
export declare const sendCode: NonNullable<AuthGateConfig["sendCode"]>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default `sendCode` for the {@link AuthGatePlugin}: deliver the OTP through
|
|
3
|
+
* the host app's ALREADY-PRIMED `@dbx-tools/email` transport, as the system
|
|
4
|
+
* sender (a verification code is machine-generated and unanswerable, so it must
|
|
5
|
+
* not arrive from a person's address inviting a reply).
|
|
6
|
+
*
|
|
7
|
+
* `@dbx-tools/email` is an OPTIONAL dependency of the tunnel - a tunnel used
|
|
8
|
+
* without the gate needs no mail. So it is imported LAZILY here; a missing module
|
|
9
|
+
* surfaces only when a gate actually tries to send a code, and
|
|
10
|
+
* {@link ensureEmailAvailable} turns that into a clear fail-fast at boot.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { log } from "@dbx-tools/shared-core";
|
|
15
|
+
import { codeEmailHtmlBody, codeEmailPreview, codeEmailSubject, codeEmailTextBody, } from "./code-email.js";
|
|
16
|
+
const logger = log.logger("tunnel:send-code");
|
|
17
|
+
let cached;
|
|
18
|
+
/**
|
|
19
|
+
* Import `@dbx-tools/email` lazily. Throws a clear, actionable error when the
|
|
20
|
+
* optional dependency is absent - the caller (a gate that is NOT insecure) treats
|
|
21
|
+
* that as fatal, since a gate that cannot email a code lets nobody in.
|
|
22
|
+
*/
|
|
23
|
+
async function loadEmail() {
|
|
24
|
+
if (cached)
|
|
25
|
+
return cached;
|
|
26
|
+
try {
|
|
27
|
+
const mod = (await import("@dbx-tools/email"));
|
|
28
|
+
cached = mod;
|
|
29
|
+
return mod;
|
|
30
|
+
}
|
|
31
|
+
catch (cause) {
|
|
32
|
+
throw new Error("the OTP gate needs @dbx-tools/email to send codes, but it is not installed. " +
|
|
33
|
+
"Add @dbx-tools/email to the app, or run the tunnel with --insecure / TUNNEL_INSECURE=true.", { cause });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fail fast when the gate cannot deliver codes: the optional email module must be
|
|
38
|
+
* importable AND configured for SMTP (real delivery). `mode: "file"` (outbox) or a
|
|
39
|
+
* throwing runtime means no code reaches a real inbox, so a gate on that config
|
|
40
|
+
* would silently admit nobody. Called from the plugin's `setup:complete` unless
|
|
41
|
+
* insecure.
|
|
42
|
+
*/
|
|
43
|
+
export async function ensureEmailAvailable() {
|
|
44
|
+
const { transport } = await loadEmail();
|
|
45
|
+
if (transport.getEmailRuntime().config.mode !== "smtp") {
|
|
46
|
+
throw new Error("email is not configured for SMTP delivery - the OTP gate cannot send codes. " +
|
|
47
|
+
"Set SMTP_HOST/SMTP_USER/SMTP_PASSWORD, or pass --insecure / TUNNEL_INSECURE=true.");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The default code sender: render the OTP email (code in the subject + preheader
|
|
52
|
+
* for mobile autofill; see `codeEmailSubject`) and send it through the shared
|
|
53
|
+
* transport as the system sender.
|
|
54
|
+
*/
|
|
55
|
+
export const sendCode = async (to, code, opts) => {
|
|
56
|
+
const { sender, transport } = await loadEmail();
|
|
57
|
+
const from = sender.resolveSystemSenderAddress(transport.getEmailRuntime().config);
|
|
58
|
+
await sendEmailWith(transport, to, code, opts, from);
|
|
59
|
+
};
|
|
60
|
+
function sendEmailWith(transport, to, code, opts, from) {
|
|
61
|
+
logger.debug("sending code email", { to });
|
|
62
|
+
return transport.sendEmail({
|
|
63
|
+
to: [to],
|
|
64
|
+
subject: codeEmailSubject(code, opts.subject),
|
|
65
|
+
body: codeEmailHtmlBody(code, opts),
|
|
66
|
+
}, from, undefined, { text: codeEmailTextBody(code, opts), preview: codeEmailPreview(code, opts) });
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1jb2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlbmQtY29kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0MsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsZ0JBQWdCLEVBQ2hCLGlCQUFpQixHQUNsQixNQUFNLGlCQUFpQixDQUFDO0FBR3pCLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztBQWdCOUMsSUFBSSxNQUErQixDQUFDO0FBRXBDOzs7O0dBSUc7QUFDSCxLQUFLLFVBQVUsU0FBUztJQUN0QixJQUFJLE1BQU07UUFBRSxPQUFPLE1BQU0sQ0FBQztJQUMxQixJQUFJLENBQUM7UUFDSCxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQTJCLENBQUM7UUFDekUsTUFBTSxHQUFHLEdBQUcsQ0FBQztRQUNiLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixNQUFNLElBQUksS0FBSyxDQUNiLDhFQUE4RTtZQUM1RSw0RkFBNEYsRUFDOUYsRUFBRSxLQUFLLEVBQUUsQ0FDVixDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQjtJQUN4QyxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxTQUFTLEVBQUUsQ0FBQztJQUN4QyxJQUFJLFNBQVMsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQ2IsOEVBQThFO1lBQzVFLG1GQUFtRixDQUN0RixDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUE0QyxLQUFLLEVBQ3BFLEVBQVUsRUFDVixJQUFZLEVBQ1osSUFBcUIsRUFDTixFQUFFO0lBQ2pCLE1BQU0sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxTQUFTLEVBQUUsQ0FBQztJQUNoRCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsMEJBQTBCLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25GLE1BQU0sYUFBYSxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztBQUN2RCxDQUFDLENBQUM7QUFFRixTQUFTLGFBQWEsQ0FDcEIsU0FBbUMsRUFDbkMsRUFBVSxFQUNWLElBQVksRUFDWixJQUFxQixFQUNyQixJQUFZO0lBRVosTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDM0MsT0FBTyxTQUFTLENBQUMsU0FBUyxDQUN4QjtRQUNFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUNSLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUM3QyxJQUFJLEVBQUUsaUJBQWlCLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQztLQUNwQyxFQUNELElBQUksRUFDSixTQUFTLEVBQ1QsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FDL0UsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoZSBkZWZhdWx0IGBzZW5kQ29kZWAgZm9yIHRoZSB7QGxpbmsgQXV0aEdhdGVQbHVnaW59OiBkZWxpdmVyIHRoZSBPVFAgdGhyb3VnaFxuICogdGhlIGhvc3QgYXBwJ3MgQUxSRUFEWS1QUklNRUQgYEBkYngtdG9vbHMvZW1haWxgIHRyYW5zcG9ydCwgYXMgdGhlIHN5c3RlbVxuICogc2VuZGVyIChhIHZlcmlmaWNhdGlvbiBjb2RlIGlzIG1hY2hpbmUtZ2VuZXJhdGVkIGFuZCB1bmFuc3dlcmFibGUsIHNvIGl0IG11c3RcbiAqIG5vdCBhcnJpdmUgZnJvbSBhIHBlcnNvbidzIGFkZHJlc3MgaW52aXRpbmcgYSByZXBseSkuXG4gKlxuICogYEBkYngtdG9vbHMvZW1haWxgIGlzIGFuIE9QVElPTkFMIGRlcGVuZGVuY3kgb2YgdGhlIHR1bm5lbCAtIGEgdHVubmVsIHVzZWRcbiAqIHdpdGhvdXQgdGhlIGdhdGUgbmVlZHMgbm8gbWFpbC4gU28gaXQgaXMgaW1wb3J0ZWQgTEFaSUxZIGhlcmU7IGEgbWlzc2luZyBtb2R1bGVcbiAqIHN1cmZhY2VzIG9ubHkgd2hlbiBhIGdhdGUgYWN0dWFsbHkgdHJpZXMgdG8gc2VuZCBhIGNvZGUsIGFuZFxuICoge0BsaW5rIGVuc3VyZUVtYWlsQXZhaWxhYmxlfSB0dXJucyB0aGF0IGludG8gYSBjbGVhciBmYWlsLWZhc3QgYXQgYm9vdC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgbG9nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7XG4gIGNvZGVFbWFpbEh0bWxCb2R5LFxuICBjb2RlRW1haWxQcmV2aWV3LFxuICBjb2RlRW1haWxTdWJqZWN0LFxuICBjb2RlRW1haWxUZXh0Qm9keSxcbn0gZnJvbSBcIi4vY29kZS1lbWFpbC50c1wiO1xuaW1wb3J0IHR5cGUgeyBBdXRoR2F0ZUNvbmZpZywgU2VuZENvZGVPcHRpb25zIH0gZnJvbSBcIi4vcGx1Z2luLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0dW5uZWw6c2VuZC1jb2RlXCIpO1xuXG4vKiogVGhlIHNsaWNlIG9mIGBAZGJ4LXRvb2xzL2VtYWlsYCB0aGUgZ2F0ZSB1c2VzLCByZXNvbHZlZCBsYXppbHkuICovXG5pbnRlcmZhY2UgRW1haWxNb2R1bGUge1xuICBzZW5kZXI6IHsgcmVzb2x2ZVN5c3RlbVNlbmRlckFkZHJlc3M6IChjb25maWc6IHVua25vd24pID0+IHN0cmluZyB9O1xuICB0cmFuc3BvcnQ6IHtcbiAgICBnZXRFbWFpbFJ1bnRpbWU6ICgpID0+IHsgY29uZmlnOiB7IG1vZGU6IHN0cmluZyB9IH07XG4gICAgc2VuZEVtYWlsOiAoXG4gICAgICBtZXNzYWdlOiB7IHRvOiBzdHJpbmdbXTsgc3ViamVjdDogc3RyaW5nOyBib2R5OiBzdHJpbmcgfSxcbiAgICAgIGZyb206IHN0cmluZyxcbiAgICAgIG9uQmVoYWxmT2Y6IHVuZGVmaW5lZCxcbiAgICAgIGV4dHJhOiB7IHRleHQ6IHN0cmluZzsgcHJldmlldzogc3RyaW5nIH0sXG4gICAgKSA9PiBQcm9taXNlPHZvaWQ+O1xuICB9O1xufVxuXG5sZXQgY2FjaGVkOiBFbWFpbE1vZHVsZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBJbXBvcnQgYEBkYngtdG9vbHMvZW1haWxgIGxhemlseS4gVGhyb3dzIGEgY2xlYXIsIGFjdGlvbmFibGUgZXJyb3Igd2hlbiB0aGVcbiAqIG9wdGlvbmFsIGRlcGVuZGVuY3kgaXMgYWJzZW50IC0gdGhlIGNhbGxlciAoYSBnYXRlIHRoYXQgaXMgTk9UIGluc2VjdXJlKSB0cmVhdHNcbiAqIHRoYXQgYXMgZmF0YWwsIHNpbmNlIGEgZ2F0ZSB0aGF0IGNhbm5vdCBlbWFpbCBhIGNvZGUgbGV0cyBub2JvZHkgaW4uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGxvYWRFbWFpbCgpOiBQcm9taXNlPEVtYWlsTW9kdWxlPiB7XG4gIGlmIChjYWNoZWQpIHJldHVybiBjYWNoZWQ7XG4gIHRyeSB7XG4gICAgY29uc3QgbW9kID0gKGF3YWl0IGltcG9ydChcIkBkYngtdG9vbHMvZW1haWxcIikpIGFzIHVua25vd24gYXMgRW1haWxNb2R1bGU7XG4gICAgY2FjaGVkID0gbW9kO1xuICAgIHJldHVybiBtb2Q7XG4gIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgXCJ0aGUgT1RQIGdhdGUgbmVlZHMgQGRieC10b29scy9lbWFpbCB0byBzZW5kIGNvZGVzLCBidXQgaXQgaXMgbm90IGluc3RhbGxlZC4gXCIgK1xuICAgICAgICBcIkFkZCBAZGJ4LXRvb2xzL2VtYWlsIHRvIHRoZSBhcHAsIG9yIHJ1biB0aGUgdHVubmVsIHdpdGggLS1pbnNlY3VyZSAvIFRVTk5FTF9JTlNFQ1VSRT10cnVlLlwiLFxuICAgICAgeyBjYXVzZSB9LFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBGYWlsIGZhc3Qgd2hlbiB0aGUgZ2F0ZSBjYW5ub3QgZGVsaXZlciBjb2RlczogdGhlIG9wdGlvbmFsIGVtYWlsIG1vZHVsZSBtdXN0IGJlXG4gKiBpbXBvcnRhYmxlIEFORCBjb25maWd1cmVkIGZvciBTTVRQIChyZWFsIGRlbGl2ZXJ5KS4gYG1vZGU6IFwiZmlsZVwiYCAob3V0Ym94KSBvciBhXG4gKiB0aHJvd2luZyBydW50aW1lIG1lYW5zIG5vIGNvZGUgcmVhY2hlcyBhIHJlYWwgaW5ib3gsIHNvIGEgZ2F0ZSBvbiB0aGF0IGNvbmZpZ1xuICogd291bGQgc2lsZW50bHkgYWRtaXQgbm9ib2R5LiBDYWxsZWQgZnJvbSB0aGUgcGx1Z2luJ3MgYHNldHVwOmNvbXBsZXRlYCB1bmxlc3NcbiAqIGluc2VjdXJlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5zdXJlRW1haWxBdmFpbGFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHsgdHJhbnNwb3J0IH0gPSBhd2FpdCBsb2FkRW1haWwoKTtcbiAgaWYgKHRyYW5zcG9ydC5nZXRFbWFpbFJ1bnRpbWUoKS5jb25maWcubW9kZSAhPT0gXCJzbXRwXCIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBcImVtYWlsIGlzIG5vdCBjb25maWd1cmVkIGZvciBTTVRQIGRlbGl2ZXJ5IC0gdGhlIE9UUCBnYXRlIGNhbm5vdCBzZW5kIGNvZGVzLiBcIiArXG4gICAgICAgIFwiU2V0IFNNVFBfSE9TVC9TTVRQX1VTRVIvU01UUF9QQVNTV09SRCwgb3IgcGFzcyAtLWluc2VjdXJlIC8gVFVOTkVMX0lOU0VDVVJFPXRydWUuXCIsXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBkZWZhdWx0IGNvZGUgc2VuZGVyOiByZW5kZXIgdGhlIE9UUCBlbWFpbCAoY29kZSBpbiB0aGUgc3ViamVjdCArIHByZWhlYWRlclxuICogZm9yIG1vYmlsZSBhdXRvZmlsbDsgc2VlIGBjb2RlRW1haWxTdWJqZWN0YCkgYW5kIHNlbmQgaXQgdGhyb3VnaCB0aGUgc2hhcmVkXG4gKiB0cmFuc3BvcnQgYXMgdGhlIHN5c3RlbSBzZW5kZXIuXG4gKi9cbmV4cG9ydCBjb25zdCBzZW5kQ29kZTogTm9uTnVsbGFibGU8QXV0aEdhdGVDb25maWdbXCJzZW5kQ29kZVwiXT4gPSBhc3luYyAoXG4gIHRvOiBzdHJpbmcsXG4gIGNvZGU6IHN0cmluZyxcbiAgb3B0czogU2VuZENvZGVPcHRpb25zLFxuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IHsgc2VuZGVyLCB0cmFuc3BvcnQgfSA9IGF3YWl0IGxvYWRFbWFpbCgpO1xuICBjb25zdCBmcm9tID0gc2VuZGVyLnJlc29sdmVTeXN0ZW1TZW5kZXJBZGRyZXNzKHRyYW5zcG9ydC5nZXRFbWFpbFJ1bnRpbWUoKS5jb25maWcpO1xuICBhd2FpdCBzZW5kRW1haWxXaXRoKHRyYW5zcG9ydCwgdG8sIGNvZGUsIG9wdHMsIGZyb20pO1xufTtcblxuZnVuY3Rpb24gc2VuZEVtYWlsV2l0aChcbiAgdHJhbnNwb3J0OiBFbWFpbE1vZHVsZVtcInRyYW5zcG9ydFwiXSxcbiAgdG86IHN0cmluZyxcbiAgY29kZTogc3RyaW5nLFxuICBvcHRzOiBTZW5kQ29kZU9wdGlvbnMsXG4gIGZyb206IHN0cmluZyxcbik6IFByb21pc2U8dm9pZD4ge1xuICBsb2dnZXIuZGVidWcoXCJzZW5kaW5nIGNvZGUgZW1haWxcIiwgeyB0byB9KTtcbiAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kRW1haWwoXG4gICAge1xuICAgICAgdG86IFt0b10sXG4gICAgICBzdWJqZWN0OiBjb2RlRW1haWxTdWJqZWN0KGNvZGUsIG9wdHMuc3ViamVjdCksXG4gICAgICBib2R5OiBjb2RlRW1haWxIdG1sQm9keShjb2RlLCBvcHRzKSxcbiAgICB9LFxuICAgIGZyb20sXG4gICAgdW5kZWZpbmVkLFxuICAgIHsgdGV4dDogY29kZUVtYWlsVGV4dEJvZHkoY29kZSwgb3B0cyksIHByZXZpZXc6IGNvZGVFbWFpbFByZXZpZXcoY29kZSwgb3B0cykgfSxcbiAgKTtcbn1cbiJdfQ==
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/allowlist.ts","../src/
|
|
1
|
+
{"root":["../src/allowlist.ts","../src/code-email.ts","../src/env.ts","../src/gate.ts","../src/headers.ts","../src/interceptor.ts","../src/otp.ts","../src/plugin.ts","../src/portr.ts","../src/rate-limit.ts","../src/send-code.ts","../src/signing-key.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -18,18 +18,20 @@
|
|
|
18
18
|
"projen": "projen"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
+
"@dbx-tools/email": "0.6.61",
|
|
21
22
|
"@types/bun": "^1.3.14",
|
|
22
23
|
"@types/node": "^24.6.0",
|
|
23
24
|
"typescript": "^5.9.3"
|
|
24
25
|
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@dbx-tools/email": "0.6.61"
|
|
28
|
+
},
|
|
25
29
|
"dependencies": {
|
|
26
30
|
"@databricks/appkit": "^0.43.0",
|
|
27
|
-
"@dbx-tools/appkit": "0.6.
|
|
28
|
-
"@dbx-tools/core": "0.6.
|
|
29
|
-
"@dbx-tools/
|
|
30
|
-
"@dbx-tools/shared-
|
|
31
|
-
"@dbx-tools/shared-email": "0.6.60",
|
|
32
|
-
"http-proxy-3": "^1.23.3",
|
|
31
|
+
"@dbx-tools/appkit": "0.6.61",
|
|
32
|
+
"@dbx-tools/core": "0.6.61",
|
|
33
|
+
"@dbx-tools/shared-core": "0.6.61",
|
|
34
|
+
"@dbx-tools/shared-email": "0.6.61",
|
|
33
35
|
"jose": "^6.2.3"
|
|
34
36
|
},
|
|
35
37
|
"main": "./lib/index.js",
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
"./package.json": "./package.json"
|
|
47
49
|
}
|
|
48
50
|
},
|
|
49
|
-
"version": "0.6.
|
|
51
|
+
"version": "0.6.61",
|
|
50
52
|
"types": "./lib/index.d.ts",
|
|
51
53
|
"type": "module",
|
|
52
54
|
"exports": {
|
|
@@ -61,6 +63,11 @@
|
|
|
61
63
|
"src",
|
|
62
64
|
"lib"
|
|
63
65
|
],
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@dbx-tools/email": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
64
71
|
"dbxToolsConfig": {
|
|
65
72
|
"tags": [
|
|
66
73
|
"node"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure builders for the OTP code email's copy - subject, preheader, and the HTML
|
|
3
|
+
* and text bodies. No transport, no `@dbx-tools/email` import, so this module is
|
|
4
|
+
* safe to load whether or not the optional email dependency is present; the actual
|
|
5
|
+
* send lives in `./send-code`.
|
|
6
|
+
*
|
|
7
|
+
* The shapes here are load-bearing for mobile autofill: the code rides in the
|
|
8
|
+
* SUBJECT and the PREHEADER (the whole of a push notification), and the text part
|
|
9
|
+
* keeps the prompt and code on ONE line. See each function for why.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { string } from "@dbx-tools/shared-core";
|
|
15
|
+
import type { SendCodeOptions } from "./plugin.ts";
|
|
16
|
+
|
|
17
|
+
/** The parts of {@link SendCodeOptions} the code email's copy is built from. */
|
|
18
|
+
export type CodeCopy = Pick<SendCodeOptions, "message" | "codeTtlSeconds">;
|
|
19
|
+
|
|
20
|
+
/** The reassurance line closing both parts. */
|
|
21
|
+
const IGNORE_LINE = "If you did not request this code, you can ignore this email.";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A code TTL as the plain phrase the email states ("10 minutes", "45 seconds").
|
|
25
|
+
*
|
|
26
|
+
* Whole minutes read as minutes; anything else stays in seconds rather than
|
|
27
|
+
* rounding, so a 90-second TTL is not advertised as "1 minute" and a recipient is
|
|
28
|
+
* never told the code lives longer than it does.
|
|
29
|
+
*/
|
|
30
|
+
export function expiresIn(seconds: number): string {
|
|
31
|
+
return seconds >= 60 && seconds % 60 === 0
|
|
32
|
+
? string.pluralize(seconds / 60, "minute")
|
|
33
|
+
: string.pluralize(seconds, "second");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The HTML part's source: the full branded template, with the code as a large
|
|
38
|
+
* styled heading (`## ` is what makes it prominent in an inbox).
|
|
39
|
+
*/
|
|
40
|
+
export function codeEmailHtmlBody(code: string, opts: CodeCopy): string {
|
|
41
|
+
return [
|
|
42
|
+
opts.message,
|
|
43
|
+
"",
|
|
44
|
+
`## ${code}`,
|
|
45
|
+
"",
|
|
46
|
+
`This code expires in ${expiresIn(opts.codeTtlSeconds)}.`,
|
|
47
|
+
"",
|
|
48
|
+
IGNORE_LINE,
|
|
49
|
+
].join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The `text/plain` part, supplied EXPLICITLY rather than rendered from the tree
|
|
54
|
+
* above. Both parts say the same thing; only the line layout differs.
|
|
55
|
+
*
|
|
56
|
+
* The prompt and the code share ONE line ("Your verification code is: 123456").
|
|
57
|
+
* That single-line shape is what iOS, Gmail, Outlook, and Android code detection
|
|
58
|
+
* keys on most reliably - the heuristics look for a code in the same sentence as
|
|
59
|
+
* a recognized prompt, so splitting them across lines makes detection dependent
|
|
60
|
+
* on the client, and any blank line between them defeats it outright.
|
|
61
|
+
*
|
|
62
|
+
* The GENERATED text part cannot hold that shape at all: it is a rendering of the
|
|
63
|
+
* HTML, so it carries the brand header/footer and turns the code heading's CSS
|
|
64
|
+
* margin into blank lines, arriving as `prompt\n\n\ncode`.
|
|
65
|
+
*
|
|
66
|
+
* The code is visible text in BOTH parts, never an image, so a client scraping
|
|
67
|
+
* either one finds it. No trailer line follows the copy - Apple's domain-bound
|
|
68
|
+
* `@domain #code` footer is deliberately NOT emitted, since it constrains the
|
|
69
|
+
* code to one origin and is not what the broadly-compatible shape needs.
|
|
70
|
+
*/
|
|
71
|
+
export function codeEmailTextBody(code: string, opts: CodeCopy): string {
|
|
72
|
+
return [
|
|
73
|
+
`${opts.message} ${code}`,
|
|
74
|
+
`This code expires in ${expiresIn(opts.codeTtlSeconds)}.`,
|
|
75
|
+
"",
|
|
76
|
+
IGNORE_LINE,
|
|
77
|
+
].join("\n");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The SUBJECT line, with the code in it: `"123456 is your verification code"`.
|
|
82
|
+
*
|
|
83
|
+
* The code has to be here, not only in the body, because of what mobile autofill
|
|
84
|
+
* actually reads. iOS offers a code from an incoming NOTIFICATION - natively for
|
|
85
|
+
* Messages and Mail, and since iOS 26 for any app's notification text, which is
|
|
86
|
+
* what finally made Gmail work - and a notification contains the sender, the
|
|
87
|
+
* subject, and a short snippet. Nothing else. A code that lives in the body is
|
|
88
|
+
* invisible to it, however cleanly the body is formatted, which is why a perfectly
|
|
89
|
+
* shaped `text/plain` part still produced no autofill prompt in Gmail.
|
|
90
|
+
*
|
|
91
|
+
* `<code> is your <thing>` rather than `<thing>: <code>` because the leading code
|
|
92
|
+
* survives TRUNCATION: a notification and an inbox list both cut the subject, and
|
|
93
|
+
* the platform heuristics want the code in the same sentence as a recognized
|
|
94
|
+
* prompt ("code", "verification"). Putting it first keeps both intact no matter
|
|
95
|
+
* where the cut lands.
|
|
96
|
+
*
|
|
97
|
+
* `subject` is the configured line ("Your verification code"), lower-cased at its
|
|
98
|
+
* first word so the sentence reads naturally, and left ALONE when it does not look
|
|
99
|
+
* like the conventional phrasing - an operator who set a deliberate subject gets
|
|
100
|
+
* theirs with the code prefixed, not a mangled hybrid.
|
|
101
|
+
*/
|
|
102
|
+
export function codeEmailSubject(code: string, subject: string): string {
|
|
103
|
+
const trimmed = subject.trim();
|
|
104
|
+
const conventional = /^your\s+/i.exec(trimmed);
|
|
105
|
+
const rest = conventional ? trimmed.slice(conventional[0].length) : trimmed;
|
|
106
|
+
return conventional ? `${code} is your ${rest}` : `${code} - ${trimmed}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The PREHEADER: the snippet beside the subject in an inbox list, and the body of
|
|
111
|
+
* the push notification. Carries the code for the same reason the subject does -
|
|
112
|
+
* it is the other half of what a notification shows - and repeats the prompt
|
|
113
|
+
* wording so a heuristic scanning the snippet alone finds a code next to a phrase
|
|
114
|
+
* it recognizes.
|
|
115
|
+
*/
|
|
116
|
+
export function codeEmailPreview(code: string, opts: CodeCopy): string {
|
|
117
|
+
return `${opts.message} ${code}`;
|
|
118
|
+
}
|