@dbx-tools/email 0.6.41 → 0.6.43
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/index.ts +10 -1
- package/lib/index.d.ts +10 -1
- package/lib/index.js +8 -1
- package/lib/src/auth/allowlist.d.ts +27 -0
- package/lib/src/auth/allowlist.js +82 -0
- package/lib/src/auth/gate.d.ts +83 -0
- package/lib/src/auth/gate.js +134 -0
- package/lib/src/auth/otp.d.ts +49 -0
- package/lib/src/auth/otp.js +135 -0
- package/lib/src/auth/rate-limit.d.ts +35 -0
- package/lib/src/auth/rate-limit.js +53 -0
- package/lib/src/config.d.ts +40 -0
- package/lib/src/config.js +54 -2
- package/lib/src/plugin.d.ts +23 -0
- package/lib/src/plugin.js +143 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/src/auth/allowlist.ts +88 -0
- package/src/auth/gate.ts +163 -0
- package/src/auth/otp.ts +151 -0
- package/src/auth/rate-limit.ts +59 -0
- package/src/config.ts +90 -1
- package/src/plugin.ts +163 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-time-code store + session JWT for the email-OTP gate.
|
|
3
|
+
*
|
|
4
|
+
* Two pieces:
|
|
5
|
+
*
|
|
6
|
+
* - **Code store** - a 6-digit code is generated with `crypto.randomInt` and
|
|
7
|
+
* kept server-side as a SHA-256 hash with an expiry and an attempt counter
|
|
8
|
+
* (never the plaintext, never in the JWT). `verifyCode` is constant-time on
|
|
9
|
+
* the hash, enforces the TTL, and burns the code after too many attempts or
|
|
10
|
+
* one success. In-memory `Map` keyed by lowercased email - fine for a
|
|
11
|
+
* single-instance app behind a tunnel.
|
|
12
|
+
* - **Session JWT** - on a correct code, `signSession` mints a short-lived
|
|
13
|
+
* HS256 JWT (via `jose`) carrying only the email; `verifySession` validates
|
|
14
|
+
* it. The signing key comes from `AUTH_JWT_SECRET`; when unset the gate
|
|
15
|
+
* FAILS OPEN with an ephemeral per-process key (sessions reset on restart)
|
|
16
|
+
* rather than refusing service - a Databricks App is already access-limited,
|
|
17
|
+
* so an unset secret degrades to "sessions don't survive restarts", not
|
|
18
|
+
* "nobody can log in".
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { createHash, randomBytes, randomInt, timingSafeEqual } from "node:crypto";
|
|
23
|
+
import { jwtVerify, SignJWT } from "jose";
|
|
24
|
+
import { log } from "@dbx-tools/shared-core";
|
|
25
|
+
const logger = log.logger("email:auth:otp");
|
|
26
|
+
/** JWT issuer/audience so a token minted for this gate isn't accepted elsewhere. */
|
|
27
|
+
const JWT_AUD = "dbx-tools-email-auth";
|
|
28
|
+
/** SHA-256 hex of a value (for the stored code + a stable key comparison). */
|
|
29
|
+
function sha256(value) {
|
|
30
|
+
return createHash("sha256").update(value).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
/** Constant-time compare of two hex digests of equal length. */
|
|
33
|
+
function safeEqualHex(a, b) {
|
|
34
|
+
if (a.length !== b.length)
|
|
35
|
+
return false;
|
|
36
|
+
return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
37
|
+
}
|
|
38
|
+
/** In-memory store of pending one-time codes, keyed by lowercased email. */
|
|
39
|
+
export class CodeStore {
|
|
40
|
+
ttlMs;
|
|
41
|
+
maxAttempts;
|
|
42
|
+
codes = new Map();
|
|
43
|
+
constructor(ttlMs, maxAttempts) {
|
|
44
|
+
this.ttlMs = ttlMs;
|
|
45
|
+
this.maxAttempts = maxAttempts;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate, store (hashed), and RETURN a fresh 6-digit code for `email`. The
|
|
49
|
+
* caller emails the returned plaintext; only the hash is retained. Replaces
|
|
50
|
+
* any pending code for the address.
|
|
51
|
+
*/
|
|
52
|
+
issue(email, now = Date.now()) {
|
|
53
|
+
const code = String(randomInt(0, 1_000_000)).padStart(6, "0");
|
|
54
|
+
this.codes.set(email.toLowerCase(), {
|
|
55
|
+
hash: sha256(code),
|
|
56
|
+
expiresAt: now + this.ttlMs,
|
|
57
|
+
attempts: 0,
|
|
58
|
+
});
|
|
59
|
+
return code;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check `code` for `email`. Consumes the entry on success or when attempts are
|
|
63
|
+
* exhausted, so a code is single-use and can't be brute-forced past the cap.
|
|
64
|
+
*/
|
|
65
|
+
verify(email, code, now = Date.now()) {
|
|
66
|
+
const key = email.toLowerCase();
|
|
67
|
+
const entry = this.codes.get(key);
|
|
68
|
+
if (!entry)
|
|
69
|
+
return "invalid";
|
|
70
|
+
if (now >= entry.expiresAt) {
|
|
71
|
+
this.codes.delete(key);
|
|
72
|
+
return "expired";
|
|
73
|
+
}
|
|
74
|
+
entry.attempts += 1;
|
|
75
|
+
if (safeEqualHex(entry.hash, sha256(code))) {
|
|
76
|
+
this.codes.delete(key);
|
|
77
|
+
return "ok";
|
|
78
|
+
}
|
|
79
|
+
if (entry.attempts >= this.maxAttempts) {
|
|
80
|
+
this.codes.delete(key);
|
|
81
|
+
return "too-many-attempts";
|
|
82
|
+
}
|
|
83
|
+
return "invalid";
|
|
84
|
+
}
|
|
85
|
+
/** Drop every pending code (tests). */
|
|
86
|
+
clear() {
|
|
87
|
+
this.codes.clear();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve the HS256 signing key. Prefers `AUTH_JWT_SECRET`; when unset, mints an
|
|
92
|
+
* ephemeral per-process key (fail-open) and warns once. Memoized so every
|
|
93
|
+
* sign/verify in a process shares one key.
|
|
94
|
+
*/
|
|
95
|
+
let cachedKey;
|
|
96
|
+
function signingKey() {
|
|
97
|
+
if (cachedKey)
|
|
98
|
+
return cachedKey;
|
|
99
|
+
const secret = process.env.AUTH_JWT_SECRET?.trim();
|
|
100
|
+
if (secret) {
|
|
101
|
+
cachedKey = new TextEncoder().encode(secret);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
logger.warn("AUTH_JWT_SECRET is not set - using an ephemeral per-process key; sessions will not survive a restart");
|
|
105
|
+
cachedKey = randomBytes(32);
|
|
106
|
+
}
|
|
107
|
+
return cachedKey;
|
|
108
|
+
}
|
|
109
|
+
/** Reset the memoized key (tests, or after changing the env in-process). */
|
|
110
|
+
export function resetSigningKey() {
|
|
111
|
+
cachedKey = undefined;
|
|
112
|
+
}
|
|
113
|
+
/** Mint a short-lived session JWT for `email`, expiring in `ttlSeconds`. */
|
|
114
|
+
export async function signSession(email, ttlSeconds) {
|
|
115
|
+
return new SignJWT({ email })
|
|
116
|
+
.setProtectedHeader({ alg: "HS256" })
|
|
117
|
+
.setSubject(email)
|
|
118
|
+
.setAudience(JWT_AUD)
|
|
119
|
+
.setIssuedAt()
|
|
120
|
+
.setExpirationTime(`${ttlSeconds}s`)
|
|
121
|
+
.sign(signingKey());
|
|
122
|
+
}
|
|
123
|
+
/** Validate a session JWT, returning the email it was minted for, or `undefined`. */
|
|
124
|
+
export async function verifySession(token) {
|
|
125
|
+
if (!token)
|
|
126
|
+
return undefined;
|
|
127
|
+
try {
|
|
128
|
+
const { payload } = await jwtVerify(token, signingKey(), { audience: JWT_AUD });
|
|
129
|
+
return typeof payload.email === "string" ? payload.email : undefined;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2F1dGgvb3RwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUVILE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEYsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDMUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRTdDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU1QyxvRkFBb0Y7QUFDcEYsTUFBTSxPQUFPLEdBQUcsc0JBQXNCLENBQUM7QUFFdkMsOEVBQThFO0FBQzlFLFNBQVMsTUFBTSxDQUFDLEtBQWE7SUFDM0IsT0FBTyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMxRCxDQUFDO0FBRUQsZ0VBQWdFO0FBQ2hFLFNBQVMsWUFBWSxDQUFDLENBQVMsRUFBRSxDQUFTO0lBQ3hDLElBQUksQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3hDLE9BQU8sZUFBZSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQVdELDRFQUE0RTtBQUM1RSxNQUFNLE9BQU8sU0FBUztJQUlEO0lBQ0E7SUFKRixLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXFCLENBQUM7SUFFdEQsWUFDbUIsS0FBYSxFQUNiLFdBQW1CO1FBRG5CLFVBQUss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QUFDLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFDO1NBQ3BDLFVBQVUsQ0FBQyxLQUFLLENBQUM7U0FDakIsV0FBVyxDQUFDLE9BQU8sQ0FBQztTQUNwQixXQUFXLEVBQUU7U0FDYixpQkFBaUIsQ0FBQyxHQUFHLFVBQVUsR0FBRyxDQUFDO1NBQ25DLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxxRkFBcUY7QUFDckYsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQUMsS0FBeUI7SUFDM0QsSUFBSSxDQUFDLEtBQUs7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM3QixJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDaEYsT0FBTyxPQUFPLE9BQU8sQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDdkUsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBPbmUtdGltZS1jb2RlIHN0b3JlICsgc2Vzc2lvbiBKV1QgZm9yIHRoZSBlbWFpbC1PVFAgZ2F0ZS5cbiAqXG4gKiBUd28gcGllY2VzOlxuICpcbiAqICAgLSAqKkNvZGUgc3RvcmUqKiAtIGEgNi1kaWdpdCBjb2RlIGlzIGdlbmVyYXRlZCB3aXRoIGBjcnlwdG8ucmFuZG9tSW50YCBhbmRcbiAqICAgICBrZXB0IHNlcnZlci1zaWRlIGFzIGEgU0hBLTI1NiBoYXNoIHdpdGggYW4gZXhwaXJ5IGFuZCBhbiBhdHRlbXB0IGNvdW50ZXJcbiAqICAgICAobmV2ZXIgdGhlIHBsYWludGV4dCwgbmV2ZXIgaW4gdGhlIEpXVCkuIGB2ZXJpZnlDb2RlYCBpcyBjb25zdGFudC10aW1lIG9uXG4gKiAgICAgdGhlIGhhc2gsIGVuZm9yY2VzIHRoZSBUVEwsIGFuZCBidXJucyB0aGUgY29kZSBhZnRlciB0b28gbWFueSBhdHRlbXB0cyBvclxuICogICAgIG9uZSBzdWNjZXNzLiBJbi1tZW1vcnkgYE1hcGAga2V5ZWQgYnkgbG93ZXJjYXNlZCBlbWFpbCAtIGZpbmUgZm9yIGFcbiAqICAgICBzaW5nbGUtaW5zdGFuY2UgYXBwIGJlaGluZCBhIHR1bm5lbC5cbiAqICAgLSAqKlNlc3Npb24gSldUKiogLSBvbiBhIGNvcnJlY3QgY29kZSwgYHNpZ25TZXNzaW9uYCBtaW50cyBhIHNob3J0LWxpdmVkXG4gKiAgICAgSFMyNTYgSldUICh2aWEgYGpvc2VgKSBjYXJyeWluZyBvbmx5IHRoZSBlbWFpbDsgYHZlcmlmeVNlc3Npb25gIHZhbGlkYXRlc1xuICogICAgIGl0LiBUaGUgc2lnbmluZyBrZXkgY29tZXMgZnJvbSBgQVVUSF9KV1RfU0VDUkVUYDsgd2hlbiB1bnNldCB0aGUgZ2F0ZVxuICogICAgIEZBSUxTIE9QRU4gd2l0aCBhbiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5IChzZXNzaW9ucyByZXNldCBvbiByZXN0YXJ0KVxuICogICAgIHJhdGhlciB0aGFuIHJlZnVzaW5nIHNlcnZpY2UgLSBhIERhdGFicmlja3MgQXBwIGlzIGFscmVhZHkgYWNjZXNzLWxpbWl0ZWQsXG4gKiAgICAgc28gYW4gdW5zZXQgc2VjcmV0IGRlZ3JhZGVzIHRvIFwic2Vzc2lvbnMgZG9uJ3Qgc3Vydml2ZSByZXN0YXJ0c1wiLCBub3RcbiAqICAgICBcIm5vYm9keSBjYW4gbG9nIGluXCIuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHJhbmRvbUJ5dGVzLCByYW5kb21JbnQsIHRpbWluZ1NhZmVFcXVhbCB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHsgand0VmVyaWZ5LCBTaWduSldUIH0gZnJvbSBcImpvc2VcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJlbWFpbDphdXRoOm90cFwiKTtcblxuLyoqIEpXVCBpc3N1ZXIvYXVkaWVuY2Ugc28gYSB0b2tlbiBtaW50ZWQgZm9yIHRoaXMgZ2F0ZSBpc24ndCBhY2NlcHRlZCBlbHNld2hlcmUuICovXG5jb25zdCBKV1RfQVVEID0gXCJkYngtdG9vbHMtZW1haWwtYXV0aFwiO1xuXG4vKiogU0hBLTI1NiBoZXggb2YgYSB2YWx1ZSAoZm9yIHRoZSBzdG9yZWQgY29kZSArIGEgc3RhYmxlIGtleSBjb21wYXJpc29uKS4gKi9cbmZ1bmN0aW9uIHNoYTI1Nih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHZhbHVlKS5kaWdlc3QoXCJoZXhcIik7XG59XG5cbi8qKiBDb25zdGFudC10aW1lIGNvbXBhcmUgb2YgdHdvIGhleCBkaWdlc3RzIG9mIGVxdWFsIGxlbmd0aC4gKi9cbmZ1bmN0aW9uIHNhZmVFcXVhbEhleChhOiBzdHJpbmcsIGI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAoYS5sZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0aW1pbmdTYWZlRXF1YWwoQnVmZmVyLmZyb20oYSwgXCJoZXhcIiksIEJ1ZmZlci5mcm9tKGIsIFwiaGV4XCIpKTtcbn1cblxuaW50ZXJmYWNlIENvZGVFbnRyeSB7XG4gIGhhc2g6IHN0cmluZztcbiAgZXhwaXJlc0F0OiBudW1iZXI7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG59XG5cbi8qKiBSZXN1bHQgb2Yge0BsaW5rIENvZGVTdG9yZS52ZXJpZnl9LiAqL1xuZXhwb3J0IHR5cGUgVmVyaWZ5T3V0Y29tZSA9IFwib2tcIiB8IFwiaW52YWxpZFwiIHwgXCJleHBpcmVkXCIgfCBcInRvby1tYW55LWF0dGVtcHRzXCI7XG5cbi8qKiBJbi1tZW1vcnkgc3RvcmUgb2YgcGVuZGluZyBvbmUtdGltZSBjb2Rlcywga2V5ZWQgYnkgbG93ZXJjYXNlZCBlbWFpbC4gKi9cbmV4cG9ydCBjbGFzcyBDb2RlU3RvcmUge1xuICBwcml2YXRlIHJlYWRvbmx5IGNvZGVzID0gbmV3IE1hcDxzdHJpbmcsIENvZGVFbnRyeT4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHR0bE1zOiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBtYXhBdHRlbXB0czogbnVtYmVyLFxuICApIHt9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlLCBzdG9yZSAoaGFzaGVkKSwgYW5kIFJFVFVSTiBhIGZyZXNoIDYtZGlnaXQgY29kZSBmb3IgYGVtYWlsYC4gVGhlXG4gICAqIGNhbGxlciBlbWFpbHMgdGhlIHJldHVybmVkIHBsYWludGV4dDsgb25seSB0aGUgaGFzaCBpcyByZXRhaW5lZC4gUmVwbGFjZXNcbiAgICogYW55IHBlbmRpbmcgY29kZSBmb3IgdGhlIGFkZHJlc3MuXG4gICAqL1xuICBpc3N1ZShlbWFpbDogc3RyaW5nLCBub3c6IG51bWJlciA9IERhdGUubm93KCkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvZGUgPSBTdHJpbmcocmFuZG9tSW50KDAsIDFfMDAwXzAwMCkpLnBhZFN0YXJ0KDYsIFwiMFwiKTtcbiAgICB0aGlzLmNvZGVzLnNldChlbWFpbC50b0xvd2VyQ2FzZSgpLCB7XG4gICAgICBoYXNoOiBzaGEyNTYoY29kZSksXG4gICAgICBleHBpcmVzQXQ6IG5vdyArIHRoaXMudHRsTXMsXG4gICAgICBhdHRlbXB0czogMCxcbiAgICB9KTtcbiAgICByZXR1cm4gY29kZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBgY29kZWAgZm9yIGBlbWFpbGAuIENvbnN1bWVzIHRoZSBlbnRyeSBvbiBzdWNjZXNzIG9yIHdoZW4gYXR0ZW1wdHMgYXJlXG4gICAqIGV4aGF1c3RlZCwgc28gYSBjb2RlIGlzIHNpbmdsZS11c2UgYW5kIGNhbid0IGJlIGJydXRlLWZvcmNlZCBwYXN0IHRoZSBjYXAuXG4gICAqL1xuICB2ZXJpZnkoZW1haWw6IHN0cmluZywgY29kZTogc3RyaW5nLCBub3c6IG51bWJlciA9IERhdGUubm93KCkpOiBWZXJpZnlPdXRjb21lIHtcbiAgICBjb25zdCBrZXkgPSBlbWFpbC50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5jb2Rlcy5nZXQoa2V5KTtcbiAgICBpZiAoIWVudHJ5KSByZXR1cm4gXCJpbnZhbGlkXCI7XG4gICAgaWYgKG5vdyA+PSBlbnRyeS5leHBpcmVzQXQpIHtcbiAgICAgIHRoaXMuY29kZXMuZGVsZXRlKGtleSk7XG4gICAgICByZXR1cm4gXCJleHBpcmVkXCI7XG4gICAgfVxuICAgIGVudHJ5LmF0dGVtcHRzICs9IDE7XG4gICAgaWYgKHNhZmVFcXVhbEhleChlbnRyeS5oYXNoLCBzaGEyNTYoY29kZSkpKSB7XG4gICAgICB0aGlzLmNvZGVzLmRlbGV0ZShrZXkpO1xuICAgICAgcmV0dXJuIFwib2tcIjtcbiAgICB9XG4gICAgaWYgKGVudHJ5LmF0dGVtcHRzID49IHRoaXMubWF4QXR0ZW1wdHMpIHtcbiAgICAgIHRoaXMuY29kZXMuZGVsZXRlKGtleSk7XG4gICAgICByZXR1cm4gXCJ0b28tbWFueS1hdHRlbXB0c1wiO1xuICAgIH1cbiAgICByZXR1cm4gXCJpbnZhbGlkXCI7XG4gIH1cblxuICAvKiogRHJvcCBldmVyeSBwZW5kaW5nIGNvZGUgKHRlc3RzKS4gKi9cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5jb2Rlcy5jbGVhcigpO1xuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgSFMyNTYgc2lnbmluZyBrZXkuIFByZWZlcnMgYEFVVEhfSldUX1NFQ1JFVGA7IHdoZW4gdW5zZXQsIG1pbnRzIGFuXG4gKiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5IChmYWlsLW9wZW4pIGFuZCB3YXJucyBvbmNlLiBNZW1vaXplZCBzbyBldmVyeVxuICogc2lnbi92ZXJpZnkgaW4gYSBwcm9jZXNzIHNoYXJlcyBvbmUga2V5LlxuICovXG5sZXQgY2FjaGVkS2V5OiBVaW50OEFycmF5IHwgdW5kZWZpbmVkO1xuZnVuY3Rpb24gc2lnbmluZ0tleSgpOiBVaW50OEFycmF5IHtcbiAgaWYgKGNhY2hlZEtleSkgcmV0dXJuIGNhY2hlZEtleTtcbiAgY29uc3Qgc2VjcmV0ID0gcHJvY2Vzcy5lbnYuQVVUSF9KV1RfU0VDUkVUPy50cmltKCk7XG4gIGlmIChzZWNyZXQpIHtcbiAgICBjYWNoZWRLZXkgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoc2VjcmV0KTtcbiAgfSBlbHNlIHtcbiAgICBsb2dnZXIud2FybihcbiAgICAgIFwiQVVUSF9KV1RfU0VDUkVUIGlzIG5vdCBzZXQgLSB1c2luZyBhbiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5OyBzZXNzaW9ucyB3aWxsIG5vdCBzdXJ2aXZlIGEgcmVzdGFydFwiLFxuICAgICk7XG4gICAgY2FjaGVkS2V5ID0gcmFuZG9tQnl0ZXMoMzIpO1xuICB9XG4gIHJldHVybiBjYWNoZWRLZXk7XG59XG5cbi8qKiBSZXNldCB0aGUgbWVtb2l6ZWQga2V5ICh0ZXN0cywgb3IgYWZ0ZXIgY2hhbmdpbmcgdGhlIGVudiBpbi1wcm9jZXNzKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldFNpZ25pbmdLZXkoKTogdm9pZCB7XG4gIGNhY2hlZEtleSA9IHVuZGVmaW5lZDtcbn1cblxuLyoqIE1pbnQgYSBzaG9ydC1saXZlZCBzZXNzaW9uIEpXVCBmb3IgYGVtYWlsYCwgZXhwaXJpbmcgaW4gYHR0bFNlY29uZHNgLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpZ25TZXNzaW9uKGVtYWlsOiBzdHJpbmcsIHR0bFNlY29uZHM6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiB7XG4gIHJldHVybiBuZXcgU2lnbkpXVCh7IGVtYWlsIH0pXG4gICAgLnNldFByb3RlY3RlZEhlYWRlcih7IGFsZzogXCJIUzI1NlwiIH0pXG4gICAgLnNldFN1YmplY3QoZW1haWwpXG4gICAgLnNldEF1ZGllbmNlKEpXVF9BVUQpXG4gICAgLnNldElzc3VlZEF0KClcbiAgICAuc2V0RXhwaXJhdGlvblRpbWUoYCR7dHRsU2Vjb25kc31zYClcbiAgICAuc2lnbihzaWduaW5nS2V5KCkpO1xufVxuXG4vKiogVmFsaWRhdGUgYSBzZXNzaW9uIEpXVCwgcmV0dXJuaW5nIHRoZSBlbWFpbCBpdCB3YXMgbWludGVkIGZvciwgb3IgYHVuZGVmaW5lZGAuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5U2Vzc2lvbih0b2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgaWYgKCF0b2tlbikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCB7IHBheWxvYWQgfSA9IGF3YWl0IGp3dFZlcmlmeSh0b2tlbiwgc2lnbmluZ0tleSgpLCB7IGF1ZGllbmNlOiBKV1RfQVVEIH0pO1xuICAgIHJldHVybiB0eXBlb2YgcGF5bG9hZC5lbWFpbCA9PT0gXCJzdHJpbmdcIiA/IHBheWxvYWQuZW1haWwgOiB1bmRlZmluZWQ7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small in-memory fixed-window rate limiter for the email-OTP gate.
|
|
3
|
+
*
|
|
4
|
+
* Keyed by an arbitrary string (an email address or a client IP). Each key gets
|
|
5
|
+
* `max` hits per `windowMs`; the window resets on first use after it elapses.
|
|
6
|
+
* `hit()` returns whether the call is allowed and, when not, how many seconds
|
|
7
|
+
* until the window resets so a caller can surface a cooldown.
|
|
8
|
+
*
|
|
9
|
+
* In-memory is intentional and sufficient for a single-app-instance gate: an
|
|
10
|
+
* app behind a portr tunnel serves from one process. It is NOT a distributed
|
|
11
|
+
* limiter; a multi-replica deployment would need shared state. Entries are
|
|
12
|
+
* pruned lazily on access, so an idle key costs nothing after its window.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/** A fixed-window rate limiter over string keys. */
|
|
17
|
+
export declare class RateLimiter {
|
|
18
|
+
private readonly max;
|
|
19
|
+
private readonly windowMs;
|
|
20
|
+
private readonly windows;
|
|
21
|
+
constructor(max: number, windowMs: number);
|
|
22
|
+
/**
|
|
23
|
+
* Record a hit for `key`. Returns `{ allowed }`, plus `retryAfter` (seconds)
|
|
24
|
+
* when the limit is exceeded. A limit of `<= 0` disables limiting (always
|
|
25
|
+
* allowed), which lets a config turn it off without special-casing callers.
|
|
26
|
+
*/
|
|
27
|
+
hit(key: string, now?: number): {
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
retryAfter?: number;
|
|
30
|
+
};
|
|
31
|
+
/** Forget a key (e.g. clear a caller's window after a successful verify). */
|
|
32
|
+
reset(key: string): void;
|
|
33
|
+
/** Drop every window (tests). */
|
|
34
|
+
clear(): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small in-memory fixed-window rate limiter for the email-OTP gate.
|
|
3
|
+
*
|
|
4
|
+
* Keyed by an arbitrary string (an email address or a client IP). Each key gets
|
|
5
|
+
* `max` hits per `windowMs`; the window resets on first use after it elapses.
|
|
6
|
+
* `hit()` returns whether the call is allowed and, when not, how many seconds
|
|
7
|
+
* until the window resets so a caller can surface a cooldown.
|
|
8
|
+
*
|
|
9
|
+
* In-memory is intentional and sufficient for a single-app-instance gate: an
|
|
10
|
+
* app behind a portr tunnel serves from one process. It is NOT a distributed
|
|
11
|
+
* limiter; a multi-replica deployment would need shared state. Entries are
|
|
12
|
+
* pruned lazily on access, so an idle key costs nothing after its window.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/** A fixed-window rate limiter over string keys. */
|
|
17
|
+
export class RateLimiter {
|
|
18
|
+
max;
|
|
19
|
+
windowMs;
|
|
20
|
+
windows = new Map();
|
|
21
|
+
constructor(max, windowMs) {
|
|
22
|
+
this.max = max;
|
|
23
|
+
this.windowMs = windowMs;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Record a hit for `key`. Returns `{ allowed }`, plus `retryAfter` (seconds)
|
|
27
|
+
* when the limit is exceeded. A limit of `<= 0` disables limiting (always
|
|
28
|
+
* allowed), which lets a config turn it off without special-casing callers.
|
|
29
|
+
*/
|
|
30
|
+
hit(key, now = Date.now()) {
|
|
31
|
+
if (this.max <= 0)
|
|
32
|
+
return { allowed: true };
|
|
33
|
+
const existing = this.windows.get(key);
|
|
34
|
+
if (!existing || now >= existing.resetAt) {
|
|
35
|
+
this.windows.set(key, { count: 1, resetAt: now + this.windowMs });
|
|
36
|
+
return { allowed: true };
|
|
37
|
+
}
|
|
38
|
+
if (existing.count < this.max) {
|
|
39
|
+
existing.count += 1;
|
|
40
|
+
return { allowed: true };
|
|
41
|
+
}
|
|
42
|
+
return { allowed: false, retryAfter: Math.ceil((existing.resetAt - now) / 1000) };
|
|
43
|
+
}
|
|
44
|
+
/** Forget a key (e.g. clear a caller's window after a successful verify). */
|
|
45
|
+
reset(key) {
|
|
46
|
+
this.windows.delete(key);
|
|
47
|
+
}
|
|
48
|
+
/** Drop every window (tests). */
|
|
49
|
+
clear() {
|
|
50
|
+
this.windows.clear();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdXRoL3JhdGUtbGltaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFPSCxvREFBb0Q7QUFDcEQsTUFBTSxPQUFPLFdBQVc7SUFJSDtJQUNBO0lBSkYsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBRXJELFlBQ21CLEdBQVcsRUFDWCxRQUFnQjtRQURoQixRQUFHLEdBQUgsR0FBRyxDQUFRO1FBQ1gsYUFBUSxHQUFSLFFBQVEsQ0FBUTtJQUNoQyxDQUFDO0lBRUo7Ozs7T0FJRztJQUNILEdBQUcsQ0FBQyxHQUFXLEVBQUUsTUFBYyxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLElBQUksSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDO1lBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUM1QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsUUFBUSxJQUFJLEdBQUcsSUFBSSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ2xFLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDOUIsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7WUFDcEIsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUMzQixDQUFDO1FBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDcEYsQ0FBQztJQUVELDZFQUE2RTtJQUM3RSxLQUFLLENBQUMsR0FBVztRQUNmLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxpQ0FBaUM7SUFDakMsS0FBSztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDdkIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBIHNtYWxsIGluLW1lbW9yeSBmaXhlZC13aW5kb3cgcmF0ZSBsaW1pdGVyIGZvciB0aGUgZW1haWwtT1RQIGdhdGUuXG4gKlxuICogS2V5ZWQgYnkgYW4gYXJiaXRyYXJ5IHN0cmluZyAoYW4gZW1haWwgYWRkcmVzcyBvciBhIGNsaWVudCBJUCkuIEVhY2gga2V5IGdldHNcbiAqIGBtYXhgIGhpdHMgcGVyIGB3aW5kb3dNc2A7IHRoZSB3aW5kb3cgcmVzZXRzIG9uIGZpcnN0IHVzZSBhZnRlciBpdCBlbGFwc2VzLlxuICogYGhpdCgpYCByZXR1cm5zIHdoZXRoZXIgdGhlIGNhbGwgaXMgYWxsb3dlZCBhbmQsIHdoZW4gbm90LCBob3cgbWFueSBzZWNvbmRzXG4gKiB1bnRpbCB0aGUgd2luZG93IHJlc2V0cyBzbyBhIGNhbGxlciBjYW4gc3VyZmFjZSBhIGNvb2xkb3duLlxuICpcbiAqIEluLW1lbW9yeSBpcyBpbnRlbnRpb25hbCBhbmQgc3VmZmljaWVudCBmb3IgYSBzaW5nbGUtYXBwLWluc3RhbmNlIGdhdGU6IGFuXG4gKiBhcHAgYmVoaW5kIGEgcG9ydHIgdHVubmVsIHNlcnZlcyBmcm9tIG9uZSBwcm9jZXNzLiBJdCBpcyBOT1QgYSBkaXN0cmlidXRlZFxuICogbGltaXRlcjsgYSBtdWx0aS1yZXBsaWNhIGRlcGxveW1lbnQgd291bGQgbmVlZCBzaGFyZWQgc3RhdGUuIEVudHJpZXMgYXJlXG4gKiBwcnVuZWQgbGF6aWx5IG9uIGFjY2Vzcywgc28gYW4gaWRsZSBrZXkgY29zdHMgbm90aGluZyBhZnRlciBpdHMgd2luZG93LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbnRlcmZhY2UgV2luZG93IHtcbiAgY291bnQ6IG51bWJlcjtcbiAgcmVzZXRBdDogbnVtYmVyO1xufVxuXG4vKiogQSBmaXhlZC13aW5kb3cgcmF0ZSBsaW1pdGVyIG92ZXIgc3RyaW5nIGtleXMuICovXG5leHBvcnQgY2xhc3MgUmF0ZUxpbWl0ZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHdpbmRvd3MgPSBuZXcgTWFwPHN0cmluZywgV2luZG93PigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSB3aW5kb3dNczogbnVtYmVyLFxuICApIHt9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBhIGhpdCBmb3IgYGtleWAuIFJldHVybnMgYHsgYWxsb3dlZCB9YCwgcGx1cyBgcmV0cnlBZnRlcmAgKHNlY29uZHMpXG4gICAqIHdoZW4gdGhlIGxpbWl0IGlzIGV4Y2VlZGVkLiBBIGxpbWl0IG9mIGA8PSAwYCBkaXNhYmxlcyBsaW1pdGluZyAoYWx3YXlzXG4gICAqIGFsbG93ZWQpLCB3aGljaCBsZXRzIGEgY29uZmlnIHR1cm4gaXQgb2ZmIHdpdGhvdXQgc3BlY2lhbC1jYXNpbmcgY2FsbGVycy5cbiAgICovXG4gIGhpdChrZXk6IHN0cmluZywgbm93OiBudW1iZXIgPSBEYXRlLm5vdygpKTogeyBhbGxvd2VkOiBib29sZWFuOyByZXRyeUFmdGVyPzogbnVtYmVyIH0ge1xuICAgIGlmICh0aGlzLm1heCA8PSAwKSByZXR1cm4geyBhbGxvd2VkOiB0cnVlIH07XG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLndpbmRvd3MuZ2V0KGtleSk7XG4gICAgaWYgKCFleGlzdGluZyB8fCBub3cgPj0gZXhpc3RpbmcucmVzZXRBdCkge1xuICAgICAgdGhpcy53aW5kb3dzLnNldChrZXksIHsgY291bnQ6IDEsIHJlc2V0QXQ6IG5vdyArIHRoaXMud2luZG93TXMgfSk7XG4gICAgICByZXR1cm4geyBhbGxvd2VkOiB0cnVlIH07XG4gICAgfVxuICAgIGlmIChleGlzdGluZy5jb3VudCA8IHRoaXMubWF4KSB7XG4gICAgICBleGlzdGluZy5jb3VudCArPSAxO1xuICAgICAgcmV0dXJuIHsgYWxsb3dlZDogdHJ1ZSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBhbGxvd2VkOiBmYWxzZSwgcmV0cnlBZnRlcjogTWF0aC5jZWlsKChleGlzdGluZy5yZXNldEF0IC0gbm93KSAvIDEwMDApIH07XG4gIH1cblxuICAvKiogRm9yZ2V0IGEga2V5IChlLmcuIGNsZWFyIGEgY2FsbGVyJ3Mgd2luZG93IGFmdGVyIGEgc3VjY2Vzc2Z1bCB2ZXJpZnkpLiAqL1xuICByZXNldChrZXk6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMud2luZG93cy5kZWxldGUoa2V5KTtcbiAgfVxuXG4gIC8qKiBEcm9wIGV2ZXJ5IHdpbmRvdyAodGVzdHMpLiAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLndpbmRvd3MuY2xlYXIoKTtcbiAgfVxufVxuIl19
|
package/lib/src/config.d.ts
CHANGED
|
@@ -81,6 +81,32 @@ export interface EmailPluginConfig extends BasePluginConfig {
|
|
|
81
81
|
* `BrandContext`.
|
|
82
82
|
*/
|
|
83
83
|
brand?: EmailBrand;
|
|
84
|
+
/**
|
|
85
|
+
* Optional email-OTP ACCESS GATE. When `enabled`, the plugin mounts a login
|
|
86
|
+
* flow (`/api/email/auth/*`) and gates every other route behind a session
|
|
87
|
+
* cookie - the front door for an app exposed publicly (e.g. through a portr
|
|
88
|
+
* tunnel that bypasses the Databricks OAuth proxy). Reuses this plugin's
|
|
89
|
+
* transport to email the code. Omit or `enabled: false` to leave the app open.
|
|
90
|
+
*/
|
|
91
|
+
auth?: AuthConfig;
|
|
92
|
+
}
|
|
93
|
+
/** Email-OTP access-gate configuration (see {@link EmailPluginConfig.auth}). */
|
|
94
|
+
export interface AuthConfig {
|
|
95
|
+
/** Turn the gate on. Falls back to `EMAIL_AUTH_ENABLED`. Default off. */
|
|
96
|
+
enabled?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Who may request a code. Each entry is a domain shortcut (`databricks.com`
|
|
99
|
+
* or `@databricks.com`), a glob (`*.databricks.com`), or a `/regex/`. An
|
|
100
|
+
* EMPTY list allows nobody (fail closed). Falls back to `EMAIL_AUTH_ALLOW`
|
|
101
|
+
* (comma/space-separated).
|
|
102
|
+
*/
|
|
103
|
+
allow?: string | string[];
|
|
104
|
+
/** Session lifetime (seconds). Falls back to `EMAIL_AUTH_SESSION_TTL`. Default 43200 (12h). */
|
|
105
|
+
sessionTtlSeconds?: number;
|
|
106
|
+
/** One-time-code lifetime (seconds). Falls back to `EMAIL_AUTH_CODE_TTL`. Default 600 (10m). */
|
|
107
|
+
codeTtlSeconds?: number;
|
|
108
|
+
/** Max verify attempts per issued code. Default 5. */
|
|
109
|
+
maxAttempts?: number;
|
|
84
110
|
}
|
|
85
111
|
/** Config shared by both resolved modes. */
|
|
86
112
|
interface ResolvedSender {
|
|
@@ -121,6 +147,20 @@ export interface ResolvedFileConfig extends ResolvedSender {
|
|
|
121
147
|
export type ResolvedEmailConfig = ResolvedSmtpConfig | ResolvedFileConfig;
|
|
122
148
|
/** JSON Schema published on the manifest's `config.schema`. */
|
|
123
149
|
export declare const EMAIL_CONFIG_SCHEMA: JSONSchema7;
|
|
150
|
+
/** Resolved email-OTP gate config, with env fallbacks applied (or `undefined` when off). */
|
|
151
|
+
export interface ResolvedAuthConfig {
|
|
152
|
+
readonly allow: string[];
|
|
153
|
+
readonly sessionTtlSeconds: number;
|
|
154
|
+
readonly codeTtlSeconds: number;
|
|
155
|
+
readonly maxAttempts: number;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Resolve {@link AuthConfig} against env, returning `undefined` when the gate is
|
|
159
|
+
* off. `enabled` gates everything; `allow` merges the config list + env
|
|
160
|
+
* (`parseList` handles a `string[]` or a delimited string). Empty `allow` is
|
|
161
|
+
* allowed here (the gate then denies everyone - a deliberate fail-closed state).
|
|
162
|
+
*/
|
|
163
|
+
export declare function resolveAuthConfig(auth: AuthConfig | undefined): ResolvedAuthConfig | undefined;
|
|
124
164
|
/**
|
|
125
165
|
* Resolve plugin config over environment defaults.
|
|
126
166
|
*
|
package/lib/src/config.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { resolve } from "node:path";
|
|
27
27
|
import { ConfigurationError, ValidationError } from "@databricks/appkit";
|
|
28
|
-
import { object } from "@dbx-tools/shared-core";
|
|
28
|
+
import { object, string } from "@dbx-tools/shared-core";
|
|
29
29
|
import { parseAllowedSenders } from "./sender.js";
|
|
30
30
|
/** SMTP submission port used when none is configured. */
|
|
31
31
|
export const DEFAULT_SMTP_PORT = 587;
|
|
@@ -104,8 +104,60 @@ export const EMAIL_CONFIG_SCHEMA = {
|
|
|
104
104
|
},
|
|
105
105
|
required: ["accent", "fontFamily"],
|
|
106
106
|
},
|
|
107
|
+
auth: {
|
|
108
|
+
type: "object",
|
|
109
|
+
description: "Email-OTP access gate. When enabled, mounts a login flow at /api/email/auth/* and gates every other route behind a session cookie.",
|
|
110
|
+
properties: {
|
|
111
|
+
enabled: {
|
|
112
|
+
type: "boolean",
|
|
113
|
+
description: "Turn the gate on (env EMAIL_AUTH_ENABLED). Default off.",
|
|
114
|
+
},
|
|
115
|
+
allow: {
|
|
116
|
+
type: "array",
|
|
117
|
+
items: { type: "string" },
|
|
118
|
+
description: 'Allow-list of who may request a code: domain shortcut ("databricks.com"), glob ("*.databricks.com"), or "/regex/". Empty = nobody. Also accepts a comma/space-separated string. Env EMAIL_AUTH_ALLOW.',
|
|
119
|
+
},
|
|
120
|
+
sessionTtlSeconds: {
|
|
121
|
+
type: "number",
|
|
122
|
+
description: "Session lifetime in seconds (env EMAIL_AUTH_SESSION_TTL). Default 43200.",
|
|
123
|
+
},
|
|
124
|
+
codeTtlSeconds: {
|
|
125
|
+
type: "number",
|
|
126
|
+
description: "One-time-code lifetime in seconds (env EMAIL_AUTH_CODE_TTL). Default 600.",
|
|
127
|
+
},
|
|
128
|
+
maxAttempts: {
|
|
129
|
+
type: "number",
|
|
130
|
+
description: "Max verify attempts per issued code. Default 5.",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
107
134
|
},
|
|
108
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Resolve {@link AuthConfig} against env, returning `undefined` when the gate is
|
|
138
|
+
* off. `enabled` gates everything; `allow` merges the config list + env
|
|
139
|
+
* (`parseList` handles a `string[]` or a delimited string). Empty `allow` is
|
|
140
|
+
* allowed here (the gate then denies everyone - a deliberate fail-closed state).
|
|
141
|
+
*/
|
|
142
|
+
export function resolveAuthConfig(auth) {
|
|
143
|
+
const enabled = auth?.enabled ?? object.toBoolean(process.env.EMAIL_AUTH_ENABLED) ?? false;
|
|
144
|
+
if (!enabled)
|
|
145
|
+
return undefined;
|
|
146
|
+
const allow = [
|
|
147
|
+
...string.parseList(auth?.allow),
|
|
148
|
+
...string.parseList(process.env.EMAIL_AUTH_ALLOW),
|
|
149
|
+
];
|
|
150
|
+
const num = (value, env, fallback) => {
|
|
151
|
+
const raw = value ?? (env ? Number(env) : undefined);
|
|
152
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
allow,
|
|
156
|
+
sessionTtlSeconds: num(auth?.sessionTtlSeconds, process.env.EMAIL_AUTH_SESSION_TTL, 43200),
|
|
157
|
+
codeTtlSeconds: num(auth?.codeTtlSeconds, process.env.EMAIL_AUTH_CODE_TTL, 600),
|
|
158
|
+
maxAttempts: auth?.maxAttempts ?? 5,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
109
161
|
/** Parse the `SMTP_SECURE` env / config flag, defaulting by port. */
|
|
110
162
|
function resolveSecure(flag, port) {
|
|
111
163
|
if (typeof flag === "boolean")
|
|
@@ -209,4 +261,4 @@ export function resolveEmailConfig(config = {}) {
|
|
|
209
261
|
const outDir = resolve(config.outDir ?? process.env.EMAIL_OUTBOX_DIR ?? resolve(process.cwd(), "tmp"));
|
|
210
262
|
return { mode: "file", outDir, ...sender };
|
|
211
263
|
}
|
|
212
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUF5QixNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUdoRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFbEQseURBQXlEO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUVyQywyRUFBMkU7QUFDM0UsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDO0FBd0gxQywrREFBK0Q7QUFDL0QsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQWdCO0lBQzlDLElBQUksRUFBRSxRQUFRO0lBQ2QsVUFBVSxFQUFFO1FBQ1YsSUFBSSxFQUFFO1lBQ0osSUFBSSxFQUFFLFFBQVE7WUFDZCxXQUFXLEVBQUUsMERBQTBEO1lBQ3ZFLFVBQVUsRUFBRTtnQkFDVixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxtQ0FBbUMsRUFBRTtnQkFDMUUsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSxRQUFRO29CQUNkLFdBQVcsRUFBRSw2Q0FBNkMsaUJBQWlCLEdBQUc7aUJBQy9FO2dCQUNELE1BQU0sRUFBRTtvQkFDTixJQUFJLEVBQUUsU0FBUztvQkFDZixXQUFXLEVBQUUsNkRBQTZELHNCQUFzQixHQUFHO2lCQUNwRztnQkFDRCxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxpQ0FBaUMsRUFBRTtnQkFDeEUsUUFBUSxFQUFFO29CQUNSLElB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bmZpZ3VyYXRpb24gZm9yIHRoZSBlbWFpbCBwbHVnaW46IHRoZSB0eXBlZFxuICoge0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnfSAodGhlIHBsdWdpbidzIHNsaWNlIG9mIEFwcEtpdCBjb25maWcpLCB0aGVcbiAqIEpTT04gU2NoZW1hIHRoZSBtYW5pZmVzdCBwdWJsaXNoZXMgZm9yIGl0LCBhbmQge0BsaW5rIHJlc29sdmVFbWFpbENvbmZpZ31cbiAqIHdoaWNoIGxheWVycyB0aGF0IGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzIGludG8gdGhlIGNvbmNyZXRlXG4gKiB7QGxpbmsgUmVzb2x2ZWRFbWFpbENvbmZpZ30gdGhlIHJ1bnRpbWUgbmVlZHMuXG4gKlxuICogVHdvIG1vZGVzIGZhbGwgb3V0IG9mIHRoZSByZXNvbHV0aW9uLiBXaGVuIFNNVFAgY3JlZGVudGlhbHMgKGhvc3QgK1xuICogdXNlciArIHBhc3N3b3JkKSBhcmUgYWxsIHByZXNlbnQgaXQgcmVzb2x2ZXMgdG8gYG1vZGU6IFwic210cFwiYCBhbmRcbiAqIG1haWwgaXMgc2VudCBmb3IgcmVhbC4gV2hlbiB0aGV5IGFyZSBhYnNlbnQgYW5kIGBFTUFJTF9PVVRCT1hfTU9ERWBcbiAqIGlzIGV4cGxpY2l0bHkgZW5hYmxlZCBpdCByZXNvbHZlcyB0byBgbW9kZTogXCJmaWxlXCJgIChhbiBcIm91dGJveFwiKVxuICogYW5kIGVhY2ggbWVzc2FnZSBpcyB3cml0dGVuIHRvIGRpc2sgYXMgSFRNTCBpbnN0ZWFkIG9mIHNlbnQuIEFueVxuICogcGFydGlhbCBTTVRQIGNvbmZpZ3VyYXRpb24gb3IgYSBzZW5kIGF0dGVtcHQgd2l0aCBubyBjcmVkZW50aWFscyBhbmRcbiAqIG5vIG91dGJveCBvcHQtaW4gdGhyb3dzLlxuICpcbiAqIFByZWNlZGVuY2UgcGVyIGZpZWxkOiBleHBsaWNpdCBwbHVnaW4gY29uZmlnIHdpbnMsIHRoZW4gdGhlIG1hdGNoaW5nXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZS4gRW52IG5hbWVzIGFyZSB1bnByZWZpeGVkIGJlY2F1c2UgdGhlIGFwcCB0YWxrc1xuICogdG8gYSBzaW5nbGUgU01UUCBzZXJ2ZXIgKGUuZy4gU01UUDJHTyk6IGBTTVRQX0hPU1RgLCBgU01UUF9QT1JUYCxcbiAqIGBTTVRQX1NFQ1VSRWAsIGBTTVRQX1VTRVJgLCBgU01UUF9QQVNTV09SRGAsIHBsdXMgYEVNQUlMX0RPTUFJTmAgZm9yXG4gKiB0aGUgZGVyaXZlZCBzZW5kZXIncyBkb21haW4sIGBFTUFJTF9GUk9NYCBmb3IgYW4gZXhwbGljaXQgb3ZlcnJpZGUsXG4gKiBgRU1BSUxfU0VOREVSX1BPTElDWWAgZm9yIHRoZSBzZW5kZXIgcmVzdHJpY3Rpb24gbW9kZSwgYW5kXG4gKiBgRU1BSUxfT1VUQk9YX0RJUmAgZm9yIHRoZSBvdXRib3ggZGlyZWN0b3J5LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IENvbmZpZ3VyYXRpb25FcnJvciwgVmFsaWRhdGlvbkVycm9yLCB0eXBlIEJhc2VQbHVnaW5Db25maWcgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBKU09OU2NoZW1hNyB9IGZyb20gXCJqc29uLXNjaGVtYVwiO1xuaW1wb3J0IHR5cGUgeyBFbWFpbEJyYW5kIH0gZnJvbSBcIi4vYnJhbmQudHNcIjtcbmltcG9ydCB7IHBhcnNlQWxsb3dlZFNlbmRlcnMgfSBmcm9tIFwiLi9zZW5kZXIudHNcIjtcblxuLyoqIFNNVFAgc3VibWlzc2lvbiBwb3J0IHVzZWQgd2hlbiBub25lIGlzIGNvbmZpZ3VyZWQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9TTVRQX1BPUlQgPSA1ODc7XG5cbi8qKiBTTVRQIHBvcnQgdGhhdCBpbXBsaWVzIGEgVExTLW9uLWNvbm5lY3Qgc29ja2V0IHJhdGhlciB0aGFuIFNUQVJUVExTLiAqL1xuZXhwb3J0IGNvbnN0IElNUExJQ0lUX1RMU19TTVRQX1BPUlQgPSA0NjU7XG5cbi8qKlxuICogSG93IHRoZSBzZW5kZXIgKGBGcm9tYCkgYWRkcmVzcyBpcyByZXN0cmljdGVkLlxuICpcbiAqIGBcImFsbG93bGlzdFwiYCBpcyB0aGUgZGVmYXVsdCBhbmQgdGhlIGRlbnktYnktZGVmYXVsdCBwb3N0dXJlOiBhIHNlbmQgaXNcbiAqIHBlcm1pdHRlZCBvbmx5IGZyb20gYW4gYWRkcmVzcyB0aGUgY29uZmlndXJhdGlvbiBuYW1lcywgZWl0aGVyIHRocm91Z2hcbiAqIHtAbGluayBFbWFpbFBsdWdpbkNvbmZpZy5hbGxvd2VkU2VuZGVyc30gb3IsIHdoZW4gdGhhdCBpcyBlbXB0eSwgdGhyb3VnaFxuICogdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZSAoe0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnLmZyb219IGFzIGFuIGV4YWN0XG4gKiBhZGRyZXNzLCB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuZG9tYWlufSBhcyBhIGAqQGRvbWFpbmAgd2lsZGNhcmQpLlxuICpcbiAqIGBcInVucmVzdHJpY3RlZFwiYCBpcyB0aGUgZXhwbGljaXQgb3B0LW91dDogYW55IGBGcm9tYCBhIGNhbGxlciBzdXBwbGllcyBpc1xuICogYWNjZXB0ZWQuIE9ubHkgcmVhY2ggZm9yIGl0IHdoZW4gYW4gdXBzdHJlYW0gc3lzdGVtIGFscmVhZHkgdmV0cyB0aGVcbiAqIHNlbmRlci5cbiAqL1xuZXhwb3J0IHR5cGUgU2VuZGVyUG9saWN5ID0gXCJhbGxvd2xpc3RcIiB8IFwidW5yZXN0cmljdGVkXCI7XG5cbi8qKiBTTVRQIGNvbm5lY3Rpb24gKyBjcmVkZW50aWFscy4gQWxsIGZpZWxkcyBmYWxsIGJhY2sgdG8gZW52IHdoZW4gdW5zZXQuICovXG5leHBvcnQgaW50ZXJmYWNlIFNtdHBDb25maWcge1xuICAvKiogU01UUCBzZXJ2ZXIgaG9zdG5hbWUgKGBTTVRQX0hPU1RgKS4gKi9cbiAgaG9zdD86IHN0cmluZztcbiAgLyoqIFNNVFAgc2VydmVyIHBvcnQgKGBTTVRQX1BPUlRgKS4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfU01UUF9QT1JUfS4gKi9cbiAgcG9ydD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFVzZSBhIFRMUy1vbi1jb25uZWN0IHNvY2tldCAoYFNNVFBfU0VDVVJFYCkuIERlZmF1bHRzIHRvXG4gICAqIGBwb3J0ID09PSBgIHtAbGluayBJTVBMSUNJVF9UTFNfU01UUF9QT1JUfS5cbiAgICovXG4gIHNlY3VyZT86IGJvb2xlYW47XG4gIC8qKiBTTVRQIGF1dGggdXNlcm5hbWUgKGBTTVRQX1VTRVJgKS4gKi9cbiAgdXNlcj86IHN0cmluZztcbiAgLyoqIFNNVFAgYXV0aCBwYXNzd29yZCAvIEFQSSBrZXkgKGBTTVRQX1BBU1NXT1JEYCkuICovXG4gIHBhc3N3b3JkPzogc3RyaW5nO1xufVxuXG4vKiogQXBwS2l0IGNvbmZpZyBhY2NlcHRlZCBieSB0aGUgZW1haWwgcGx1Z2luLiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbWFpbFBsdWdpbkNvbmZpZyBleHRlbmRzIEJhc2VQbHVnaW5Db25maWcge1xuICAvKiogU01UUCBjb25uZWN0aW9uICsgY3JlZGVudGlhbHMuIE9taXQgdG8gcnVuIGluIGZpbGUvb3V0Ym94IG1vZGUuICovXG4gIHNtdHA/OiBTbXRwQ29uZmlnO1xuICAvKipcbiAgICogRG9tYWluIHVzZWQgdG8gYnVpbGQgdGhlIHNlbmRlciBhZGRyZXNzIGZyb20gdGhlIG9uLWJlaGFsZi1vZiB1c2VyXG4gICAqIChgPGxvY2FsLXBhcnQ+QDxkb21haW4+YCkuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0RPTUFJTmAuIFJlcXVpcmVkIGluXG4gICAqIFNNVFAgbW9kZSB1bmxlc3Mge0BsaW5rIGZyb219IGlzIHNldDsgb3B0aW9uYWwgaW4gZmlsZSBtb2RlICh0aGVcbiAgICogb3V0Ym94IGZhbGxzIGJhY2sgdG8gdGhlIHVzZXIncyBvd24gZW1haWwgYWRkcmVzcykuXG4gICAqL1xuICBkb21haW4/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBFeHBsaWNpdCBgRnJvbWAgYWRkcmVzcy4gV2hlbiBzZXQsIHRoZSBzZW5kZXIgaXMgdXNlZCB2ZXJiYXRpbSBhbmRcbiAgICogdGhlIHBlci11c2VyIGRlcml2YXRpb24gaXMgc2tpcHBlZC4gRmFsbHMgYmFjayB0byBgRU1BSUxfRlJPTWAuXG4gICAqL1xuICBmcm9tPzogc3RyaW5nO1xuICAvKipcbiAgICogRGlyZWN0b3J5IGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2suIEZhbGxzIGJhY2sgdG9cbiAgICogYEVNQUlMX09VVEJPWF9ESVJgLCB0aGVuIGA8Y3dkPi90bXBgLiBPbmx5IHVzZWQgd2hlbiBTTVRQXG4gICAqIGNyZWRlbnRpYWxzIGFyZSBhYnNlbnQuXG4gICAqL1xuICBvdXREaXI/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBBbGxvdy1saXN0IHJlc3RyaWN0aW5nIHRoZSBzZW5kZXIgKGBGcm9tYCkgYWRkcmVzcy4gRWFjaCBlbnRyeSBpcyBhblxuICAgKiBleGFjdCBhZGRyZXNzIChgdXNlckBkb21haW4uY29tYCksIGEgZG9tYWluIHdpbGRjYXJkIChgKkBkb21haW4uY29tYFxuICAgKiBvciB0aGUgYmFyZSBgZG9tYWluLmNvbWAsIG1hdGNoaW5nIGFueSBsb2NhbCBwYXJ0IG9uIHRoYXQgZG9tYWluKSwgb3JcbiAgICogYCpgIChhbnkpLiBBIHJlc29sdmVkIC8gY2hvc2VuIHNlbmRlciB0aGF0IG1hdGNoZXMgbm8gZW50cnkgaXNcbiAgICogcmVqZWN0ZWQgYXQgc2VuZCB0aW1lLiBBY2NlcHRzIGEgYHN0cmluZ1tdYCBvciBhIHNpbmdsZSBjb21tYS0gL1xuICAgKiB3aGl0ZXNwYWNlLXNlcGFyYXRlZCBzdHJpbmc7IGZhbGxzIGJhY2sgdG8gYEVNQUlMX0FMTE9XRURfU0VOREVSU2AuXG4gICAqIFdoZW4gZW1wdHksIHRoZSB7QGxpbmsgc2VuZGVyUG9saWN5fSBkZWNpZGVzIHdoYXQgaXMgcGVybWl0dGVkLlxuICAgKi9cbiAgYWxsb3dlZFNlbmRlcnM/OiBzdHJpbmcgfCBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIEhvdyB0aGUgc2VuZGVyIGFkZHJlc3MgaXMgcmVzdHJpY3RlZCB3aGVuIHtAbGluayBhbGxvd2VkU2VuZGVyc30gaXNcbiAgICogZW1wdHkgKGBFTUFJTF9TRU5ERVJfUE9MSUNZYCkuIERlZmF1bHRzIHRvIGBcImFsbG93bGlzdFwiYCwgd2hpY2hcbiAgICogbmFycm93cyBzZW5kcyB0byB0aGUgY29uZmlndXJlZCBzZW5kZXIgc291cmNlLiBTZWVcbiAgICoge0BsaW5rIFNlbmRlclBvbGljeX0uXG4gICAqL1xuICBzZW5kZXJQb2xpY3k/OiBTZW5kZXJQb2xpY3k7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBicmFuZCBzdHlsaW5nIChhY2NlbnQsIGZvbnQsIGhlYWRlciBsb2dvKSBhcHBsaWVkIHRvIHRoZVxuICAgKiByZW5kZXJlZCBIVE1MIG9mIGV2ZXJ5IG1lc3NhZ2UuIE9taXQgZm9yIHRoZSBuZXV0cmFsIGRlZmF1bHQgbGF5b3V0LlxuICAgKiBQYXNzIHtAbGluayBlbWFpbEJyYW5kRnJvbUNvbnRleHR9IHRvIGRlcml2ZSBpdCBmcm9tIGEgc2hhcmVkXG4gICAqIGBCcmFuZENvbnRleHRgLlxuICAgKi9cbiAgYnJhbmQ/OiBFbWFpbEJyYW5kO1xufVxuXG4vKiogQ29uZmlnIHNoYXJlZCBieSBib3RoIHJlc29sdmVkIG1vZGVzLiAqL1xuaW50ZXJmYWNlIFJlc29sdmVkU2VuZGVyIHtcbiAgLyoqIFNlbmRlciBkb21haW47IHByZXNlbnQgd2hlbmV2ZXIge0BsaW5rIGZyb219IGlzIGFic2VudC4gKi9cbiAgZG9tYWluPzogc3RyaW5nO1xuICAvKiogRXhwbGljaXQgc2VuZGVyIG92ZXJyaWRlOyBwcmVzZW50IHNraXBzIHBlci11c2VyIGRlcml2YXRpb24uICovXG4gIGZyb20/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBFZmZlY3RpdmUgc2VuZGVyIGFsbG93LWxpc3Q6IHRoZSBjb25maWd1cmVkIHBhdHRlcm5zIHdoZW4gYW55IHdlcmVcbiAgICogZ2l2ZW4sIGVsc2UgdGhlIHBhdHRlcm5zIGltcGxpZWQgYnkgdGhlIHNlbmRlciBzb3VyY2UgdW5kZXIgYW5cbiAgICogYFwiYWxsb3dsaXN0XCJgIHBvbGljeS4gRW1wdHkgbWVhbnMgdW5lbmZvcmNlYWJsZSAoYW4gYFwidW5yZXN0cmljdGVkXCJgXG4gICAqIHBvbGljeSwgb3IgYW4gb3V0Ym94IHdpdGggbm8gc2VuZGVyIHNvdXJjZSB0byBuYXJyb3cgdG8pLlxuICAgKi9cbiAgYWxsb3dlZFNlbmRlcnM6IHN0cmluZ1tdO1xuICAvKiogVGhlIHJlc3RyaWN0aW9uIG1vZGUgdGhlIGFsbG93LWxpc3Qgd2FzIHJlc29sdmVkIHVuZGVyLiAqL1xuICBzZW5kZXJQb2xpY3k6IFNlbmRlclBvbGljeTtcbiAgLyoqIEJyYW5kIHN0eWxpbmcgYXBwbGllZCB0byByZW5kZXJlZCBIVE1MOyBhYnNlbnQgZm9yIHRoZSBkZWZhdWx0IGxheW91dC4gKi9cbiAgYnJhbmQ/OiBFbWFpbEJyYW5kO1xufVxuXG4vKiogUmVzb2x2ZWQgY29uZmlnIGZvciByZWFsIFNNVFAgZGVsaXZlcnkuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkU210cENvbmZpZyBleHRlbmRzIFJlc29sdmVkU2VuZGVyIHtcbiAgbW9kZTogXCJzbXRwXCI7XG4gIGhvc3Q6IHN0cmluZztcbiAgcG9ydDogbnVtYmVyO1xuICBzZWN1cmU6IGJvb2xlYW47XG4gIGF1dGg6IHsgdXNlcjogc3RyaW5nOyBwYXNzOiBzdHJpbmcgfTtcbn1cblxuLyoqIFJlc29sdmVkIGNvbmZpZyBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrIChubyBTTVRQIGNyZWRlbnRpYWxzKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRGaWxlQ29uZmlnIGV4dGVuZHMgUmVzb2x2ZWRTZW5kZXIge1xuICBtb2RlOiBcImZpbGVcIjtcbiAgLyoqIEFic29sdXRlIGRpcmVjdG9yeSBtZXNzYWdlcyBhcmUgd3JpdHRlbiB1bmRlci4gKi9cbiAgb3V0RGlyOiBzdHJpbmc7XG59XG5cbi8qKiBDb25jcmV0ZSwgdmFsaWRhdGVkIGNvbmZpZyB0aGUgcnVudGltZSBkaXNwYXRjaGVzIHRocm91Z2guICovXG5leHBvcnQgdHlwZSBSZXNvbHZlZEVtYWlsQ29uZmlnID0gUmVzb2x2ZWRTbXRwQ29uZmlnIHwgUmVzb2x2ZWRGaWxlQ29uZmlnO1xuXG4vKiogSlNPTiBTY2hlbWEgcHVibGlzaGVkIG9uIHRoZSBtYW5pZmVzdCdzIGBjb25maWcuc2NoZW1hYC4gKi9cbmV4cG9ydCBjb25zdCBFTUFJTF9DT05GSUdfU0NIRU1BOiBKU09OU2NoZW1hNyA9IHtcbiAgdHlwZTogXCJvYmplY3RcIixcbiAgcHJvcGVydGllczoge1xuICAgIHNtdHA6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJTTVRQIGNvbm5lY3Rpb24gYW5kIGNyZWRlbnRpYWxzIChlbnYgZmFsbGJhY2tzOiBTTVRQXyopLlwiLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBob3N0OiB7IHR5cGU6IFwic3RyaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlNNVFAgc2VydmVyIGhvc3RuYW1lIChTTVRQX0hPU1QpLlwiIH0sXG4gICAgICAgIHBvcnQ6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgU01UUCBzZXJ2ZXIgcG9ydCAoU01UUF9QT1JUKS4gRGVmYXVsdHMgdG8gJHtERUZBVUxUX1NNVFBfUE9SVH0uYCxcbiAgICAgICAgfSxcbiAgICAgICAgc2VjdXJlOiB7XG4gICAgICAgICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBUTFMtb24tY29ubmVjdCBzb2NrZXQgKFNNVFBfU0VDVVJFKS4gRGVmYXVsdHMgdG8gcG9ydCA9PT0gJHtJTVBMSUNJVF9UTFNfU01UUF9QT1JUfS5gLFxuICAgICAgICB9LFxuICAgICAgICB1c2VyOiB7IHR5cGU6IFwic3RyaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlNNVFAgYXV0aCB1c2VybmFtZSAoU01UUF9VU0VSKS5cIiB9LFxuICAgICAgICBwYXNzd29yZDoge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiU01UUCBhdXRoIHBhc3N3b3JkIC8gQVBJIGtleSAoU01UUF9QQVNTV09SRCkuXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gICAgZG9tYWluOiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRG9tYWluIGZvciB0aGUgZGVyaXZlZCBzZW5kZXIgYWRkcmVzcyAoPHVzZXItbG9jYWwtcGFydD5APGRvbWFpbj4pLiBGYWxscyBiYWNrIHRvIEVNQUlMX0RPTUFJTi5cIixcbiAgICB9LFxuICAgIGZyb206IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJFeHBsaWNpdCBGcm9tIGFkZHJlc3M7IHNraXBzIHBlci11c2VyIGRlcml2YXRpb24uIEZhbGxzIGJhY2sgdG8gRU1BSUxfRlJPTS5cIixcbiAgICB9LFxuICAgIG91dERpcjoge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkRpcmVjdG9yeSBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrIHdoZW4gU01UUCBpcyB1bmNvbmZpZ3VyZWQuIEZhbGxzIGJhY2sgdG8gRU1BSUxfT1VUQk9YX0RJUiwgdGhlbiA8Y3dkPi90bXAuXCIsXG4gICAgfSxcbiAgICBhbGxvd2VkU2VuZGVyczoge1xuICAgICAgdHlwZTogXCJhcnJheVwiLFxuICAgICAgaXRlbXM6IHsgdHlwZTogXCJzdHJpbmdcIiB9LFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbGxvdy1saXN0IG9mIHBlcm1pdHRlZCBzZW5kZXIgKEZyb20pIHBhdHRlcm5zOiBleGFjdCBhZGRyZXNzZXMgKFwidXNlckBkb21haW4uY29tXCIpLCBkb21haW4gd2lsZGNhcmRzIChcIipAZG9tYWluLmNvbVwiKSwgb3IgXCIqXCIuIEFsc28gYWNjZXB0cyBhIGNvbW1hL3NwYWNlLXNlcGFyYXRlZCBzdHJpbmcuIEZhbGxzIGJhY2sgdG8gRU1BSUxfQUxMT1dFRF9TRU5ERVJTLiBXaGVuIGVtcHR5LCBzZW5kZXJQb2xpY3kgZGVjaWRlcy4nLFxuICAgIH0sXG4gICAgc2VuZGVyUG9saWN5OiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZW51bTogW1wiYWxsb3dsaXN0XCIsIFwidW5yZXN0cmljdGVkXCJdLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdIb3cgdGhlIHNlbmRlciBpcyByZXN0cmljdGVkIHdoZW4gYWxsb3dlZFNlbmRlcnMgaXMgZW1wdHkgKEVNQUlMX1NFTkRFUl9QT0xJQ1kpLiBcImFsbG93bGlzdFwiIChkZWZhdWx0KSBuYXJyb3dzIHNlbmRzIHRvIHRoZSBjb25maWd1cmVkIHNlbmRlciBzb3VyY2U7IFwidW5yZXN0cmljdGVkXCIgYWNjZXB0cyBhbnkgRnJvbS4nLFxuICAgIH0sXG4gICAgYnJhbmQ6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJCcmFuZCBzdHlsaW5nIGlubGluZWQgaW50byBldmVyeSByZW5kZXJlZCBtZXNzYWdlLiBPbWl0IGZvciB0aGUgbmV1dHJhbCBkZWZhdWx0IGxheW91dC5cIixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgYWNjZW50OiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0hlYWRlci1iYW5kIGJhY2tncm91bmQgYW5kIGJvZHkgbGluayBjb2xvciAoZS5nLiBcIiNGRjM2MjFcIikuJyxcbiAgICAgICAgfSxcbiAgICAgICAgb25BY2NlbnQ6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRleHQgYW5kIGxvZ28gY29sb3IgcmVuZGVyZWQgb24gdGhlIGFjY2VudCBiYW5kLiBEZWZhdWx0cyB0byB3aGl0ZS5cIixcbiAgICAgICAgfSxcbiAgICAgICAgZm9udEZhbWlseToge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdCb2R5IGZvbnQgc3RhY2sgKGUuZy4gXCJJbnRlciwgdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCBzYW5zLXNlcmlmXCIpLicsXG4gICAgICAgIH0sXG4gICAgICAgIG5hbWU6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlByb2R1Y3QgLyBkaXNwbGF5IG5hbWUgdXNlZCBhcyB0aGUgaGVhZGVyIHRleHQgYW5kIHRoZSBsb2dvIGFsdCB0ZXh0LlwiLFxuICAgICAgICB9LFxuICAgICAgICBsb2dvVXJsOiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgIFwiTG9nbyBpbWFnZSBmb3IgdGhlIGhlYWRlciBiYW5kLiBPbmx5IGFuIGh0dHAocyk6IG9yIGRhdGE6IFVSTCByZW5kZXJzOyBvdGhlciB2YWx1ZXMgYXJlIGRyb3BwZWQgYmVjYXVzZSBhIG1haWwgY2xpZW50IGNhbm5vdCBsb2FkIHRoZW0uXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgcmVxdWlyZWQ6IFtcImFjY2VudFwiLCBcImZvbnRGYW1pbHlcIl0sXG4gICAgfSxcbiAgfSxcbn07XG5cbi8qKiBQYXJzZSB0aGUgYFNNVFBfU0VDVVJFYCBlbnYgLyBjb25maWcgZmxhZywgZGVmYXVsdGluZyBieSBwb3J0LiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVNlY3VyZShmbGFnOiBib29sZWFuIHwgdW5kZWZpbmVkLCBwb3J0OiBudW1iZXIpOiBib29sZWFuIHtcbiAgaWYgKHR5cGVvZiBmbGFnID09PSBcImJvb2xlYW5cIikgcmV0dXJuIGZsYWc7XG4gIHJldHVybiBvYmplY3QudG9Cb29sZWFuKHByb2Nlc3MuZW52LlNNVFBfU0VDVVJFKSA/PyBwb3J0ID09PSBJTVBMSUNJVF9UTFNfU01UUF9QT1JUO1xufVxuXG4vKiogUGFyc2UgdGhlIGBFTUFJTF9TRU5ERVJfUE9MSUNZYCBlbnYgLyBjb25maWcgdmFsdWUsIGRlZmF1bHRpbmcgdG8gZGVueS1ieS1kZWZhdWx0LiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVNlbmRlclBvbGljeShwb2xpY3k6IFNlbmRlclBvbGljeSB8IHVuZGVmaW5lZCk6IFNlbmRlclBvbGljeSB7XG4gIGNvbnN0IHJhdyA9IHBvbGljeSA/PyBwcm9jZXNzLmVudi5FTUFJTF9TRU5ERVJfUE9MSUNZPy50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgaWYgKHJhdyA9PT0gXCJ1bnJlc3RyaWN0ZWRcIikgcmV0dXJuIFwidW5yZXN0cmljdGVkXCI7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09IFwiXCIgfHwgcmF3ID09PSBcImFsbG93bGlzdFwiKSByZXR1cm4gXCJhbGxvd2xpc3RcIjtcbiAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLmludmFsaWRWYWx1ZShcInNlbmRlclBvbGljeVwiLCByYXcsICdcImFsbG93bGlzdFwiIG9yIFwidW5yZXN0cmljdGVkXCInKTtcbn1cblxuLyoqXG4gKiBFZmZlY3RpdmUgYWxsb3ctbGlzdCBmb3IgYW4gYFwiYWxsb3dsaXN0XCJgIHBvbGljeSB3aXRoIG5vIGV4cGxpY2l0IHBhdHRlcm5zOlxuICogdGhlIHNlbmRlciBzb3VyY2UgaXRzZWxmLCBzbyBhIGNvbmZpZ3VyZWQgZG9tYWluIG9yIGZpeGVkIGFkZHJlc3MgaXMgdGhlXG4gKiBib3VuZGFyeSByYXRoZXIgdGhhbiBcImFueXRoaW5nIGdvZXNcIi4gWWllbGRzIG5vdGhpbmcgd2hlbiBuZWl0aGVyIGlzIHNldCxcbiAqIHdoaWNoIG9ubHkgaGFwcGVucyBpbiBvdXRib3ggbW9kZSAod2hlcmUgdGhlIHNlbmRlciBmYWxscyBiYWNrIHRvIHRoZVxuICogb24tYmVoYWxmLW9mIHVzZXIncyBvd24gYWRkcmVzcyBhbmQgY2Fubm90IGJlIGVudW1lcmF0ZWQgdXAgZnJvbnQpLlxuICovXG5mdW5jdGlvbiBpbXBsaWVkU2VuZGVyUGF0dGVybnMoZG9tYWluOiBzdHJpbmcgfCB1bmRlZmluZWQsIGZyb206IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZ1tdIHtcbiAgY29uc3QgcGF0dGVybnM6IHN0cmluZ1tdID0gW107XG4gIGlmIChmcm9tKSBwYXR0ZXJucy5wdXNoKGZyb20udHJpbSgpLnRvTG93ZXJDYXNlKCkpO1xuICBpZiAoZG9tYWluKSBwYXR0ZXJucy5wdXNoKGAqQCR7ZG9tYWluLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWApO1xuICByZXR1cm4gcGF0dGVybnM7XG59XG5cbi8qKiBXaGV0aGVyIGBFTUFJTF9PVVRCT1hfTU9ERWAgZXhwbGljaXRseSBvcHRzIGludG8gdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrLiAqL1xuZnVuY3Rpb24gaXNPdXRib3hNb2RlRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuRU1BSUxfT1VUQk9YX01PREUpID8/IGZhbHNlO1xufVxuXG5jb25zdCBTTVRQX1JFUVVJUkVEX0ZJRUxEUyA9IFtcIlNNVFBfSE9TVFwiLCBcIlNNVFBfVVNFUlwiLCBcIlNNVFBfUEFTU1dPUkRcIl0gYXMgY29uc3Q7XG5cbi8qKiBMaXN0IGVudiBrZXlzIGZvciBTTVRQIGZpZWxkcyB0aGF0IGFyZSB1bnNldCBpbiB0aGUgcmVzb2x2ZWQgY3JlZGVudGlhbCBzZXQuICovXG5mdW5jdGlvbiBtaXNzaW5nU210cEZpZWxkcyhcbiAgaG9zdDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICB1c2VyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHBhc3M6IHN0cmluZyB8IHVuZGVmaW5lZCxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgdmFsdWVzID0gW2hvc3QsIHVzZXIsIHBhc3NdIGFzIGNvbnN0O1xuICByZXR1cm4gU01UUF9SRVFVSVJFRF9GSUVMRFMuZmlsdGVyKChfLCBpbmRleCkgPT4gIXZhbHVlc1tpbmRleF0pO1xufVxuXG4vKipcbiAqIFJlc29sdmUgcGx1Z2luIGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzLlxuICpcbiAqIFdoZW4gU01UUCBob3N0ICsgdXNlciArIHBhc3N3b3JkIGFyZSBhbGwgcHJlc2VudCwgcmV0dXJucyBgbW9kZTpcbiAqIFwic210cFwiYCBmb3IgcmVhbCBkZWxpdmVyeSAoYW5kIHRocm93cyBpZiBubyBzZW5kZXIgc291cmNlIC0gZG9tYWluIG9yXG4gKiBmcm9tIC0gaXMgY29uZmlndXJlZCwgc2luY2UgU01UUCBjYW4ndCBkZXJpdmUgb25lIGZyb20gbm90aGluZykuXG4gKiBXaGVuIGFsbCB0aHJlZSBhcmUgYWJzZW50IGFuZCBgRU1BSUxfT1VUQk9YX01PREVgIGlzIGVuYWJsZWQsIHJldHVybnNcbiAqIGBtb2RlOiBcImZpbGVcImAgc28gdGhlIHJ1bnRpbWUgd3JpdGVzIG1lc3NhZ2VzIHRvIHRoZSBvdXRib3ggZGlyZWN0b3J5XG4gKiBmb3IgbG9jYWwgdGVzdGluZzsgaW4gdGhhdCBtb2RlIGEgc2VuZGVyIHNvdXJjZSBpcyBvcHRpb25hbCAodGhlXG4gKiBvdXRib3ggZmFsbHMgYmFjayB0byB0aGUgT0JPIHVzZXIncyBvd24gYWRkcmVzcykuIFBhcnRpYWwgU01UUFxuICogY29uZmlndXJhdGlvbiBvciBhIHNlbmQgd2l0aCBubyBjcmVkZW50aWFscyBhbmQgbm8gb3V0Ym94IG9wdC1pblxuICogdGhyb3dzLlxuICpcbiAqIFRoZSBzZW5kZXIgYWxsb3ctbGlzdCBpcyByZXNvbHZlZCBoZXJlIHRvbzogdW5kZXIgdGhlIGRlZmF1bHRcbiAqIGBcImFsbG93bGlzdFwiYCBwb2xpY3kgYW4gZW1wdHkgbGlzdCBpcyBmaWxsZWQgaW4gZnJvbSB0aGUgc2VuZGVyIHNvdXJjZSxcbiAqIHNvIGEgZGVwbG95bWVudCB0aGF0IG9ubHkgc2V0cyBgRU1BSUxfRE9NQUlOYCBzdGlsbCByZWplY3RzIGEgYEZyb21gIG9uXG4gKiBhbnkgb3RoZXIgZG9tYWluLiBTZWUge0BsaW5rIFNlbmRlclBvbGljeX0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlRW1haWxDb25maWcoY29uZmlnOiBFbWFpbFBsdWdpbkNvbmZpZyA9IHt9KTogUmVzb2x2ZWRFbWFpbENvbmZpZyB7XG4gIGNvbnN0IHNtdHAgPSBjb25maWcuc210cCA/PyB7fTtcbiAgY29uc3QgaG9zdCA9IHNtdHAuaG9zdCA/PyBwcm9jZXNzLmVudi5TTVRQX0hPU1Q7XG4gIGNvbnN0IHVzZXIgPSBzbXRwLnVzZXIgPz8gcHJvY2Vzcy5lbnYuU01UUF9VU0VSO1xuICBjb25zdCBwYXNzID0gc210cC5wYXNzd29yZCA/PyBwcm9jZXNzLmVudi5TTVRQX1BBU1NXT1JEO1xuICBjb25zdCBkb21haW4gPSBjb25maWcuZG9tYWluID8/IHByb2Nlc3MuZW52LkVNQUlMX0RPTUFJTjtcbiAgY29uc3QgZnJvbSA9IGNvbmZpZy5mcm9tID8/IHByb2Nlc3MuZW52LkVNQUlMX0ZST007XG4gIGNvbnN0IHNlbmRlclBvbGljeSA9IHJlc29sdmVTZW5kZXJQb2xpY3koY29uZmlnLnNlbmRlclBvbGljeSk7XG4gIGNvbnN0IGNvbmZpZ3VyZWRTZW5kZXJzID0gcGFyc2VBbGxvd2VkU2VuZGVycyhcbiAgICBjb25maWcuYWxsb3dlZFNlbmRlcnMgPz8gcHJvY2Vzcy5lbnYuRU1BSUxfQUxMT1dFRF9TRU5ERVJTLFxuICApO1xuICBjb25zdCBhbGxvd2VkU2VuZGVycyA9XG4gICAgY29uZmlndXJlZFNlbmRlcnMubGVuZ3RoID4gMCB8fCBzZW5kZXJQb2xpY3kgPT09IFwidW5yZXN0cmljdGVkXCJcbiAgICAgID8gY29uZmlndXJlZFNlbmRlcnNcbiAgICAgIDogaW1wbGllZFNlbmRlclBhdHRlcm5zKGRvbWFpbiwgZnJvbSk7XG4gIGNvbnN0IHNlbmRlcjogUmVzb2x2ZWRTZW5kZXIgPSB7XG4gICAgLi4uKGRvbWFpbiA/IHsgZG9tYWluIH0gOiB7fSksXG4gICAgLi4uKGZyb20gPyB7IGZyb20gfSA6IHt9KSxcbiAgICBhbGxvd2VkU2VuZGVycyxcbiAgICBzZW5kZXJQb2xpY3ksXG4gICAgLi4uKGNvbmZpZy5icmFuZCA/IHsgYnJhbmQ6IGNvbmZpZy5icmFuZCB9IDoge30pLFxuICB9O1xuXG4gIGNvbnN0IGhhc0FsbFNtdHAgPSBCb29sZWFuKGhvc3QgJiYgdXNlciAmJiBwYXNzKTtcbiAgY29uc3QgaGFzQW55U210cCA9IEJvb2xlYW4oaG9zdCB8fCB1c2VyIHx8IHBhc3MpO1xuXG4gIGlmIChoYXNBbnlTbXRwICYmICFoYXNBbGxTbXRwKSB7XG4gICAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLm1pc3NpbmdFbnZWYXJzKG1pc3NpbmdTbXRwRmllbGRzKGhvc3QsIHVzZXIsIHBhc3MpKTtcbiAgfVxuXG4gIGlmIChoYXNBbGxTbXRwKSB7XG4gICAgaWYgKCFkb21haW4gJiYgIWZyb20pIHtcbiAgICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5yZXNvdXJjZU5vdEZvdW5kKFxuICAgICAgICBcIkVtYWlsIHNlbmRlciBzb3VyY2VcIixcbiAgICAgICAgXCJTZXQgRU1BSUxfRE9NQUlOIHRvIGRlcml2ZSA8dXNlci1sb2NhbC1wYXJ0PkA8ZG9tYWluPiwgb3IgRU1BSUxfRlJPTSBmb3IgYSBmaXhlZCBhZGRyZXNzLlwiLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgcG9ydFJhdyA9IHNtdHAucG9ydCA/PyBOdW1iZXIocHJvY2Vzcy5lbnYuU01UUF9QT1JUKTtcbiAgICBjb25zdCBwb3J0ID0gTnVtYmVyLmlzRmluaXRlKHBvcnRSYXcpICYmIHBvcnRSYXcgPyBOdW1iZXIocG9ydFJhdykgOiBERUZBVUxUX1NNVFBfUE9SVDtcbiAgICByZXR1cm4ge1xuICAgICAgbW9kZTogXCJzbXRwXCIsXG4gICAgICBob3N0OiBob3N0ISxcbiAgICAgIHBvcnQsXG4gICAgICBzZWN1cmU6IHJlc29sdmVTZWN1cmUoc210cC5zZWN1cmUsIHBvcnQpLFxuICAgICAgYXV0aDogeyB1c2VyOiB1c2VyISwgcGFzczogcGFzcyEgfSxcbiAgICAgIC4uLnNlbmRlcixcbiAgICB9O1xuICB9XG5cbiAgaWYgKCFpc091dGJveE1vZGVFbmFibGVkKCkpIHtcbiAgICB0aHJvdyBDb25maWd1cmF0aW9uRXJyb3IuaW52YWxpZENvbm5lY3Rpb24oXG4gICAgICBcIlNNVFBcIixcbiAgICAgIGBTZXQgJHtTTVRQX1JFUVVJUkVEX0ZJRUxEUy5qb2luKFwiLCBcIil9LCBvciBFTUFJTF9PVVRCT1hfTU9ERT0xIHRvIHdyaXRlIG1lc3NhZ2VzIHRvIGEgbG9jYWwgb3V0Ym94IGluc3RlYWQuYCxcbiAgICApO1xuICB9XG5cbiAgY29uc3Qgb3V0RGlyID0gcmVzb2x2ZShcbiAgICBjb25maWcub3V0RGlyID8/IHByb2Nlc3MuZW52LkVNQUlMX09VVEJPWF9ESVIgPz8gcmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCBcInRtcFwiKSxcbiAgKTtcbiAgcmV0dXJuIHsgbW9kZTogXCJmaWxlXCIsIG91dERpciwgLi4uc2VuZGVyIH07XG59XG4iXX0=
|
|
264
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUF5QixNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHeEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWxELHlEQUF5RDtBQUN6RCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7QUFFckMsMkVBQTJFO0FBQzNFLE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztBQW1KMUMsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFnQjtJQUM5QyxJQUFJLEVBQUUsUUFBUTtJQUNkLFVBQVUsRUFBRTtRQUNWLElBQUksRUFBRTtZQUNKLElBQUksRUFBRSxRQUFRO1lBQ2QsV0FBVyxFQUFFLDBEQUEwRDtZQUN2RSxVQUFVLEVBQUU7Z0JBQ1YsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsbUNBQW1DLEVBQUU7Z0JBQzFFLElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsUUFBUTtvQkFDZCxXQUFXLEVBQUUsNkNBQTZDLGlCQUFpQixHQUFHO2lCQUMvRTtnQkFDRCxNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLFNBQVM7b0JBQ2YsV0FBVyxFQUFFLDZEQUE2RCxzQkFBc0IsR0FBRztpQkFDcEc7Z0JBQ0QsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsaUNBQWlDLEVBQUU7Z0JBQ3hFLFFBQVEsRUFB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QyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSyxFQUFFLElBQUksRUFBRSxJQUFLLEVBQUU7WUFDbEMsR0FBRyxNQUFNO1NBQ1YsQ0FBQztJQUNKLENBQUM7SUFFRCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDO1FBQzNCLE1BQU0sa0JBQWtCLENBQUMsaUJBQWlCLENBQ3hDLE1BQU0sRUFDTixPQUFPLG9CQUFvQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQzlHLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUNwQixNQUFNLENBQUMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FDL0UsQ0FBQztJQUNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO0FBQzdDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNNVFAgY29uZmlndXJhdGlvbiBmb3IgdGhlIGVtYWlsIHBsdWdpbjogdGhlIHR5cGVkXG4gKiB7QGxpbmsgRW1haWxQbHVnaW5Db25maWd9ICh0aGUgcGx1Z2luJ3Mgc2xpY2Ugb2YgQXBwS2l0IGNvbmZpZyksIHRoZVxuICogSlNPTiBTY2hlbWEgdGhlIG1hbmlmZXN0IHB1Ymxpc2hlcyBmb3IgaXQsIGFuZCB7QGxpbmsgcmVzb2x2ZUVtYWlsQ29uZmlnfVxuICogd2hpY2ggbGF5ZXJzIHRoYXQgY29uZmlnIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMgaW50byB0aGUgY29uY3JldGVcbiAqIHtAbGluayBSZXNvbHZlZEVtYWlsQ29uZmlnfSB0aGUgcnVudGltZSBuZWVkcy5cbiAqXG4gKiBUd28gbW9kZXMgZmFsbCBvdXQgb2YgdGhlIHJlc29sdXRpb24uIFdoZW4gU01UUCBjcmVkZW50aWFscyAoaG9zdCArXG4gKiB1c2VyICsgcGFzc3dvcmQpIGFyZSBhbGwgcHJlc2VudCBpdCByZXNvbHZlcyB0byBgbW9kZTogXCJzbXRwXCJgIGFuZFxuICogbWFpbCBpcyBzZW50IGZvciByZWFsLiBXaGVuIHRoZXkgYXJlIGFic2VudCBhbmQgYEVNQUlMX09VVEJPWF9NT0RFYFxuICogaXMgZXhwbGljaXRseSBlbmFibGVkIGl0IHJlc29sdmVzIHRvIGBtb2RlOiBcImZpbGVcImAgKGFuIFwib3V0Ym94XCIpXG4gKiBhbmQgZWFjaCBtZXNzYWdlIGlzIHdyaXR0ZW4gdG8gZGlzayBhcyBIVE1MIGluc3RlYWQgb2Ygc2VudC4gQW55XG4gKiBwYXJ0aWFsIFNNVFAgY29uZmlndXJhdGlvbiBvciBhIHNlbmQgYXR0ZW1wdCB3aXRoIG5vIGNyZWRlbnRpYWxzIGFuZFxuICogbm8gb3V0Ym94IG9wdC1pbiB0aHJvd3MuXG4gKlxuICogUHJlY2VkZW5jZSBwZXIgZmllbGQ6IGV4cGxpY2l0IHBsdWdpbiBjb25maWcgd2lucywgdGhlbiB0aGUgbWF0Y2hpbmdcbiAqIGVudmlyb25tZW50IHZhcmlhYmxlLiBFbnYgbmFtZXMgYXJlIHVucHJlZml4ZWQgYmVjYXVzZSB0aGUgYXBwIHRhbGtzXG4gKiB0byBhIHNpbmdsZSBTTVRQIHNlcnZlciAoZS5nLiBTTVRQMkdPKTogYFNNVFBfSE9TVGAsIGBTTVRQX1BPUlRgLFxuICogYFNNVFBfU0VDVVJFYCwgYFNNVFBfVVNFUmAsIGBTTVRQX1BBU1NXT1JEYCwgcGx1cyBgRU1BSUxfRE9NQUlOYCBmb3JcbiAqIHRoZSBkZXJpdmVkIHNlbmRlcidzIGRvbWFpbiwgYEVNQUlMX0ZST01gIGZvciBhbiBleHBsaWNpdCBvdmVycmlkZSxcbiAqIGBFTUFJTF9TRU5ERVJfUE9MSUNZYCBmb3IgdGhlIHNlbmRlciByZXN0cmljdGlvbiBtb2RlLCBhbmRcbiAqIGBFTUFJTF9PVVRCT1hfRElSYCBmb3IgdGhlIG91dGJveCBkaXJlY3RvcnkuXG4gKlxuICogQG1vZHVsZVxuICovXG5pbXBvcnQgeyByZXNvbHZlIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvbkVycm9yLCBWYWxpZGF0aW9uRXJyb3IsIHR5cGUgQmFzZVBsdWdpbkNvbmZpZyB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgSlNPTlNjaGVtYTcgfSBmcm9tIFwianNvbi1zY2hlbWFcIjtcbmltcG9ydCB0eXBlIHsgRW1haWxCcmFuZCB9IGZyb20gXCIuL2JyYW5kLnRzXCI7XG5pbXBvcnQgeyBwYXJzZUFsbG93ZWRTZW5kZXJzIH0gZnJvbSBcIi4vc2VuZGVyLnRzXCI7XG5cbi8qKiBTTVRQIHN1Ym1pc3Npb24gcG9ydCB1c2VkIHdoZW4gbm9uZSBpcyBjb25maWd1cmVkLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU01UUF9QT1JUID0gNTg3O1xuXG4vKiogU01UUCBwb3J0IHRoYXQgaW1wbGllcyBhIFRMUy1vbi1jb25uZWN0IHNvY2tldCByYXRoZXIgdGhhbiBTVEFSVFRMUy4gKi9cbmV4cG9ydCBjb25zdCBJTVBMSUNJVF9UTFNfU01UUF9QT1JUID0gNDY1O1xuXG4vKipcbiAqIEhvdyB0aGUgc2VuZGVyIChgRnJvbWApIGFkZHJlc3MgaXMgcmVzdHJpY3RlZC5cbiAqXG4gKiBgXCJhbGxvd2xpc3RcImAgaXMgdGhlIGRlZmF1bHQgYW5kIHRoZSBkZW55LWJ5LWRlZmF1bHQgcG9zdHVyZTogYSBzZW5kIGlzXG4gKiBwZXJtaXR0ZWQgb25seSBmcm9tIGFuIGFkZHJlc3MgdGhlIGNvbmZpZ3VyYXRpb24gbmFtZXMsIGVpdGhlciB0aHJvdWdoXG4gKiB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuYWxsb3dlZFNlbmRlcnN9IG9yLCB3aGVuIHRoYXQgaXMgZW1wdHksIHRocm91Z2hcbiAqIHRoZSBjb25maWd1cmVkIHNlbmRlciBzb3VyY2UgKHtAbGluayBFbWFpbFBsdWdpbkNvbmZpZy5mcm9tfSBhcyBhbiBleGFjdFxuICogYWRkcmVzcywge0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnLmRvbWFpbn0gYXMgYSBgKkBkb21haW5gIHdpbGRjYXJkKS5cbiAqXG4gKiBgXCJ1bnJlc3RyaWN0ZWRcImAgaXMgdGhlIGV4cGxpY2l0IG9wdC1vdXQ6IGFueSBgRnJvbWAgYSBjYWxsZXIgc3VwcGxpZXMgaXNcbiAqIGFjY2VwdGVkLiBPbmx5IHJlYWNoIGZvciBpdCB3aGVuIGFuIHVwc3RyZWFtIHN5c3RlbSBhbHJlYWR5IHZldHMgdGhlXG4gKiBzZW5kZXIuXG4gKi9cbmV4cG9ydCB0eXBlIFNlbmRlclBvbGljeSA9IFwiYWxsb3dsaXN0XCIgfCBcInVucmVzdHJpY3RlZFwiO1xuXG4vKiogU01UUCBjb25uZWN0aW9uICsgY3JlZGVudGlhbHMuIEFsbCBmaWVsZHMgZmFsbCBiYWNrIHRvIGVudiB3aGVuIHVuc2V0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTbXRwQ29uZmlnIHtcbiAgLyoqIFNNVFAgc2VydmVyIGhvc3RuYW1lIChgU01UUF9IT1NUYCkuICovXG4gIGhvc3Q/OiBzdHJpbmc7XG4gIC8qKiBTTVRQIHNlcnZlciBwb3J0IChgU01UUF9QT1JUYCkuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX1NNVFBfUE9SVH0uICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBVc2UgYSBUTFMtb24tY29ubmVjdCBzb2NrZXQgKGBTTVRQX1NFQ1VSRWApLiBEZWZhdWx0cyB0b1xuICAgKiBgcG9ydCA9PT0gYCB7QGxpbmsgSU1QTElDSVRfVExTX1NNVFBfUE9SVH0uXG4gICAqL1xuICBzZWN1cmU/OiBib29sZWFuO1xuICAvKiogU01UUCBhdXRoIHVzZXJuYW1lIChgU01UUF9VU0VSYCkuICovXG4gIHVzZXI/OiBzdHJpbmc7XG4gIC8qKiBTTVRQIGF1dGggcGFzc3dvcmQgLyBBUEkga2V5IChgU01UUF9QQVNTV09SRGApLiAqL1xuICBwYXNzd29yZD86IHN0cmluZztcbn1cblxuLyoqIEFwcEtpdCBjb25maWcgYWNjZXB0ZWQgYnkgdGhlIGVtYWlsIHBsdWdpbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW1haWxQbHVnaW5Db25maWcgZXh0ZW5kcyBCYXNlUGx1Z2luQ29uZmlnIHtcbiAgLyoqIFNNVFAgY29ubmVjdGlvbiArIGNyZWRlbnRpYWxzLiBPbWl0IHRvIHJ1biBpbiBmaWxlL291dGJveCBtb2RlLiAqL1xuICBzbXRwPzogU210cENvbmZpZztcbiAgLyoqXG4gICAqIERvbWFpbiB1c2VkIHRvIGJ1aWxkIHRoZSBzZW5kZXIgYWRkcmVzcyBmcm9tIHRoZSBvbi1iZWhhbGYtb2YgdXNlclxuICAgKiAoYDxsb2NhbC1wYXJ0PkA8ZG9tYWluPmApLiBGYWxscyBiYWNrIHRvIGBFTUFJTF9ET01BSU5gLiBSZXF1aXJlZCBpblxuICAgKiBTTVRQIG1vZGUgdW5sZXNzIHtAbGluayBmcm9tfSBpcyBzZXQ7IG9wdGlvbmFsIGluIGZpbGUgbW9kZSAodGhlXG4gICAqIG91dGJveCBmYWxscyBiYWNrIHRvIHRoZSB1c2VyJ3Mgb3duIGVtYWlsIGFkZHJlc3MpLlxuICAgKi9cbiAgZG9tYWluPzogc3RyaW5nO1xuICAvKipcbiAgICogRXhwbGljaXQgYEZyb21gIGFkZHJlc3MuIFdoZW4gc2V0LCB0aGUgc2VuZGVyIGlzIHVzZWQgdmVyYmF0aW0gYW5kXG4gICAqIHRoZSBwZXItdXNlciBkZXJpdmF0aW9uIGlzIHNraXBwZWQuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0ZST01gLlxuICAgKi9cbiAgZnJvbT86IHN0cmluZztcbiAgLyoqXG4gICAqIERpcmVjdG9yeSBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrLiBGYWxscyBiYWNrIHRvXG4gICAqIGBFTUFJTF9PVVRCT1hfRElSYCwgdGhlbiBgPGN3ZD4vdG1wYC4gT25seSB1c2VkIHdoZW4gU01UUFxuICAgKiBjcmVkZW50aWFscyBhcmUgYWJzZW50LlxuICAgKi9cbiAgb3V0RGlyPzogc3RyaW5nO1xuICAvKipcbiAgICogQWxsb3ctbGlzdCByZXN0cmljdGluZyB0aGUgc2VuZGVyIChgRnJvbWApIGFkZHJlc3MuIEVhY2ggZW50cnkgaXMgYW5cbiAgICogZXhhY3QgYWRkcmVzcyAoYHVzZXJAZG9tYWluLmNvbWApLCBhIGRvbWFpbiB3aWxkY2FyZCAoYCpAZG9tYWluLmNvbWBcbiAgICogb3IgdGhlIGJhcmUgYGRvbWFpbi5jb21gLCBtYXRjaGluZyBhbnkgbG9jYWwgcGFydCBvbiB0aGF0IGRvbWFpbiksIG9yXG4gICAqIGAqYCAoYW55KS4gQSByZXNvbHZlZCAvIGNob3NlbiBzZW5kZXIgdGhhdCBtYXRjaGVzIG5vIGVudHJ5IGlzXG4gICAqIHJlamVjdGVkIGF0IHNlbmQgdGltZS4gQWNjZXB0cyBhIGBzdHJpbmdbXWAgb3IgYSBzaW5nbGUgY29tbWEtIC9cbiAgICogd2hpdGVzcGFjZS1zZXBhcmF0ZWQgc3RyaW5nOyBmYWxscyBiYWNrIHRvIGBFTUFJTF9BTExPV0VEX1NFTkRFUlNgLlxuICAgKiBXaGVuIGVtcHR5LCB0aGUge0BsaW5rIHNlbmRlclBvbGljeX0gZGVjaWRlcyB3aGF0IGlzIHBlcm1pdHRlZC5cbiAgICovXG4gIGFsbG93ZWRTZW5kZXJzPzogc3RyaW5nIHwgc3RyaW5nW107XG4gIC8qKlxuICAgKiBIb3cgdGhlIHNlbmRlciBhZGRyZXNzIGlzIHJlc3RyaWN0ZWQgd2hlbiB7QGxpbmsgYWxsb3dlZFNlbmRlcnN9IGlzXG4gICAqIGVtcHR5IChgRU1BSUxfU0VOREVSX1BPTElDWWApLiBEZWZhdWx0cyB0byBgXCJhbGxvd2xpc3RcImAsIHdoaWNoXG4gICAqIG5hcnJvd3Mgc2VuZHMgdG8gdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZS4gU2VlXG4gICAqIHtAbGluayBTZW5kZXJQb2xpY3l9LlxuICAgKi9cbiAgc2VuZGVyUG9saWN5PzogU2VuZGVyUG9saWN5O1xuICAvKipcbiAgICogT3B0aW9uYWwgYnJhbmQgc3R5bGluZyAoYWNjZW50LCBmb250LCBoZWFkZXIgbG9nbykgYXBwbGllZCB0byB0aGVcbiAgICogcmVuZGVyZWQgSFRNTCBvZiBldmVyeSBtZXNzYWdlLiBPbWl0IGZvciB0aGUgbmV1dHJhbCBkZWZhdWx0IGxheW91dC5cbiAgICogUGFzcyB7QGxpbmsgZW1haWxCcmFuZEZyb21Db250ZXh0fSB0byBkZXJpdmUgaXQgZnJvbSBhIHNoYXJlZFxuICAgKiBgQnJhbmRDb250ZXh0YC5cbiAgICovXG4gIGJyYW5kPzogRW1haWxCcmFuZDtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGVtYWlsLU9UUCBBQ0NFU1MgR0FURS4gV2hlbiBgZW5hYmxlZGAsIHRoZSBwbHVnaW4gbW91bnRzIGEgbG9naW5cbiAgICogZmxvdyAoYC9hcGkvZW1haWwvYXV0aC8qYCkgYW5kIGdhdGVzIGV2ZXJ5IG90aGVyIHJvdXRlIGJlaGluZCBhIHNlc3Npb25cbiAgICogY29va2llIC0gdGhlIGZyb250IGRvb3IgZm9yIGFuIGFwcCBleHBvc2VkIHB1YmxpY2x5IChlLmcuIHRocm91Z2ggYSBwb3J0clxuICAgKiB0dW5uZWwgdGhhdCBieXBhc3NlcyB0aGUgRGF0YWJyaWNrcyBPQXV0aCBwcm94eSkuIFJldXNlcyB0aGlzIHBsdWdpbidzXG4gICAqIHRyYW5zcG9ydCB0byBlbWFpbCB0aGUgY29kZS4gT21pdCBvciBgZW5hYmxlZDogZmFsc2VgIHRvIGxlYXZlIHRoZSBhcHAgb3Blbi5cbiAgICovXG4gIGF1dGg/OiBBdXRoQ29uZmlnO1xufVxuXG4vKiogRW1haWwtT1RQIGFjY2Vzcy1nYXRlIGNvbmZpZ3VyYXRpb24gKHNlZSB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuYXV0aH0pLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoQ29uZmlnIHtcbiAgLyoqIFR1cm4gdGhlIGdhdGUgb24uIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0FVVEhfRU5BQkxFRGAuIERlZmF1bHQgb2ZmLiAqL1xuICBlbmFibGVkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdobyBtYXkgcmVxdWVzdCBhIGNvZGUuIEVhY2ggZW50cnkgaXMgYSBkb21haW4gc2hvcnRjdXQgKGBkYXRhYnJpY2tzLmNvbWBcbiAgICogb3IgYEBkYXRhYnJpY2tzLmNvbWApLCBhIGdsb2IgKGAqLmRhdGFicmlja3MuY29tYCksIG9yIGEgYC9yZWdleC9gLiBBblxuICAgKiBFTVBUWSBsaXN0IGFsbG93cyBub2JvZHkgKGZhaWwgY2xvc2VkKS4gRmFsbHMgYmFjayB0byBgRU1BSUxfQVVUSF9BTExPV2BcbiAgICogKGNvbW1hL3NwYWNlLXNlcGFyYXRlZCkuXG4gICAqL1xuICBhbGxvdz86IHN0cmluZyB8IHN0cmluZ1tdO1xuICAvKiogU2Vzc2lvbiBsaWZldGltZSAoc2Vjb25kcykuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0FVVEhfU0VTU0lPTl9UVExgLiBEZWZhdWx0IDQzMjAwICgxMmgpLiAqL1xuICBzZXNzaW9uVHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqIE9uZS10aW1lLWNvZGUgbGlmZXRpbWUgKHNlY29uZHMpLiBGYWxscyBiYWNrIHRvIGBFTUFJTF9BVVRIX0NPREVfVFRMYC4gRGVmYXVsdCA2MDAgKDEwbSkuICovXG4gIGNvZGVUdGxTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogTWF4IHZlcmlmeSBhdHRlbXB0cyBwZXIgaXNzdWVkIGNvZGUuIERlZmF1bHQgNS4gKi9cbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG59XG5cbi8qKiBDb25maWcgc2hhcmVkIGJ5IGJvdGggcmVzb2x2ZWQgbW9kZXMuICovXG5pbnRlcmZhY2UgUmVzb2x2ZWRTZW5kZXIge1xuICAvKiogU2VuZGVyIGRvbWFpbjsgcHJlc2VudCB3aGVuZXZlciB7QGxpbmsgZnJvbX0gaXMgYWJzZW50LiAqL1xuICBkb21haW4/OiBzdHJpbmc7XG4gIC8qKiBFeHBsaWNpdCBzZW5kZXIgb3ZlcnJpZGU7IHByZXNlbnQgc2tpcHMgcGVyLXVzZXIgZGVyaXZhdGlvbi4gKi9cbiAgZnJvbT86IHN0cmluZztcbiAgLyoqXG4gICAqIEVmZmVjdGl2ZSBzZW5kZXIgYWxsb3ctbGlzdDogdGhlIGNvbmZpZ3VyZWQgcGF0dGVybnMgd2hlbiBhbnkgd2VyZVxuICAgKiBnaXZlbiwgZWxzZSB0aGUgcGF0dGVybnMgaW1wbGllZCBieSB0aGUgc2VuZGVyIHNvdXJjZSB1bmRlciBhblxuICAgKiBgXCJhbGxvd2xpc3RcImAgcG9saWN5LiBFbXB0eSBtZWFucyB1bmVuZm9yY2VhYmxlIChhbiBgXCJ1bnJlc3RyaWN0ZWRcImBcbiAgICogcG9saWN5LCBvciBhbiBvdXRib3ggd2l0aCBubyBzZW5kZXIgc291cmNlIHRvIG5hcnJvdyB0bykuXG4gICAqL1xuICBhbGxvd2VkU2VuZGVyczogc3RyaW5nW107XG4gIC8qKiBUaGUgcmVzdHJpY3Rpb24gbW9kZSB0aGUgYWxsb3ctbGlzdCB3YXMgcmVzb2x2ZWQgdW5kZXIuICovXG4gIHNlbmRlclBvbGljeTogU2VuZGVyUG9saWN5O1xuICAvKiogQnJhbmQgc3R5bGluZyBhcHBsaWVkIHRvIHJlbmRlcmVkIEhUTUw7IGFic2VudCBmb3IgdGhlIGRlZmF1bHQgbGF5b3V0LiAqL1xuICBicmFuZD86IEVtYWlsQnJhbmQ7XG59XG5cbi8qKiBSZXNvbHZlZCBjb25maWcgZm9yIHJlYWwgU01UUCBkZWxpdmVyeS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRTbXRwQ29uZmlnIGV4dGVuZHMgUmVzb2x2ZWRTZW5kZXIge1xuICBtb2RlOiBcInNtdHBcIjtcbiAgaG9zdDogc3RyaW5nO1xuICBwb3J0OiBudW1iZXI7XG4gIHNlY3VyZTogYm9vbGVhbjtcbiAgYXV0aDogeyB1c2VyOiBzdHJpbmc7IHBhc3M6IHN0cmluZyB9O1xufVxuXG4vKiogUmVzb2x2ZWQgY29uZmlnIGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2sgKG5vIFNNVFAgY3JlZGVudGlhbHMpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZEZpbGVDb25maWcgZXh0ZW5kcyBSZXNvbHZlZFNlbmRlciB7XG4gIG1vZGU6IFwiZmlsZVwiO1xuICAvKiogQWJzb2x1dGUgZGlyZWN0b3J5IG1lc3NhZ2VzIGFyZSB3cml0dGVuIHVuZGVyLiAqL1xuICBvdXREaXI6IHN0cmluZztcbn1cblxuLyoqIENvbmNyZXRlLCB2YWxpZGF0ZWQgY29uZmlnIHRoZSBydW50aW1lIGRpc3BhdGNoZXMgdGhyb3VnaC4gKi9cbmV4cG9ydCB0eXBlIFJlc29sdmVkRW1haWxDb25maWcgPSBSZXNvbHZlZFNtdHBDb25maWcgfCBSZXNvbHZlZEZpbGVDb25maWc7XG5cbi8qKiBKU09OIFNjaGVtYSBwdWJsaXNoZWQgb24gdGhlIG1hbmlmZXN0J3MgYGNvbmZpZy5zY2hlbWFgLiAqL1xuZXhwb3J0IGNvbnN0IEVNQUlMX0NPTkZJR19TQ0hFTUE6IEpTT05TY2hlbWE3ID0ge1xuICB0eXBlOiBcIm9iamVjdFwiLFxuICBwcm9wZXJ0aWVzOiB7XG4gICAgc210cDoge1xuICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlNNVFAgY29ubmVjdGlvbiBhbmQgY3JlZGVudGlhbHMgKGVudiBmYWxsYmFja3M6IFNNVFBfKikuXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGhvc3Q6IHsgdHlwZTogXCJzdHJpbmdcIiwgZGVzY3JpcHRpb246IFwiU01UUCBzZXJ2ZXIgaG9zdG5hbWUgKFNNVFBfSE9TVCkuXCIgfSxcbiAgICAgICAgcG9ydDoge1xuICAgICAgICAgIHR5cGU6IFwibnVtYmVyXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBTTVRQIHNlcnZlciBwb3J0IChTTVRQX1BPUlQpLiBEZWZhdWx0cyB0byAke0RFRkFVTFRfU01UUF9QT1JUfS5gLFxuICAgICAgICB9LFxuICAgICAgICBzZWN1cmU6IHtcbiAgICAgICAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogYFRMUy1vbi1jb25uZWN0IHNvY2tldCAoU01UUF9TRUNVUkUpLiBEZWZhdWx0cyB0byBwb3J0ID09PSAke0lNUExJQ0lUX1RMU19TTVRQX1BPUlR9LmAsXG4gICAgICAgIH0sXG4gICAgICAgIHVzZXI6IHsgdHlwZTogXCJzdHJpbmdcIiwgZGVzY3JpcHRpb246IFwiU01UUCBhdXRoIHVzZXJuYW1lIChTTVRQX1VTRVIpLlwiIH0sXG4gICAgICAgIHBhc3N3b3JkOiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTTVRQIGF1dGggcGFzc3dvcmQgLyBBUEkga2V5IChTTVRQX1BBU1NXT1JEKS5cIixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgICBkb21haW46IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJEb21haW4gZm9yIHRoZSBkZXJpdmVkIHNlbmRlciBhZGRyZXNzICg8dXNlci1sb2NhbC1wYXJ0PkA8ZG9tYWluPikuIEZhbGxzIGJhY2sgdG8gRU1BSUxfRE9NQUlOLlwiLFxuICAgIH0sXG4gICAgZnJvbToge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkV4cGxpY2l0IEZyb20gYWRkcmVzczsgc2tpcHMgcGVyLXVzZXIgZGVyaXZhdGlvbi4gRmFsbHMgYmFjayB0byBFTUFJTF9GUk9NLlwiLFxuICAgIH0sXG4gICAgb3V0RGlyOiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRGlyZWN0b3J5IGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2sgd2hlbiBTTVRQIGlzIHVuY29uZmlndXJlZC4gRmFsbHMgYmFjayB0byBFTUFJTF9PVVRCT1hfRElSLCB0aGVuIDxjd2Q+L3RtcC5cIixcbiAgICB9LFxuICAgIGFsbG93ZWRTZW5kZXJzOiB7XG4gICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICBpdGVtczogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FsbG93LWxpc3Qgb2YgcGVybWl0dGVkIHNlbmRlciAoRnJvbSkgcGF0dGVybnM6IGV4YWN0IGFkZHJlc3NlcyAoXCJ1c2VyQGRvbWFpbi5jb21cIiksIGRvbWFpbiB3aWxkY2FyZHMgKFwiKkBkb21haW4uY29tXCIpLCBvciBcIipcIi4gQWxzbyBhY2NlcHRzIGEgY29tbWEvc3BhY2Utc2VwYXJhdGVkIHN0cmluZy4gRmFsbHMgYmFjayB0byBFTUFJTF9BTExPV0VEX1NFTkRFUlMuIFdoZW4gZW1wdHksIHNlbmRlclBvbGljeSBkZWNpZGVzLicsXG4gICAgfSxcbiAgICBzZW5kZXJQb2xpY3k6IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBlbnVtOiBbXCJhbGxvd2xpc3RcIiwgXCJ1bnJlc3RyaWN0ZWRcIl0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0hvdyB0aGUgc2VuZGVyIGlzIHJlc3RyaWN0ZWQgd2hlbiBhbGxvd2VkU2VuZGVycyBpcyBlbXB0eSAoRU1BSUxfU0VOREVSX1BPTElDWSkuIFwiYWxsb3dsaXN0XCIgKGRlZmF1bHQpIG5hcnJvd3Mgc2VuZHMgdG8gdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZTsgXCJ1bnJlc3RyaWN0ZWRcIiBhY2NlcHRzIGFueSBGcm9tLicsXG4gICAgfSxcbiAgICBicmFuZDoge1xuICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkJyYW5kIHN0eWxpbmcgaW5saW5lZCBpbnRvIGV2ZXJ5IHJlbmRlcmVkIG1lc3NhZ2UuIE9taXQgZm9yIHRoZSBuZXV0cmFsIGRlZmF1bHQgbGF5b3V0LlwiLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBhY2NlbnQ6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnSGVhZGVyLWJhbmQgYmFja2dyb3VuZCBhbmQgYm9keSBsaW5rIGNvbG9yIChlLmcuIFwiI0ZGMzYyMVwiKS4nLFxuICAgICAgICB9LFxuICAgICAgICBvbkFjY2VudDoge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiVGV4dCBhbmQgbG9nbyBjb2xvciByZW5kZXJlZCBvbiB0aGUgYWNjZW50IGJhbmQuIERlZmF1bHRzIHRvIHdoaXRlLlwiLFxuICAgICAgICB9LFxuICAgICAgICBmb250RmFtaWx5OiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0JvZHkgZm9udCBzdGFjayAoZS5nLiBcIkludGVyLCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIHNhbnMtc2VyaWZcIikuJyxcbiAgICAgICAgfSxcbiAgICAgICAgbmFtZToge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiUHJvZHVjdCAvIGRpc3BsYXkgbmFtZSB1c2VkIGFzIHRoZSBoZWFkZXIgdGV4dCBhbmQgdGhlIGxvZ28gYWx0IHRleHQuXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ29Vcmw6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgXCJMb2dvIGltYWdlIGZvciB0aGUgaGVhZGVyIGJhbmQuIE9ubHkgYW4gaHR0cChzKTogb3IgZGF0YTogVVJMIHJlbmRlcnM7IG90aGVyIHZhbHVlcyBhcmUgZHJvcHBlZCBiZWNhdXNlIGEgbWFpbCBjbGllbnQgY2Fubm90IGxvYWQgdGhlbS5cIixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICByZXF1aXJlZDogW1wiYWNjZW50XCIsIFwiZm9udEZhbWlseVwiXSxcbiAgICB9LFxuICAgIGF1dGg6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJFbWFpbC1PVFAgYWNjZXNzIGdhdGUuIFdoZW4gZW5hYmxlZCwgbW91bnRzIGEgbG9naW4gZmxvdyBhdCAvYXBpL2VtYWlsL2F1dGgvKiBhbmQgZ2F0ZXMgZXZlcnkgb3RoZXIgcm91dGUgYmVoaW5kIGEgc2Vzc2lvbiBjb29raWUuXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGVuYWJsZWQ6IHtcbiAgICAgICAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUdXJuIHRoZSBnYXRlIG9uIChlbnYgRU1BSUxfQVVUSF9FTkFCTEVEKS4gRGVmYXVsdCBvZmYuXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGFsbG93OiB7XG4gICAgICAgICAgdHlwZTogXCJhcnJheVwiLFxuICAgICAgICAgIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICdBbGxvdy1saXN0IG9mIHdobyBtYXkgcmVxdWVzdCBhIGNvZGU6IGRvbWFpbiBzaG9ydGN1dCAoXCJkYXRhYnJpY2tzLmNvbVwiKSwgZ2xvYiAoXCIqLmRhdGFicmlja3MuY29tXCIpLCBvciBcIi9yZWdleC9cIi4gRW1wdHkgPSBub2JvZHkuIEFsc28gYWNjZXB0cyBhIGNvbW1hL3NwYWNlLXNlcGFyYXRlZCBzdHJpbmcuIEVudiBFTUFJTF9BVVRIX0FMTE9XLicsXG4gICAgICAgIH0sXG4gICAgICAgIHNlc3Npb25UdGxTZWNvbmRzOiB7XG4gICAgICAgICAgdHlwZTogXCJudW1iZXJcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTZXNzaW9uIGxpZmV0aW1lIGluIHNlY29uZHMgKGVudiBFTUFJTF9BVVRIX1NFU1NJT05fVFRMKS4gRGVmYXVsdCA0MzIwMC5cIixcbiAgICAgICAgfSxcbiAgICAgICAgY29kZVR0bFNlY29uZHM6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk9uZS10aW1lLWNvZGUgbGlmZXRpbWUgaW4gc2Vjb25kcyAoZW52IEVNQUlMX0FVVEhfQ09ERV9UVEwpLiBEZWZhdWx0IDYwMC5cIixcbiAgICAgICAgfSxcbiAgICAgICAgbWF4QXR0ZW1wdHM6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk1heCB2ZXJpZnkgYXR0ZW1wdHMgcGVyIGlzc3VlZCBjb2RlLiBEZWZhdWx0IDUuXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0sXG59O1xuXG4vKiogUmVzb2x2ZWQgZW1haWwtT1RQIGdhdGUgY29uZmlnLCB3aXRoIGVudiBmYWxsYmFja3MgYXBwbGllZCAob3IgYHVuZGVmaW5lZGAgd2hlbiBvZmYpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZEF1dGhDb25maWcge1xuICByZWFkb25seSBhbGxvdzogc3RyaW5nW107XG4gIHJlYWRvbmx5IHNlc3Npb25UdGxTZWNvbmRzOiBudW1iZXI7XG4gIHJlYWRvbmx5IGNvZGVUdGxTZWNvbmRzOiBudW1iZXI7XG4gIHJlYWRvbmx5IG1heEF0dGVtcHRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB7QGxpbmsgQXV0aENvbmZpZ30gYWdhaW5zdCBlbnYsIHJldHVybmluZyBgdW5kZWZpbmVkYCB3aGVuIHRoZSBnYXRlIGlzXG4gKiBvZmYuIGBlbmFibGVkYCBnYXRlcyBldmVyeXRoaW5nOyBgYWxsb3dgIG1lcmdlcyB0aGUgY29uZmlnIGxpc3QgKyBlbnZcbiAqIChgcGFyc2VMaXN0YCBoYW5kbGVzIGEgYHN0cmluZ1tdYCBvciBhIGRlbGltaXRlZCBzdHJpbmcpLiBFbXB0eSBgYWxsb3dgIGlzXG4gKiBhbGxvd2VkIGhlcmUgKHRoZSBnYXRlIHRoZW4gZGVuaWVzIGV2ZXJ5b25lIC0gYSBkZWxpYmVyYXRlIGZhaWwtY2xvc2VkIHN0YXRlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBdXRoQ29uZmlnKGF1dGg6IEF1dGhDb25maWcgfCB1bmRlZmluZWQpOiBSZXNvbHZlZEF1dGhDb25maWcgfCB1bmRlZmluZWQge1xuICBjb25zdCBlbmFibGVkID0gYXV0aD8uZW5hYmxlZCA/PyBvYmplY3QudG9Cb29sZWFuKHByb2Nlc3MuZW52LkVNQUlMX0FVVEhfRU5BQkxFRCkgPz8gZmFsc2U7XG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgYWxsb3cgPSBbXG4gICAgLi4uc3RyaW5nLnBhcnNlTGlzdChhdXRoPy5hbGxvdyksXG4gICAgLi4uc3RyaW5nLnBhcnNlTGlzdChwcm9jZXNzLmVudi5FTUFJTF9BVVRIX0FMTE9XKSxcbiAgXTtcbiAgY29uc3QgbnVtID0gKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGVudjogc3RyaW5nIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyID0+IHtcbiAgICBjb25zdCByYXcgPSB2YWx1ZSA/PyAoZW52ID8gTnVtYmVyKGVudikgOiB1bmRlZmluZWQpO1xuICAgIHJldHVybiB0eXBlb2YgcmF3ID09PSBcIm51bWJlclwiICYmIE51bWJlci5pc0Zpbml0ZShyYXcpICYmIHJhdyA+IDAgPyByYXcgOiBmYWxsYmFjaztcbiAgfTtcbiAgcmV0dXJuIHtcbiAgICBhbGxvdyxcbiAgICBzZXNzaW9uVHRsU2Vjb25kczogbnVtKGF1dGg/LnNlc3Npb25UdGxTZWNvbmRzLCBwcm9jZXNzLmVudi5FTUFJTF9BVVRIX1NFU1NJT05fVFRMLCA0MzIwMCksXG4gICAgY29kZVR0bFNlY29uZHM6IG51bShhdXRoPy5jb2RlVHRsU2Vjb25kcywgcHJvY2Vzcy5lbnYuRU1BSUxfQVVUSF9DT0RFX1RUTCwgNjAwKSxcbiAgICBtYXhBdHRlbXB0czogYXV0aD8ubWF4QXR0ZW1wdHMgPz8gNSxcbiAgfTtcbn1cblxuLyoqIFBhcnNlIHRoZSBgU01UUF9TRUNVUkVgIGVudiAvIGNvbmZpZyBmbGFnLCBkZWZhdWx0aW5nIGJ5IHBvcnQuICovXG5mdW5jdGlvbiByZXNvbHZlU2VjdXJlKGZsYWc6IGJvb2xlYW4gfCB1bmRlZmluZWQsIHBvcnQ6IG51bWJlcik6IGJvb2xlYW4ge1xuICBpZiAodHlwZW9mIGZsYWcgPT09IFwiYm9vbGVhblwiKSByZXR1cm4gZmxhZztcbiAgcmV0dXJuIG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuU01UUF9TRUNVUkUpID8/IHBvcnQgPT09IElNUExJQ0lUX1RMU19TTVRQX1BPUlQ7XG59XG5cbi8qKiBQYXJzZSB0aGUgYEVNQUlMX1NFTkRFUl9QT0xJQ1lgIGVudiAvIGNvbmZpZyB2YWx1ZSwgZGVmYXVsdGluZyB0byBkZW55LWJ5LWRlZmF1bHQuICovXG5mdW5jdGlvbiByZXNvbHZlU2VuZGVyUG9saWN5KHBvbGljeTogU2VuZGVyUG9saWN5IHwgdW5kZWZpbmVkKTogU2VuZGVyUG9saWN5IHtcbiAgY29uc3QgcmF3ID0gcG9saWN5ID8/IHByb2Nlc3MuZW52LkVNQUlMX1NFTkRFUl9QT0xJQ1k/LnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICBpZiAocmF3ID09PSBcInVucmVzdHJpY3RlZFwiKSByZXR1cm4gXCJ1bnJlc3RyaWN0ZWRcIjtcbiAgaWYgKHJhdyA9PT0gdW5kZWZpbmVkIHx8IHJhdyA9PT0gXCJcIiB8fCByYXcgPT09IFwiYWxsb3dsaXN0XCIpIHJldHVybiBcImFsbG93bGlzdFwiO1xuICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IuaW52YWxpZFZhbHVlKFwic2VuZGVyUG9saWN5XCIsIHJhdywgJ1wiYWxsb3dsaXN0XCIgb3IgXCJ1bnJlc3RyaWN0ZWRcIicpO1xufVxuXG4vKipcbiAqIEVmZmVjdGl2ZSBhbGxvdy1saXN0IGZvciBhbiBgXCJhbGxvd2xpc3RcImAgcG9saWN5IHdpdGggbm8gZXhwbGljaXQgcGF0dGVybnM6XG4gKiB0aGUgc2VuZGVyIHNvdXJjZSBpdHNlbGYsIHNvIGEgY29uZmlndXJlZCBkb21haW4gb3IgZml4ZWQgYWRkcmVzcyBpcyB0aGVcbiAqIGJvdW5kYXJ5IHJhdGhlciB0aGFuIFwiYW55dGhpbmcgZ29lc1wiLiBZaWVsZHMgbm90aGluZyB3aGVuIG5laXRoZXIgaXMgc2V0LFxuICogd2hpY2ggb25seSBoYXBwZW5zIGluIG91dGJveCBtb2RlICh3aGVyZSB0aGUgc2VuZGVyIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBvbi1iZWhhbGYtb2YgdXNlcidzIG93biBhZGRyZXNzIGFuZCBjYW5ub3QgYmUgZW51bWVyYXRlZCB1cCBmcm9udCkuXG4gKi9cbmZ1bmN0aW9uIGltcGxpZWRTZW5kZXJQYXR0ZXJucyhkb21haW46IHN0cmluZyB8IHVuZGVmaW5lZCwgZnJvbTogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nW10ge1xuICBjb25zdCBwYXR0ZXJuczogc3RyaW5nW10gPSBbXTtcbiAgaWYgKGZyb20pIHBhdHRlcm5zLnB1c2goZnJvbS50cmltKCkudG9Mb3dlckNhc2UoKSk7XG4gIGlmIChkb21haW4pIHBhdHRlcm5zLnB1c2goYCpAJHtkb21haW4udHJpbSgpLnRvTG93ZXJDYXNlKCl9YCk7XG4gIHJldHVybiBwYXR0ZXJucztcbn1cblxuLyoqIFdoZXRoZXIgYEVNQUlMX09VVEJPWF9NT0RFYCBleHBsaWNpdGx5IG9wdHMgaW50byB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2suICovXG5mdW5jdGlvbiBpc091dGJveE1vZGVFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gb2JqZWN0LnRvQm9vbGVhbihwcm9jZXNzLmVudi5FTUFJTF9PVVRCT1hfTU9ERSkgPz8gZmFsc2U7XG59XG5cbmNvbnN0IFNNVFBfUkVRVUlSRURfRklFTERTID0gW1wiU01UUF9IT1NUXCIsIFwiU01UUF9VU0VSXCIsIFwiU01UUF9QQVNTV09SRFwiXSBhcyBjb25zdDtcblxuLyoqIExpc3QgZW52IGtleXMgZm9yIFNNVFAgZmllbGRzIHRoYXQgYXJlIHVuc2V0IGluIHRoZSByZXNvbHZlZCBjcmVkZW50aWFsIHNldC4gKi9cbmZ1bmN0aW9uIG1pc3NpbmdTbXRwRmllbGRzKFxuICBob3N0OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHVzZXI6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgcGFzczogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogc3RyaW5nW10ge1xuICBjb25zdCB2YWx1ZXMgPSBbaG9zdCwgdXNlciwgcGFzc10gYXMgY29uc3Q7XG4gIHJldHVybiBTTVRQX1JFUVVJUkVEX0ZJRUxEUy5maWx0ZXIoKF8sIGluZGV4KSA9PiAhdmFsdWVzW2luZGV4XSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBwbHVnaW4gY29uZmlnIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMuXG4gKlxuICogV2hlbiBTTVRQIGhvc3QgKyB1c2VyICsgcGFzc3dvcmQgYXJlIGFsbCBwcmVzZW50LCByZXR1cm5zIGBtb2RlOlxuICogXCJzbXRwXCJgIGZvciByZWFsIGRlbGl2ZXJ5IChhbmQgdGhyb3dzIGlmIG5vIHNlbmRlciBzb3VyY2UgLSBkb21haW4gb3JcbiAqIGZyb20gLSBpcyBjb25maWd1cmVkLCBzaW5jZSBTTVRQIGNhbid0IGRlcml2ZSBvbmUgZnJvbSBub3RoaW5nKS5cbiAqIFdoZW4gYWxsIHRocmVlIGFyZSBhYnNlbnQgYW5kIGBFTUFJTF9PVVRCT1hfTU9ERWAgaXMgZW5hYmxlZCwgcmV0dXJuc1xuICogYG1vZGU6IFwiZmlsZVwiYCBzbyB0aGUgcnVudGltZSB3cml0ZXMgbWVzc2FnZXMgdG8gdGhlIG91dGJveCBkaXJlY3RvcnlcbiAqIGZvciBsb2NhbCB0ZXN0aW5nOyBpbiB0aGF0IG1vZGUgYSBzZW5kZXIgc291cmNlIGlzIG9wdGlvbmFsICh0aGVcbiAqIG91dGJveCBmYWxscyBiYWNrIHRvIHRoZSBPQk8gdXNlcidzIG93biBhZGRyZXNzKS4gUGFydGlhbCBTTVRQXG4gKiBjb25maWd1cmF0aW9uIG9yIGEgc2VuZCB3aXRoIG5vIGNyZWRlbnRpYWxzIGFuZCBubyBvdXRib3ggb3B0LWluXG4gKiB0aHJvd3MuXG4gKlxuICogVGhlIHNlbmRlciBhbGxvdy1saXN0IGlzIHJlc29sdmVkIGhlcmUgdG9vOiB1bmRlciB0aGUgZGVmYXVsdFxuICogYFwiYWxsb3dsaXN0XCJgIHBvbGljeSBhbiBlbXB0eSBsaXN0IGlzIGZpbGxlZCBpbiBmcm9tIHRoZSBzZW5kZXIgc291cmNlLFxuICogc28gYSBkZXBsb3ltZW50IHRoYXQgb25seSBzZXRzIGBFTUFJTF9ET01BSU5gIHN0aWxsIHJlamVjdHMgYSBgRnJvbWAgb25cbiAqIGFueSBvdGhlciBkb21haW4uIFNlZSB7QGxpbmsgU2VuZGVyUG9saWN5fS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVFbWFpbENvbmZpZyhjb25maWc6IEVtYWlsUGx1Z2luQ29uZmlnID0ge30pOiBSZXNvbHZlZEVtYWlsQ29uZmlnIHtcbiAgY29uc3Qgc210cCA9IGNvbmZpZy5zbXRwID8/IHt9O1xuICBjb25zdCBob3N0ID0gc210cC5ob3N0ID8/IHByb2Nlc3MuZW52LlNNVFBfSE9TVDtcbiAgY29uc3QgdXNlciA9IHNtdHAudXNlciA/PyBwcm9jZXNzLmVudi5TTVRQX1VTRVI7XG4gIGNvbnN0IHBhc3MgPSBzbXRwLnBhc3N3b3JkID8/IHByb2Nlc3MuZW52LlNNVFBfUEFTU1dPUkQ7XG4gIGNvbnN0IGRvbWFpbiA9IGNvbmZpZy5kb21haW4gPz8gcHJvY2Vzcy5lbnYuRU1BSUxfRE9NQUlOO1xuICBjb25zdCBmcm9tID0gY29uZmlnLmZyb20gPz8gcHJvY2Vzcy5lbnYuRU1BSUxfRlJPTTtcbiAgY29uc3Qgc2VuZGVyUG9saWN5ID0gcmVzb2x2ZVNlbmRlclBvbGljeShjb25maWcuc2VuZGVyUG9saWN5KTtcbiAgY29uc3QgY29uZmlndXJlZFNlbmRlcnMgPSBwYXJzZUFsbG93ZWRTZW5kZXJzKFxuICAgIGNvbmZpZy5hbGxvd2VkU2VuZGVycyA/PyBwcm9jZXNzLmVudi5FTUFJTF9BTExPV0VEX1NFTkRFUlMsXG4gICk7XG4gIGNvbnN0IGFsbG93ZWRTZW5kZXJzID1cbiAgICBjb25maWd1cmVkU2VuZGVycy5sZW5ndGggPiAwIHx8IHNlbmRlclBvbGljeSA9PT0gXCJ1bnJlc3RyaWN0ZWRcIlxuICAgICAgPyBjb25maWd1cmVkU2VuZGVyc1xuICAgICAgOiBpbXBsaWVkU2VuZGVyUGF0dGVybnMoZG9tYWluLCBmcm9tKTtcbiAgY29uc3Qgc2VuZGVyOiBSZXNvbHZlZFNlbmRlciA9IHtcbiAgICAuLi4oZG9tYWluID8geyBkb21haW4gfSA6IHt9KSxcbiAgICAuLi4oZnJvbSA/IHsgZnJvbSB9IDoge30pLFxuICAgIGFsbG93ZWRTZW5kZXJzLFxuICAgIHNlbmRlclBvbGljeSxcbiAgICAuLi4oY29uZmlnLmJyYW5kID8geyBicmFuZDogY29uZmlnLmJyYW5kIH0gOiB7fSksXG4gIH07XG5cbiAgY29uc3QgaGFzQWxsU210cCA9IEJvb2xlYW4oaG9zdCAmJiB1c2VyICYmIHBhc3MpO1xuICBjb25zdCBoYXNBbnlTbXRwID0gQm9vbGVhbihob3N0IHx8IHVzZXIgfHwgcGFzcyk7XG5cbiAgaWYgKGhhc0FueVNtdHAgJiYgIWhhc0FsbFNtdHApIHtcbiAgICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IubWlzc2luZ0VudlZhcnMobWlzc2luZ1NtdHBGaWVsZHMoaG9zdCwgdXNlciwgcGFzcykpO1xuICB9XG5cbiAgaWYgKGhhc0FsbFNtdHApIHtcbiAgICBpZiAoIWRvbWFpbiAmJiAhZnJvbSkge1xuICAgICAgdGhyb3cgQ29uZmlndXJhdGlvbkVycm9yLnJlc291cmNlTm90Rm91bmQoXG4gICAgICAgIFwiRW1haWwgc2VuZGVyIHNvdXJjZVwiLFxuICAgICAgICBcIlNldCBFTUFJTF9ET01BSU4gdG8gZGVyaXZlIDx1c2VyLWxvY2FsLXBhcnQ+QDxkb21haW4+LCBvciBFTUFJTF9GUk9NIGZvciBhIGZpeGVkIGFkZHJlc3MuXCIsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBwb3J0UmF3ID0gc210cC5wb3J0ID8/IE51bWJlcihwcm9jZXNzLmVudi5TTVRQX1BPUlQpO1xuICAgIGNvbnN0IHBvcnQgPSBOdW1iZXIuaXNGaW5pdGUocG9ydFJhdykgJiYgcG9ydFJhdyA/IE51bWJlcihwb3J0UmF3KSA6IERFRkFVTFRfU01UUF9QT1JUO1xuICAgIHJldHVybiB7XG4gICAgICBtb2RlOiBcInNtdHBcIixcbiAgICAgIGhvc3Q6IGhvc3QhLFxuICAgICAgcG9ydCxcbiAgICAgIHNlY3VyZTogcmVzb2x2ZVNlY3VyZShzbXRwLnNlY3VyZSwgcG9ydCksXG4gICAgICBhdXRoOiB7IHVzZXI6IHVzZXIhLCBwYXNzOiBwYXNzISB9LFxuICAgICAgLi4uc2VuZGVyLFxuICAgIH07XG4gIH1cblxuICBpZiAoIWlzT3V0Ym94TW9kZUVuYWJsZWQoKSkge1xuICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5pbnZhbGlkQ29ubmVjdGlvbihcbiAgICAgIFwiU01UUFwiLFxuICAgICAgYFNldCAke1NNVFBfUkVRVUlSRURfRklFTERTLmpvaW4oXCIsIFwiKX0sIG9yIEVNQUlMX09VVEJPWF9NT0RFPTEgdG8gd3JpdGUgbWVzc2FnZXMgdG8gYSBsb2NhbCBvdXRib3ggaW5zdGVhZC5gLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBvdXREaXIgPSByZXNvbHZlKFxuICAgIGNvbmZpZy5vdXREaXIgPz8gcHJvY2Vzcy5lbnYuRU1BSUxfT1VUQk9YX0RJUiA/PyByZXNvbHZlKHByb2Nlc3MuY3dkKCksIFwidG1wXCIpLFxuICApO1xuICByZXR1cm4geyBtb2RlOiBcImZpbGVcIiwgb3V0RGlyLCAuLi5zZW5kZXIgfTtcbn1cbiJdfQ==
|
package/lib/src/plugin.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ import { type EmailPluginConfig } from "./config.ts";
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements ToolProvider {
|
|
50
|
+
/** The email-OTP access gate, constructed in {@link setup} when `auth.enabled`. */
|
|
51
|
+
private authGate?;
|
|
50
52
|
static manifest: {
|
|
51
53
|
name: "email";
|
|
52
54
|
displayName: string;
|
|
@@ -101,6 +103,15 @@ export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements To
|
|
|
101
103
|
* local part.
|
|
102
104
|
*/
|
|
103
105
|
injectRoutes(router: IAppRouter): void;
|
|
106
|
+
/**
|
|
107
|
+
* Mount the email-OTP login flow under `/api/email/auth/*` when the gate is
|
|
108
|
+
* enabled. These routes are the ONLY ones the gate middleware leaves open (see
|
|
109
|
+
* {@link AuthGate.middleware}); everything else requires the session cookie
|
|
110
|
+
* they establish. No-op when auth is off.
|
|
111
|
+
*/
|
|
112
|
+
private injectAuthRoutes;
|
|
113
|
+
/** Client IP for rate-limiting, honoring the Apps ingress `x-forwarded-for`. */
|
|
114
|
+
private clientIp;
|
|
104
115
|
exports(): {
|
|
105
116
|
/**
|
|
106
117
|
* Send a message immediately from `from` through the shared
|
|
@@ -129,6 +140,18 @@ export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements To
|
|
|
129
140
|
* not wrap it again.
|
|
130
141
|
*/
|
|
131
142
|
private send;
|
|
143
|
+
/**
|
|
144
|
+
* Build the email-OTP access gate when `auth.enabled`, wiring its code
|
|
145
|
+
* delivery through this plugin's own transport. Called from {@link setup}; a
|
|
146
|
+
* no-op (leaves {@link authGate} undefined) when the gate is off.
|
|
147
|
+
*/
|
|
148
|
+
private setupAuthGate;
|
|
149
|
+
/**
|
|
150
|
+
* Deliver a one-time code to `email` through this plugin's transport. Throws
|
|
151
|
+
* on failure (the gate swallows it, so a delivery error never leaks whether
|
|
152
|
+
* the address was allow-listed).
|
|
153
|
+
*/
|
|
154
|
+
private sendOtpEmail;
|
|
132
155
|
/** Run the sender-options lookup through the plugin's interceptor chain. */
|
|
133
156
|
private executeListSenders;
|
|
134
157
|
/**
|