@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.
@@ -0,0 +1,196 @@
1
+ /**
2
+ * The tunnel's in-app AUTH GATE - Express middleware + login routes the
3
+ * {@link AuthGatePlugin} registers on the app's OWN server via `this.context`.
4
+ *
5
+ * This replaces the old standalone reverse-proxy (`proxy.ts`): the app is now the
6
+ * process, so there is nothing to forward to. Instead the gate is middleware that
7
+ * either short-circuits (401, or answers the open login routes) or calls `next()`
8
+ * to let the app's real handlers run. It is the "stands in for AppKit auth" path:
9
+ * a portr caller proves an email via OTP, and on success the gate injects the
10
+ * identity headers AppKit reads, so a gated request runs like a front-door one.
11
+ *
12
+ * WHICH TRAFFIC IS GATED - the `Host` header, not the socket. portr's client
13
+ * forwards with Go's `httputil.NewSingleHostReverseProxy` and a `Director` that
14
+ * PRESERVES the original `Host`, so tunnel requests arrive with
15
+ * `Host: <subdomain>.<server>` (the public domain). A local process hitting the
16
+ * app directly sends `Host: 127.0.0.1:<port>` / `localhost`. So ONLY requests whose
17
+ * `Host` matches the configured public domain are gated; the platform front door
18
+ * and any other local client pass through untouched. There is no portr-injected
19
+ * identifying header and no TCP/source-IP signal to use instead (the client dials
20
+ * the target over plain loopback).
21
+ *
22
+ * @module
23
+ */
24
+ import { http, json, log, token } from "@dbx-tools/shared-core";
25
+ import { authRequestSchema, authVerifySchema, SESSION_COOKIE_NAME } from "@dbx-tools/shared-email";
26
+ import { toHeaderPolicy } from "./headers.js";
27
+ const logger = log.logger("tunnel:gate");
28
+ /** Route prefix the login flow lives under (open, answered in-process). */
29
+ export const AUTH_PREFIX = "/api/email/auth";
30
+ /**
31
+ * True when the request's `Host` is the tunnel's public domain - i.e. it came in
32
+ * over portr. Case-insensitive; the optional `:port` is ignored. When no public
33
+ * domain is configured, nothing is tunnel traffic.
34
+ */
35
+ export function isTunnelHost(req, publicDomain) {
36
+ if (!publicDomain)
37
+ return false;
38
+ const host = (req.headers.host ?? "").toLowerCase().split(":")[0];
39
+ return host === publicDomain.toLowerCase().split(":")[0];
40
+ }
41
+ /** The session cookie for a verified email, as a Set-Cookie string. */
42
+ function sessionCookie(value, maxAgeSeconds) {
43
+ return [
44
+ `${SESSION_COOKIE_NAME}=${value}`,
45
+ "Path=/",
46
+ "HttpOnly",
47
+ "SameSite=Lax",
48
+ `Max-Age=${maxAgeSeconds}`,
49
+ // Real enforcement in production: the session cookie must be Secure so it is
50
+ // never sent over plaintext. Local dev (http) omits it so the cookie works.
51
+ process.env.NODE_ENV === "production" ? "Secure" : "",
52
+ ]
53
+ .filter(Boolean)
54
+ .join("; ");
55
+ }
56
+ /**
57
+ * Client IP for rate-limiting: the RIGHTMOST `x-forwarded-for` entry (the value
58
+ * the nearest trusted hop - portr - wrote), else the socket address. Reading the
59
+ * rightmost, not the leftmost, stops a caller minting a fresh rate-limit bucket by
60
+ * varying the header. Called before {@link stripHeaders}.
61
+ */
62
+ function clientIp(req) {
63
+ const forwarded = req.headers["x-forwarded-for"];
64
+ const chain = (Array.isArray(forwarded) ? forwarded.join(",") : (forwarded ?? ""))
65
+ .split(",")
66
+ .map((entry) => entry.trim())
67
+ .filter(Boolean);
68
+ return chain.at(-1) ?? req.socket.remoteAddress ?? "unknown";
69
+ }
70
+ /**
71
+ * Remove the gate's session cookie from the `Cookie` header before the app's
72
+ * handlers run, so the app never sees `dbx_auth` (it is the gate's concern).
73
+ * Preserves other cookies; deletes the header when it becomes empty.
74
+ */
75
+ function stripSessionCookie(req) {
76
+ const raw = req.headers.cookie;
77
+ if (!raw)
78
+ return;
79
+ const kept = raw
80
+ .split(";")
81
+ .map((c) => c.trim())
82
+ .filter((c) => c && !c.startsWith(`${SESSION_COOKIE_NAME}=`));
83
+ if (kept.length)
84
+ req.headers.cookie = kept.join("; ");
85
+ else
86
+ delete req.headers.cookie;
87
+ }
88
+ /**
89
+ * Present an OTP-authenticated caller to the app the SAME way a platform front
90
+ * door does: set the front-door identity headers to the verified address (AppKit
91
+ * reads {@link token.USER_ID_HEADER} for the OBO user id), so the app needs no
92
+ * gate-specific code path.
93
+ *
94
+ * What the gate CANNOT set is {@link token.ACCESS_TOKEN_HEADER}: an OTP session
95
+ * proves an email, not possession of a Databricks credential. Its absence is what
96
+ * `@dbx-tools/appkit`'s `identity: "auto"` detects, so a gated request runs as the
97
+ * app service principal instead of throwing.
98
+ */
99
+ function injectIdentity(req, email) {
100
+ req.headers[token.USER_ID_HEADER] = email;
101
+ req.headers[token.USER_EMAIL_HEADER] = email;
102
+ }
103
+ function sendJson(res, status, body, setCookie) {
104
+ if (setCookie)
105
+ res.setHeader("set-cookie", setCookie);
106
+ res.status(status).json(body);
107
+ }
108
+ /** Read the raw request body as text (AppKit parses JSON, but the gate routes
109
+ * are mounted before that runs for tunnel traffic, so read defensively). */
110
+ function readBody(req) {
111
+ // AppKit's json body-parser may have already populated req.body; prefer it.
112
+ if (req.body !== undefined && req.body !== null) {
113
+ return Promise.resolve(typeof req.body === "string" ? req.body : JSON.stringify(req.body));
114
+ }
115
+ return new Promise((resolve) => {
116
+ let data = "";
117
+ req.on("data", (chunk) => (data += chunk));
118
+ req.on("end", () => resolve(data));
119
+ req.on("error", () => resolve(data));
120
+ });
121
+ }
122
+ /**
123
+ * Register the login routes and the gating middleware on the app's Express
124
+ * instance. Called from {@link AuthGatePlugin} with the router AppKit hands
125
+ * `injectRoutes`, plus `this.context.addMiddleware` for the global gate.
126
+ *
127
+ * `addRoute`/`addMiddleware` are used (via the passed callbacks) because the login
128
+ * routes live at an ABSOLUTE path (`/api/email/auth/*`, the client's contract),
129
+ * not under the plugin's `/api/authGate` base.
130
+ */
131
+ export function mountGate(opts, addRoute, addMiddleware) {
132
+ const { gate, publicDomain, forwardHeaders } = opts;
133
+ const headerPolicy = toHeaderPolicy(forwardHeaders);
134
+ logger.debug("gate mounted", { publicDomain, forward: headerPolicy.patterns });
135
+ const applyHeaderPolicy = (req) => {
136
+ const removed = headerPolicy.apply(req.headers);
137
+ if (removed.length)
138
+ logger.debug("stripped inbound headers", { removed });
139
+ };
140
+ // --- Login routes (open on tunnel traffic; answered in-process) ---
141
+ const statusHandler = (async (req, res) => {
142
+ const cookie = http.parseCookies(req.headers.cookie ?? null)[SESSION_COOKIE_NAME];
143
+ sendJson(res, 200, await gate.status(cookie));
144
+ });
145
+ const requestHandler = (async (req, res) => {
146
+ const parsed = authRequestSchema.safeParse(json.parseRecord(await readBody(req)));
147
+ if (!parsed.success)
148
+ return sendJson(res, 200, { ok: true }); // anti-enumeration
149
+ sendJson(res, 200, await gate.request(parsed.data.email, clientIp(req)));
150
+ });
151
+ const verifyHandler = (async (req, res) => {
152
+ const parsed = authVerifySchema.safeParse(json.parseRecord(await readBody(req)));
153
+ if (!parsed.success)
154
+ return sendJson(res, 200, { ok: false });
155
+ const result = await gate.verify(parsed.data.email, parsed.data.code, clientIp(req));
156
+ const cookie = result.ok && result.token ? sessionCookie(result.token, gate.sessionTtlSeconds) : undefined;
157
+ sendJson(res, 200, { ok: result.ok, ...(result.retryAfter ? { retryAfter: result.retryAfter } : {}) }, cookie);
158
+ });
159
+ const logoutHandler = ((_req, res) => {
160
+ sendJson(res, 200, { ok: true }, `${SESSION_COOKIE_NAME}=; Path=/; HttpOnly; Max-Age=0`);
161
+ });
162
+ addRoute("get", `${AUTH_PREFIX}/status`, statusHandler);
163
+ addRoute("post", `${AUTH_PREFIX}/request`, requestHandler);
164
+ addRoute("post", `${AUTH_PREFIX}/verify`, verifyHandler);
165
+ addRoute("post", `${AUTH_PREFIX}/logout`, logoutHandler);
166
+ // --- The gate middleware (runs before static + the app's /api handlers) ---
167
+ const gateMiddleware = (async (req, res, next) => {
168
+ // Not tunnel traffic (platform front door, or any other local caller): the
169
+ // request is already authenticated (or is not ours to gate). Pass through.
170
+ if (!isTunnelHost(req, publicDomain))
171
+ return next();
172
+ const path = (req.url ?? "/").split("?")[0] ?? "/";
173
+ // The login flow is open so the browser can render <AuthGate> and sign in.
174
+ if (path.startsWith(AUTH_PREFIX))
175
+ return next();
176
+ // Anti-spoof: only the gate may assert identity on tunnel traffic.
177
+ applyHeaderPolicy(req);
178
+ // Static (non-API) loads freely so the SPA can render; drop the gate cookie.
179
+ if (!path.startsWith("/api/")) {
180
+ stripSessionCookie(req);
181
+ return next();
182
+ }
183
+ // Every other /api/* needs a valid OTP session.
184
+ const cookie = http.parseCookies(req.headers.cookie ?? null)[SESSION_COOKIE_NAME];
185
+ const email = await gate.session(cookie);
186
+ if (!email) {
187
+ sendJson(res, 401, { error: "authentication required", loginPath: AUTH_PREFIX });
188
+ return;
189
+ }
190
+ injectIdentity(req, email);
191
+ stripSessionCookie(req);
192
+ next();
193
+ });
194
+ addMiddleware("/", gateMiddleware);
195
+ }
196
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2F0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9nYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRWhFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25HLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFHOUMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUV6QywyRUFBMkU7QUFDM0UsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDO0FBb0I3Qzs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxHQUFZLEVBQUUsWUFBZ0M7SUFDekUsSUFBSSxDQUFDLFlBQVk7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNoQyxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRSxPQUFPLElBQUksS0FBSyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzNELENBQUM7QUFFRCx1RUFBdUU7QUFDdkUsU0FBUyxhQUFhLENBQUMsS0FBYSxFQUFFLGFBQXFCO0lBQ3pELE9BQU87UUFDTCxHQUFHLG1CQUFtQixJQUFJLEtBQUssRUFBRTtRQUNqQyxRQUFRO1FBQ1IsVUFBVTtRQUNWLGNBQWM7UUFDZCxXQUFXLGFBQWEsRUFBRTtRQUMxQiw2RUFB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RUFBRSxDQUFDLENBQUM7WUFDakYsT0FBTztRQUNULENBQUM7UUFDRCxjQUFjLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzNCLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLElBQUksRUFBRSxDQUFDO0lBQ1QsQ0FBQyxDQUFtQixDQUFDO0lBRXJCLGFBQWEsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDckMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIHR1bm5lbCdzIGluLWFwcCBBVVRIIEdBVEUgLSBFeHByZXNzIG1pZGRsZXdhcmUgKyBsb2dpbiByb3V0ZXMgdGhlXG4gKiB7QGxpbmsgQXV0aEdhdGVQbHVnaW59IHJlZ2lzdGVycyBvbiB0aGUgYXBwJ3MgT1dOIHNlcnZlciB2aWEgYHRoaXMuY29udGV4dGAuXG4gKlxuICogVGhpcyByZXBsYWNlcyB0aGUgb2xkIHN0YW5kYWxvbmUgcmV2ZXJzZS1wcm94eSAoYHByb3h5LnRzYCk6IHRoZSBhcHAgaXMgbm93IHRoZVxuICogcHJvY2Vzcywgc28gdGhlcmUgaXMgbm90aGluZyB0byBmb3J3YXJkIHRvLiBJbnN0ZWFkIHRoZSBnYXRlIGlzIG1pZGRsZXdhcmUgdGhhdFxuICogZWl0aGVyIHNob3J0LWNpcmN1aXRzICg0MDEsIG9yIGFuc3dlcnMgdGhlIG9wZW4gbG9naW4gcm91dGVzKSBvciBjYWxscyBgbmV4dCgpYFxuICogdG8gbGV0IHRoZSBhcHAncyByZWFsIGhhbmRsZXJzIHJ1bi4gSXQgaXMgdGhlIFwic3RhbmRzIGluIGZvciBBcHBLaXQgYXV0aFwiIHBhdGg6XG4gKiBhIHBvcnRyIGNhbGxlciBwcm92ZXMgYW4gZW1haWwgdmlhIE9UUCwgYW5kIG9uIHN1Y2Nlc3MgdGhlIGdhdGUgaW5qZWN0cyB0aGVcbiAqIGlkZW50aXR5IGhlYWRlcnMgQXBwS2l0IHJlYWRzLCBzbyBhIGdhdGVkIHJlcXVlc3QgcnVucyBsaWtlIGEgZnJvbnQtZG9vciBvbmUuXG4gKlxuICogV0hJQ0ggVFJBRkZJQyBJUyBHQVRFRCAtIHRoZSBgSG9zdGAgaGVhZGVyLCBub3QgdGhlIHNvY2tldC4gcG9ydHIncyBjbGllbnRcbiAqIGZvcndhcmRzIHdpdGggR28ncyBgaHR0cHV0aWwuTmV3U2luZ2xlSG9zdFJldmVyc2VQcm94eWAgYW5kIGEgYERpcmVjdG9yYCB0aGF0XG4gKiBQUkVTRVJWRVMgdGhlIG9yaWdpbmFsIGBIb3N0YCwgc28gdHVubmVsIHJlcXVlc3RzIGFycml2ZSB3aXRoXG4gKiBgSG9zdDogPHN1YmRvbWFpbj4uPHNlcnZlcj5gICh0aGUgcHVibGljIGRvbWFpbikuIEEgbG9jYWwgcHJvY2VzcyBoaXR0aW5nIHRoZVxuICogYXBwIGRpcmVjdGx5IHNlbmRzIGBIb3N0OiAxMjcuMC4wLjE6PHBvcnQ+YCAvIGBsb2NhbGhvc3RgLiBTbyBPTkxZIHJlcXVlc3RzIHdob3NlXG4gKiBgSG9zdGAgbWF0Y2hlcyB0aGUgY29uZmlndXJlZCBwdWJsaWMgZG9tYWluIGFyZSBnYXRlZDsgdGhlIHBsYXRmb3JtIGZyb250IGRvb3JcbiAqIGFuZCBhbnkgb3RoZXIgbG9jYWwgY2xpZW50IHBhc3MgdGhyb3VnaCB1bnRvdWNoZWQuIFRoZXJlIGlzIG5vIHBvcnRyLWluamVjdGVkXG4gKiBpZGVudGlmeWluZyBoZWFkZXIgYW5kIG5vIFRDUC9zb3VyY2UtSVAgc2lnbmFsIHRvIHVzZSBpbnN0ZWFkICh0aGUgY2xpZW50IGRpYWxzXG4gKiB0aGUgdGFyZ2V0IG92ZXIgcGxhaW4gbG9vcGJhY2spLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBodHRwLCBqc29uLCBsb2csIHRva2VuIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVxdWVzdEhhbmRsZXIsIFJlc3BvbnNlIH0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCB7IGF1dGhSZXF1ZXN0U2NoZW1hLCBhdXRoVmVyaWZ5U2NoZW1hLCBTRVNTSU9OX0NPT0tJRV9OQU1FIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWVtYWlsXCI7XG5pbXBvcnQgeyB0b0hlYWRlclBvbGljeSB9IGZyb20gXCIuL2hlYWRlcnMudHNcIjtcbmltcG9ydCB0eXBlIHsgQXV0aEdhdGVBcGkgfSBmcm9tIFwiLi9wbHVnaW4udHNcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcInR1bm5lbDpnYXRlXCIpO1xuXG4vKiogUm91dGUgcHJlZml4IHRoZSBsb2dpbiBmbG93IGxpdmVzIHVuZGVyIChvcGVuLCBhbnN3ZXJlZCBpbi1wcm9jZXNzKS4gKi9cbmV4cG9ydCBjb25zdCBBVVRIX1BSRUZJWCA9IFwiL2FwaS9lbWFpbC9hdXRoXCI7XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgbW91bnRHYXRlfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2F0ZU9wdGlvbnMge1xuICAvKiogVGhlIGluLXByb2Nlc3MgZ2F0ZSBBUEkgKHNlc3Npb24vcmVxdWVzdC92ZXJpZnkvc3RhdHVzKS4gKi9cbiAgZ2F0ZTogQXV0aEdhdGVBcGk7XG4gIC8qKlxuICAgKiBUaGUgcHVibGljIGA8c3ViZG9tYWluPi48c2VydmVyPmAgdGhhdCBpZGVudGlmaWVzIHBvcnRyIHRyYWZmaWMgYnkgYEhvc3RgLlxuICAgKiBXaGVuIGFic2VudCwgbm8gcmVxdWVzdCBpcyBldmVyIGNsYXNzaWZpZWQgYXMgdHVubmVsIHRyYWZmaWMgYW5kIHRoZSBnYXRlIGlzXG4gICAqIGluZXJ0IChldmVyeXRoaW5nIHBhc3NlcyB0aHJvdWdoKSAtIGEgdHVubmVsIHdpdGggbm8gcHVibGljIGRvbWFpbiBnYXRlc1xuICAgKiBub3RoaW5nLlxuICAgKi9cbiAgcHVibGljRG9tYWluPzogc3RyaW5nO1xuICAvKipcbiAgICogRXh0cmEgYHgtYCByZXF1ZXN0IGhlYWRlcnMgdHVubmVsIHRyYWZmaWMgbWF5IGZvcndhcmQgKHVuaW9uZWQgd2l0aCB0aGVcbiAgICogYnVpbHQtaW4gYWxsb3ctbGlzdCkuIEV2ZXJ5IG90aGVyIGB4LWAgaGVhZGVyIGlzIHN0cmlwcGVkIGZyb20gdHVubmVsIHRyYWZmaWMuXG4gICAqL1xuICBmb3J3YXJkSGVhZGVycz86IHJlYWRvbmx5IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFRydWUgd2hlbiB0aGUgcmVxdWVzdCdzIGBIb3N0YCBpcyB0aGUgdHVubmVsJ3MgcHVibGljIGRvbWFpbiAtIGkuZS4gaXQgY2FtZSBpblxuICogb3ZlciBwb3J0ci4gQ2FzZS1pbnNlbnNpdGl2ZTsgdGhlIG9wdGlvbmFsIGA6cG9ydGAgaXMgaWdub3JlZC4gV2hlbiBubyBwdWJsaWNcbiAqIGRvbWFpbiBpcyBjb25maWd1cmVkLCBub3RoaW5nIGlzIHR1bm5lbCB0cmFmZmljLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNUdW5uZWxIb3N0KHJlcTogUmVxdWVzdCwgcHVibGljRG9tYWluOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgaWYgKCFwdWJsaWNEb21haW4pIHJldHVybiBmYWxzZTtcbiAgY29uc3QgaG9zdCA9IChyZXEuaGVhZGVycy5ob3N0ID8/IFwiXCIpLnRvTG93ZXJDYXNlKCkuc3BsaXQoXCI6XCIpWzBdO1xuICByZXR1cm4gaG9zdCA9PT0gcHVibGljRG9tYWluLnRvTG93ZXJDYXNlKCkuc3BsaXQoXCI6XCIpWzBdO1xufVxuXG4vKiogVGhlIHNlc3Npb24gY29va2llIGZvciBhIHZlcmlmaWVkIGVtYWlsLCBhcyBhIFNldC1Db29raWUgc3RyaW5nLiAqL1xuZnVuY3Rpb24gc2Vzc2lvbkNvb2tpZSh2YWx1ZTogc3RyaW5nLCBtYXhBZ2VTZWNvbmRzOiBudW1iZXIpOiBzdHJpbmcge1xuICByZXR1cm4gW1xuICAgIGAke1NFU1NJT05fQ09PS0lFX05BTUV9PSR7dmFsdWV9YCxcbiAgICBcIlBhdGg9L1wiLFxuICAgIFwiSHR0cE9ubHlcIixcbiAgICBcIlNhbWVTaXRlPUxheFwiLFxuICAgIGBNYXgtQWdlPSR7bWF4QWdlU2Vjb25kc31gLFxuICAgIC8vIFJlYWwgZW5mb3JjZW1lbnQgaW4gcHJvZHVjdGlvbjogdGhlIHNlc3Npb24gY29va2llIG11c3QgYmUgU2VjdXJlIHNvIGl0IGlzXG4gICAgLy8gbmV2ZXIgc2VudCBvdmVyIHBsYWludGV4dC4gTG9jYWwgZGV2IChodHRwKSBvbWl0cyBpdCBzbyB0aGUgY29va2llIHdvcmtzLlxuICAgIHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcInByb2R1Y3Rpb25cIiA/IFwiU2VjdXJlXCIgOiBcIlwiLFxuICBdXG4gICAgLmZpbHRlcihCb29sZWFuKVxuICAgIC5qb2luKFwiOyBcIik7XG59XG5cbi8qKlxuICogQ2xpZW50IElQIGZvciByYXRlLWxpbWl0aW5nOiB0aGUgUklHSFRNT1NUIGB4LWZvcndhcmRlZC1mb3JgIGVudHJ5ICh0aGUgdmFsdWVcbiAqIHRoZSBuZWFyZXN0IHRydXN0ZWQgaG9wIC0gcG9ydHIgLSB3cm90ZSksIGVsc2UgdGhlIHNvY2tldCBhZGRyZXNzLiBSZWFkaW5nIHRoZVxuICogcmlnaHRtb3N0LCBub3QgdGhlIGxlZnRtb3N0LCBzdG9wcyBhIGNhbGxlciBtaW50aW5nIGEgZnJlc2ggcmF0ZS1saW1pdCBidWNrZXQgYnlcbiAqIHZhcnlpbmcgdGhlIGhlYWRlci4gQ2FsbGVkIGJlZm9yZSB7QGxpbmsgc3RyaXBIZWFkZXJzfS5cbiAqL1xuZnVuY3Rpb24gY2xpZW50SXAocmVxOiBSZXF1ZXN0KTogc3RyaW5nIHtcbiAgY29uc3QgZm9yd2FyZGVkID0gcmVxLmhlYWRlcnNbXCJ4LWZvcndhcmRlZC1mb3JcIl07XG4gIGNvbnN0IGNoYWluID0gKEFycmF5LmlzQXJyYXkoZm9yd2FyZGVkKSA/IGZvcndhcmRlZC5qb2luKFwiLFwiKSA6IChmb3J3YXJkZWQgPz8gXCJcIikpXG4gICAgLnNwbGl0KFwiLFwiKVxuICAgIC5tYXAoKGVudHJ5KSA9PiBlbnRyeS50cmltKCkpXG4gICAgLmZpbHRlcihCb29sZWFuKTtcbiAgcmV0dXJuIGNoYWluLmF0KC0xKSA/PyByZXEuc29ja2V0LnJlbW90ZUFkZHJlc3MgPz8gXCJ1bmtub3duXCI7XG59XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBnYXRlJ3Mgc2Vzc2lvbiBjb29raWUgZnJvbSB0aGUgYENvb2tpZWAgaGVhZGVyIGJlZm9yZSB0aGUgYXBwJ3NcbiAqIGhhbmRsZXJzIHJ1biwgc28gdGhlIGFwcCBuZXZlciBzZWVzIGBkYnhfYXV0aGAgKGl0IGlzIHRoZSBnYXRlJ3MgY29uY2VybikuXG4gKiBQcmVzZXJ2ZXMgb3RoZXIgY29va2llczsgZGVsZXRlcyB0aGUgaGVhZGVyIHdoZW4gaXQgYmVjb21lcyBlbXB0eS5cbiAqL1xuZnVuY3Rpb24gc3RyaXBTZXNzaW9uQ29va2llKHJlcTogUmVxdWVzdCk6IHZvaWQge1xuICBjb25zdCByYXcgPSByZXEuaGVhZGVycy5jb29raWU7XG4gIGlmICghcmF3KSByZXR1cm47XG4gIGNvbnN0IGtlcHQgPSByYXdcbiAgICAuc3BsaXQoXCI7XCIpXG4gICAgLm1hcCgoYykgPT4gYy50cmltKCkpXG4gICAgLmZpbHRlcigoYykgPT4gYyAmJiAhYy5zdGFydHNXaXRoKGAke1NFU1NJT05fQ09PS0lFX05BTUV9PWApKTtcbiAgaWYgKGtlcHQubGVuZ3RoKSByZXEuaGVhZGVycy5jb29raWUgPSBrZXB0LmpvaW4oXCI7IFwiKTtcbiAgZWxzZSBkZWxldGUgcmVxLmhlYWRlcnMuY29va2llO1xufVxuXG4vKipcbiAqIFByZXNlbnQgYW4gT1RQLWF1dGhlbnRpY2F0ZWQgY2FsbGVyIHRvIHRoZSBhcHAgdGhlIFNBTUUgd2F5IGEgcGxhdGZvcm0gZnJvbnRcbiAqIGRvb3IgZG9lczogc2V0IHRoZSBmcm9udC1kb29yIGlkZW50aXR5IGhlYWRlcnMgdG8gdGhlIHZlcmlmaWVkIGFkZHJlc3MgKEFwcEtpdFxuICogcmVhZHMge0BsaW5rIHRva2VuLlVTRVJfSURfSEVBREVSfSBmb3IgdGhlIE9CTyB1c2VyIGlkKSwgc28gdGhlIGFwcCBuZWVkcyBub1xuICogZ2F0ZS1zcGVjaWZpYyBjb2RlIHBhdGguXG4gKlxuICogV2hhdCB0aGUgZ2F0ZSBDQU5OT1Qgc2V0IGlzIHtAbGluayB0b2tlbi5BQ0NFU1NfVE9LRU5fSEVBREVSfTogYW4gT1RQIHNlc3Npb25cbiAqIHByb3ZlcyBhbiBlbWFpbCwgbm90IHBvc3Nlc3Npb24gb2YgYSBEYXRhYnJpY2tzIGNyZWRlbnRpYWwuIEl0cyBhYnNlbmNlIGlzIHdoYXRcbiAqIGBAZGJ4LXRvb2xzL2FwcGtpdGAncyBgaWRlbnRpdHk6IFwiYXV0b1wiYCBkZXRlY3RzLCBzbyBhIGdhdGVkIHJlcXVlc3QgcnVucyBhcyB0aGVcbiAqIGFwcCBzZXJ2aWNlIHByaW5jaXBhbCBpbnN0ZWFkIG9mIHRocm93aW5nLlxuICovXG5mdW5jdGlvbiBpbmplY3RJZGVudGl0eShyZXE6IFJlcXVlc3QsIGVtYWlsOiBzdHJpbmcpOiB2b2lkIHtcbiAgcmVxLmhlYWRlcnNbdG9rZW4uVVNFUl9JRF9IRUFERVJdID0gZW1haWw7XG4gIHJlcS5oZWFkZXJzW3Rva2VuLlVTRVJfRU1BSUxfSEVBREVSXSA9IGVtYWlsO1xufVxuXG5mdW5jdGlvbiBzZW5kSnNvbihyZXM6IFJlc3BvbnNlLCBzdGF0dXM6IG51bWJlciwgYm9keTogdW5rbm93biwgc2V0Q29va2llPzogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChzZXRDb29raWUpIHJlcy5zZXRIZWFkZXIoXCJzZXQtY29va2llXCIsIHNldENvb2tpZSk7XG4gIHJlcy5zdGF0dXMoc3RhdHVzKS5qc29uKGJvZHkpO1xufVxuXG4vKiogUmVhZCB0aGUgcmF3IHJlcXVlc3QgYm9keSBhcyB0ZXh0IChBcHBLaXQgcGFyc2VzIEpTT04sIGJ1dCB0aGUgZ2F0ZSByb3V0ZXNcbiAqIGFyZSBtb3VudGVkIGJlZm9yZSB0aGF0IHJ1bnMgZm9yIHR1bm5lbCB0cmFmZmljLCBzbyByZWFkIGRlZmVuc2l2ZWx5KS4gKi9cbmZ1bmN0aW9uIHJlYWRCb2R5KHJlcTogUmVxdWVzdCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIC8vIEFwcEtpdCdzIGpzb24gYm9keS1wYXJzZXIgbWF5IGhhdmUgYWxyZWFkeSBwb3B1bGF0ZWQgcmVxLmJvZHk7IHByZWZlciBpdC5cbiAgaWYgKHJlcS5ib2R5ICE9PSB1bmRlZmluZWQgJiYgcmVxLmJvZHkgIT09IG51bGwpIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHR5cGVvZiByZXEuYm9keSA9PT0gXCJzdHJpbmdcIiA/IHJlcS5ib2R5IDogSlNPTi5zdHJpbmdpZnkocmVxLmJvZHkpKTtcbiAgfVxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBsZXQgZGF0YSA9IFwiXCI7XG4gICAgcmVxLm9uKFwiZGF0YVwiLCAoY2h1bmspID0+IChkYXRhICs9IGNodW5rKSk7XG4gICAgcmVxLm9uKFwiZW5kXCIsICgpID0+IHJlc29sdmUoZGF0YSkpO1xuICAgIHJlcS5vbihcImVycm9yXCIsICgpID0+IHJlc29sdmUoZGF0YSkpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlciB0aGUgbG9naW4gcm91dGVzIGFuZCB0aGUgZ2F0aW5nIG1pZGRsZXdhcmUgb24gdGhlIGFwcCdzIEV4cHJlc3NcbiAqIGluc3RhbmNlLiBDYWxsZWQgZnJvbSB7QGxpbmsgQXV0aEdhdGVQbHVnaW59IHdpdGggdGhlIHJvdXRlciBBcHBLaXQgaGFuZHNcbiAqIGBpbmplY3RSb3V0ZXNgLCBwbHVzIGB0aGlzLmNvbnRleHQuYWRkTWlkZGxld2FyZWAgZm9yIHRoZSBnbG9iYWwgZ2F0ZS5cbiAqXG4gKiBgYWRkUm91dGVgL2BhZGRNaWRkbGV3YXJlYCBhcmUgdXNlZCAodmlhIHRoZSBwYXNzZWQgY2FsbGJhY2tzKSBiZWNhdXNlIHRoZSBsb2dpblxuICogcm91dGVzIGxpdmUgYXQgYW4gQUJTT0xVVEUgcGF0aCAoYC9hcGkvZW1haWwvYXV0aC8qYCwgdGhlIGNsaWVudCdzIGNvbnRyYWN0KSxcbiAqIG5vdCB1bmRlciB0aGUgcGx1Z2luJ3MgYC9hcGkvYXV0aEdhdGVgIGJhc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtb3VudEdhdGUoXG4gIG9wdHM6IEdhdGVPcHRpb25zLFxuICBhZGRSb3V0ZTogKG1ldGhvZDogXCJnZXRcIiB8IFwicG9zdFwiLCBwYXRoOiBzdHJpbmcsIGhhbmRsZXI6IFJlcXVlc3RIYW5kbGVyKSA9PiB2b2lkLFxuICBhZGRNaWRkbGV3YXJlOiAocGF0aDogc3RyaW5nLCBoYW5kbGVyOiBSZXF1ZXN0SGFuZGxlcikgPT4gdm9pZCxcbik6IHZvaWQge1xuICBjb25zdCB7IGdhdGUsIHB1YmxpY0RvbWFpbiwgZm9yd2FyZEhlYWRlcnMgfSA9IG9wdHM7XG4gIGNvbnN0IGhlYWRlclBvbGljeSA9IHRvSGVhZGVyUG9saWN5KGZvcndhcmRIZWFkZXJzKTtcbiAgbG9nZ2VyLmRlYnVnKFwiZ2F0ZSBtb3VudGVkXCIsIHsgcHVibGljRG9tYWluLCBmb3J3YXJkOiBoZWFkZXJQb2xpY3kucGF0dGVybnMgfSk7XG5cbiAgY29uc3QgYXBwbHlIZWFkZXJQb2xpY3kgPSAocmVxOiBSZXF1ZXN0KTogdm9pZCA9PiB7XG4gICAgY29uc3QgcmVtb3ZlZCA9IGhlYWRlclBvbGljeS5hcHBseShyZXEuaGVhZGVycyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik7XG4gICAgaWYgKHJlbW92ZWQubGVuZ3RoKSBsb2dnZXIuZGVidWcoXCJzdHJpcHBlZCBpbmJvdW5kIGhlYWRlcnNcIiwgeyByZW1vdmVkIH0pO1xuICB9O1xuXG4gIC8vIC0tLSBMb2dpbiByb3V0ZXMgKG9wZW4gb24gdHVubmVsIHRyYWZmaWM7IGFuc3dlcmVkIGluLXByb2Nlc3MpIC0tLVxuXG4gIGNvbnN0IHN0YXR1c0hhbmRsZXIgPSAoYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgY29uc3QgY29va2llID0gaHR0cC5wYXJzZUNvb2tpZXMocmVxLmhlYWRlcnMuY29va2llID8/IG51bGwpW1NFU1NJT05fQ09PS0lFX05BTUVdO1xuICAgIHNlbmRKc29uKHJlcywgMjAwLCBhd2FpdCBnYXRlLnN0YXR1cyhjb29raWUpKTtcbiAgfSkgYXMgUmVxdWVzdEhhbmRsZXI7XG5cbiAgY29uc3QgcmVxdWVzdEhhbmRsZXIgPSAoYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgY29uc3QgcGFyc2VkID0gYXV0aFJlcXVlc3RTY2hlbWEuc2FmZVBhcnNlKGpzb24ucGFyc2VSZWNvcmQoYXdhaXQgcmVhZEJvZHkocmVxKSkpO1xuICAgIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHJldHVybiBzZW5kSnNvbihyZXMsIDIwMCwgeyBvazogdHJ1ZSB9KTsgLy8gYW50aS1lbnVtZXJhdGlvblxuICAgIHNlbmRKc29uKHJlcywgMjAwLCBhd2FpdCBnYXRlLnJlcXVlc3QocGFyc2VkLmRhdGEuZW1haWwsIGNsaWVudElwKHJlcSkpKTtcbiAgfSkgYXMgUmVxdWVzdEhhbmRsZXI7XG5cbiAgY29uc3QgdmVyaWZ5SGFuZGxlciA9IChhc3luYyAocmVxLCByZXMpID0+IHtcbiAgICBjb25zdCBwYXJzZWQgPSBhdXRoVmVyaWZ5U2NoZW1hLnNhZmVQYXJzZShqc29uLnBhcnNlUmVjb3JkKGF3YWl0IHJlYWRCb2R5KHJlcSkpKTtcbiAgICBpZiAoIXBhcnNlZC5zdWNjZXNzKSByZXR1cm4gc2VuZEpzb24ocmVzLCAyMDAsIHsgb2s6IGZhbHNlIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdhdGUudmVyaWZ5KHBhcnNlZC5kYXRhLmVtYWlsLCBwYXJzZWQuZGF0YS5jb2RlLCBjbGllbnRJcChyZXEpKTtcbiAgICBjb25zdCBjb29raWUgPVxuICAgICAgcmVzdWx0Lm9rICYmIHJlc3VsdC50b2tlbiA/IHNlc3Npb25Db29raWUocmVzdWx0LnRva2VuLCBnYXRlLnNlc3Npb25UdGxTZWNvbmRzKSA6IHVuZGVmaW5lZDtcbiAgICBzZW5kSnNvbihcbiAgICAgIHJlcyxcbiAgICAgIDIwMCxcbiAgICAgIHsgb2s6IHJlc3VsdC5vaywgLi4uKHJlc3VsdC5yZXRyeUFmdGVyID8geyByZXRyeUFmdGVyOiByZXN1bHQucmV0cnlBZnRlciB9IDoge30pIH0sXG4gICAgICBjb29raWUsXG4gICAgKTtcbiAgfSkgYXMgUmVxdWVzdEhhbmRsZXI7XG5cbiAgY29uc3QgbG9nb3V0SGFuZGxlciA9ICgoX3JlcSwgcmVzKSA9PiB7XG4gICAgc2VuZEpzb24ocmVzLCAyMDAsIHsgb2s6IHRydWUgfSwgYCR7U0VTU0lPTl9DT09LSUVfTkFNRX09OyBQYXRoPS87IEh0dHBPbmx5OyBNYXgtQWdlPTBgKTtcbiAgfSkgYXMgUmVxdWVzdEhhbmRsZXI7XG5cbiAgYWRkUm91dGUoXCJnZXRcIiwgYCR7QVVUSF9QUkVGSVh9L3N0YXR1c2AsIHN0YXR1c0hhbmRsZXIpO1xuICBhZGRSb3V0ZShcInBvc3RcIiwgYCR7QVVUSF9QUkVGSVh9L3JlcXVlc3RgLCByZXF1ZXN0SGFuZGxlcik7XG4gIGFkZFJvdXRlKFwicG9zdFwiLCBgJHtBVVRIX1BSRUZJWH0vdmVyaWZ5YCwgdmVyaWZ5SGFuZGxlcik7XG4gIGFkZFJvdXRlKFwicG9zdFwiLCBgJHtBVVRIX1BSRUZJWH0vbG9nb3V0YCwgbG9nb3V0SGFuZGxlcik7XG5cbiAgLy8gLS0tIFRoZSBnYXRlIG1pZGRsZXdhcmUgKHJ1bnMgYmVmb3JlIHN0YXRpYyArIHRoZSBhcHAncyAvYXBpIGhhbmRsZXJzKSAtLS1cblxuICBjb25zdCBnYXRlTWlkZGxld2FyZSA9IChhc3luYyAocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICAvLyBOb3QgdHVubmVsIHRyYWZmaWMgKHBsYXRmb3JtIGZyb250IGRvb3IsIG9yIGFueSBvdGhlciBsb2NhbCBjYWxsZXIpOiB0aGVcbiAgICAvLyByZXF1ZXN0IGlzIGFscmVhZHkgYXV0aGVudGljYXRlZCAob3IgaXMgbm90IG91cnMgdG8gZ2F0ZSkuIFBhc3MgdGhyb3VnaC5cbiAgICBpZiAoIWlzVHVubmVsSG9zdChyZXEsIHB1YmxpY0RvbWFpbikpIHJldHVybiBuZXh0KCk7XG5cbiAgICBjb25zdCBwYXRoID0gKHJlcS51cmwgPz8gXCIvXCIpLnNwbGl0KFwiP1wiKVswXSA/PyBcIi9cIjtcblxuICAgIC8vIFRoZSBsb2dpbiBmbG93IGlzIG9wZW4gc28gdGhlIGJyb3dzZXIgY2FuIHJlbmRlciA8QXV0aEdhdGU+IGFuZCBzaWduIGluLlxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoQVVUSF9QUkVGSVgpKSByZXR1cm4gbmV4dCgpO1xuXG4gICAgLy8gQW50aS1zcG9vZjogb25seSB0aGUgZ2F0ZSBtYXkgYXNzZXJ0IGlkZW50aXR5IG9uIHR1bm5lbCB0cmFmZmljLlxuICAgIGFwcGx5SGVhZGVyUG9saWN5KHJlcSk7XG5cbiAgICAvLyBTdGF0aWMgKG5vbi1BUEkpIGxvYWRzIGZyZWVseSBzbyB0aGUgU1BBIGNhbiByZW5kZXI7IGRyb3AgdGhlIGdhdGUgY29va2llLlxuICAgIGlmICghcGF0aC5zdGFydHNXaXRoKFwiL2FwaS9cIikpIHtcbiAgICAgIHN0cmlwU2Vzc2lvbkNvb2tpZShyZXEpO1xuICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICB9XG5cbiAgICAvLyBFdmVyeSBvdGhlciAvYXBpLyogbmVlZHMgYSB2YWxpZCBPVFAgc2Vzc2lvbi5cbiAgICBjb25zdCBjb29raWUgPSBodHRwLnBhcnNlQ29va2llcyhyZXEuaGVhZGVycy5jb29raWUgPz8gbnVsbClbU0VTU0lPTl9DT09LSUVfTkFNRV07XG4gICAgY29uc3QgZW1haWwgPSBhd2FpdCBnYXRlLnNlc3Npb24oY29va2llKTtcbiAgICBpZiAoIWVtYWlsKSB7XG4gICAgICBzZW5kSnNvbihyZXMsIDQwMSwgeyBlcnJvcjogXCJhdXRoZW50aWNhdGlvbiByZXF1aXJlZFwiLCBsb2dpblBhdGg6IEFVVEhfUFJFRklYIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpbmplY3RJZGVudGl0eShyZXEsIGVtYWlsKTtcbiAgICBzdHJpcFNlc3Npb25Db29raWUocmVxKTtcbiAgICBuZXh0KCk7XG4gIH0pIGFzIFJlcXVlc3RIYW5kbGVyO1xuXG4gIGFkZE1pZGRsZXdhcmUoXCIvXCIsIGdhdGVNaWRkbGV3YXJlKTtcbn1cbiJdfQ==
@@ -16,10 +16,10 @@
16
16
  * 4. registers an AppKit `shutdown` lifecycle handler so an orderly app shutdown
17
17
  * also stops portr.
18
18
  *
19
- * The email-OTP GATE is a separate concern: it is the {@link authGate} AppKit
20
- * plugin plus the {@link startProxy} reverse-proxy, both exported from this package
21
- * for an app that wants to gate the tunnelled traffic. This interceptor is only the
22
- * portr half - "update the host, bind portr" - matching the smallest useful unit.
19
+ * The email-OTP GATE is a separate concern: it is the `authGate` AppKit plugin,
20
+ * which registers the login routes + a gating middleware on the app's own server.
21
+ * Register it in the app's `plugins` for gated traffic. This interceptor is only
22
+ * the portr half - "update the host, bind portr" - the smallest useful unit.
23
23
  *
24
24
  * @module
25
25
  */
@@ -16,10 +16,10 @@
16
16
  * 4. registers an AppKit `shutdown` lifecycle handler so an orderly app shutdown
17
17
  * also stops portr.
18
18
  *
19
- * The email-OTP GATE is a separate concern: it is the {@link authGate} AppKit
20
- * plugin plus the {@link startProxy} reverse-proxy, both exported from this package
21
- * for an app that wants to gate the tunnelled traffic. This interceptor is only the
22
- * portr half - "update the host, bind portr" - matching the smallest useful unit.
19
+ * The email-OTP GATE is a separate concern: it is the `authGate` AppKit plugin,
20
+ * which registers the login routes + a gating middleware on the app's own server.
21
+ * Register it in the app's `plugins` for gated traffic. This interceptor is only
22
+ * the portr half - "update the host, bind portr" - the smallest useful unit.
23
23
  *
24
24
  * @module
25
25
  */
@@ -81,4 +81,4 @@ export function tunnelInterceptor(options = {}) {
81
81
  logger.info(`tunnel bound: portr -> :${port} (${portrConfig.subdomain}.${portrConfig.server})`);
82
82
  };
83
83
  }
84
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJjZXB0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW50ZXJjZXB0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdCRztBQUdILE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUU1RixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUM7QUFnQmhELHFGQUFxRjtBQUNyRixTQUFTLGlCQUFpQixDQUFDLElBQWE7SUFDdEMsT0FBTyxJQUFJLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLElBQUksSUFBSSxDQUFDLENBQUM7QUFDakUsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxVQUFvQyxFQUFFO0lBQ3RFLE9BQU8sQ0FBQyxHQUF1QixFQUFRLEVBQUU7UUFDdkMsNkVBQTZFO1FBQzdFLDhFQUE4RTtRQUM5RSw2REFBNkQ7UUFDN0QsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDO1FBQ3pELENBQUM7UUFFRCxnRkFBZ0Y7UUFDaEYsZ0ZBQWdGO1FBQ2hGLHFEQUFxRDtRQUNyRCxNQUFNLElBQUksR0FBRyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLENBQUM7WUFDckMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1lBQ2xDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztZQUM1QixJQUFJO1NBQ0wsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsNEVBQTRFLENBQUMsQ0FBQztZQUMxRixPQUFPO1FBQ1QsQ0FBQztRQUVELCtFQUErRTtRQUMvRSxNQUFNLFFBQVEsR0FBRyxZQUFZLEVBQUUsQ0FBQztRQUNoQyxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNoRCxHQUFHLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXZCLCtFQUErRTtRQUMvRSwyREFBMkQ7UUFDM0QsR0FBRyxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFO1lBQy9CLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtnQkFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsSUFBSSxLQUFLLFdBQVcsQ0FBQyxTQUFTLElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDbEcsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYHR1bm5lbEludGVyY2VwdG9yKClgIC0gdGhlIHtAbGluayBJbnRlcmNlcHRvcn0gdGhhdCBmcm9udHMgYW4gYXBwIHdpdGggYSBwdWJsaWNcbiAqIHBvcnRyIHR1bm5lbCwgY29uc3VtaW5nIHRoZSB7QGxpbmsgSW50ZXJjZXB0b3JDb250ZXh0fSBgQGRieC10b29scy9hcHBraXRgJ3NcbiAqIGBjcmVhdGVBcHBgIGhhbmRzIGl0LlxuICpcbiAqIFRoaXMgaXMgdGhlIGluLXByb2Nlc3MgcmVwbGFjZW1lbnQgZm9yIHRoZSBvbGQgYGRieHQtdHVubmVsIC0tIDxjbWQ+YCB3cmFwcGVyLlxuICogSW5zdGVhZCBvZiB0aGUgdHVubmVsIGJlaW5nIHRoZSBtYWluIHByb2Nlc3MgdGhhdCBzcGF3bnMgdGhlIGFwcCBhcyBhIGNoaWxkLCB0aGVcbiAqIEFQUCBpcyB0aGUgbWFpbiBwcm9jZXNzIGFuZCBoYW5kcyB0aGlzIGludGVyY2VwdG9yIGl0cyBjb250ZXh0LiBUaGUgaW50ZXJjZXB0b3I6XG4gKlxuICogICAxLiBhcHBsaWVzIHRoZSB3b3Jrc3BhY2UgaG9zdCB0aGUgY29udGV4dCBjb21wdXRlZCB0byBgcHJvY2Vzcy5lbnZgXG4gKiAgICAgIChgREFUQUJSSUNLU19IT1NUYCksIHNvIHBvcnRyIGFuZCBhbnkgbGF0ZXIgU0RLIGNhbGwgYWdyZWUgb24gdGhlIHdvcmtzcGFjZTtcbiAqICAgMi4gaW5zdGFsbHMgKyBsYXVuY2hlcyBwb3J0ciwgcG9pbnRlZCBhdCB0aGUgYXBwJ3MgUFVCTElDIHBvcnQ7XG4gKiAgIDMuIGBiaW5kUHJvY2Vzc2BlcyBwb3J0ciBzbyB0aGUgYXBwIGFuZCB0aGUgdHVubmVsIGxpdmUgYW5kIGRpZSBhcyBvbmUgLVxuICogICAgICBzaWduYWxzIHBhc3MgdGhyb3VnaCBhbmQgZWl0aGVyIGRlYXRoIHRlYXJzIHRoZSBwYWlyIGRvd24gKHRoZVxuICogICAgICBjb25jdXJyZW50bHktc3R5bGUgc3VwZXJ2aXNpb24gdGhhdCB1c2VkIHRvIGJlIGBzdXBlcnZpc2VFeGl0YCk7XG4gKiAgIDQuIHJlZ2lzdGVycyBhbiBBcHBLaXQgYHNodXRkb3duYCBsaWZlY3ljbGUgaGFuZGxlciBzbyBhbiBvcmRlcmx5IGFwcCBzaHV0ZG93blxuICogICAgICBhbHNvIHN0b3BzIHBvcnRyLlxuICpcbiAqIFRoZSBlbWFpbC1PVFAgR0FURSBpcyBhIHNlcGFyYXRlIGNvbmNlcm46IGl0IGlzIHRoZSB7QGxpbmsgYXV0aEdhdGV9IEFwcEtpdFxuICogcGx1Z2luIHBsdXMgdGhlIHtAbGluayBzdGFydFByb3h5fSByZXZlcnNlLXByb3h5LCBib3RoIGV4cG9ydGVkIGZyb20gdGhpcyBwYWNrYWdlXG4gKiBmb3IgYW4gYXBwIHRoYXQgd2FudHMgdG8gZ2F0ZSB0aGUgdHVubmVsbGVkIHRyYWZmaWMuIFRoaXMgaW50ZXJjZXB0b3IgaXMgb25seSB0aGVcbiAqIHBvcnRyIGhhbGYgLSBcInVwZGF0ZSB0aGUgaG9zdCwgYmluZCBwb3J0clwiIC0gbWF0Y2hpbmcgdGhlIHNtYWxsZXN0IHVzZWZ1bCB1bml0LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IEludGVyY2VwdG9yLCBJbnRlcmNlcHRvckNvbnRleHQgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBpbnN0YWxsUG9ydHIsIHJlc29sdmVQb3J0ckNvbmZpZywgc3RhcnRQb3J0ciwgd3JpdGVQb3J0ckNvbmZpZyB9IGZyb20gXCIuL3BvcnRyLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0dW5uZWw6aW50ZXJjZXB0b3JcIik7XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgdHVubmVsSW50ZXJjZXB0b3J9IChlYWNoIGFsc28gcmVzb2x2YWJsZSBmcm9tIGVudikuICovXG5leHBvcnQgaW50ZXJmYWNlIFR1bm5lbEludGVyY2VwdG9yT3B0aW9ucyB7XG4gIC8qKiBwb3J0ciBgPHN1YmRvbWFpbj4uPHNlcnZlcj5gIHRvIHNlcnZlIG9uLiBFbnYgYFRVTk5FTF9QVUJMSUNfRE9NQUlOYC4gKi9cbiAgcHVibGljRG9tYWluPzogc3RyaW5nO1xuICAvKiogcG9ydHIgc3ViZG9tYWluIChlbHNlIGRlcml2ZWQgZnJvbSB7QGxpbmsgcHVibGljRG9tYWlufSkuICovXG4gIHN1YmRvbWFpbj86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBQVUJMSUMgcG9ydCBwb3J0ciBmb3J3YXJkcyB0byAtIHRoZSBwb3J0IHRoZSBhcHAgaXRzZWxmIGxpc3RlbnMgb24uXG4gICAqIERlZmF1bHRzIHRvIHRoZSBEYXRhYnJpY2tzIEFwcHMgcnVudGltZSBjb250cmFjdCBgREFUQUJSSUNLU19BUFBfUE9SVGBcbiAgICogKHRoZW4gYDgwMDBgKSwgd2hpY2ggaXMgdGhlIHBvcnQgdGhlIHBsYXRmb3JtIHJvdXRlcyB0by5cbiAgICovXG4gIHBvcnQ/OiBudW1iZXI7XG59XG5cbi8qKiBSZXNvbHZlIHRoZSBwdWJsaWMgcG9ydCBwb3J0ciBzaG91bGQgdGFyZ2V0OiBleHBsaWNpdCwgZWxzZSB0aGUgQXBwcyBjb250cmFjdC4gKi9cbmZ1bmN0aW9uIHJlc29sdmVQdWJsaWNQb3J0KHBvcnQ/OiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gcG9ydCA/PyBOdW1iZXIocHJvY2Vzcy5lbnYuREFUQUJSSUNLU19BUFBfUE9SVCA/PyA4MDAwKTtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgdHVubmVsIHtAbGluayBJbnRlcmNlcHRvcn0uIFBhc3MgaXQgdG8gYGNyZWF0ZUFwcCh7IGludGVyY2VwdG9yIH0pYC5cbiAqXG4gKiBBIG5vLW9wIChsb2dzIGFuZCByZXR1cm5zKSB3aGVuIG5vIHBvcnRyIHR1bm5lbCBpcyBjb25maWd1cmVkIC0gbm8gYFBPUlRSX1RPS0VOYFxuICogb3Igbm8gcmVzb2x2YWJsZSBgPHN1YmRvbWFpbj4uPHNlcnZlcj5gIC0gc28gYW4gYXBwIGNhbiByZWdpc3RlciBpdFxuICogdW5jb25kaXRpb25hbGx5IGFuZCBvbmx5IGFjdHVhbGx5IHR1bm5lbHMgd2hlcmUgdGhlIGRlcGxveW1lbnQgd2lyZWQgcG9ydHIuXG4gKlxuICogQGV4YW1wbGVcbiAqIGltcG9ydCB7IGNyZWF0ZUFwcCB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdFwiO1xuICogaW1wb3J0IHsgdHVubmVsSW50ZXJjZXB0b3IgfSBmcm9tIFwiQGRieC10b29scy90dW5uZWxcIjtcbiAqXG4gKiBhd2FpdCBjcmVhdGVBcHAoe1xuICogICBwbHVnaW5zOiBbc2VydmVyKHsgaG9zdCwgc3RhdGljUGF0aCB9KV0sXG4gKiAgIGludGVyY2VwdG9yOiB0dW5uZWxJbnRlcmNlcHRvcigpLFxuICogfSk7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0dW5uZWxJbnRlcmNlcHRvcihvcHRpb25zOiBUdW5uZWxJbnRlcmNlcHRvck9wdGlvbnMgPSB7fSk6IEludGVyY2VwdG9yIHtcbiAgcmV0dXJuIChjdHg6IEludGVyY2VwdG9yQ29udGV4dCk6IHZvaWQgPT4ge1xuICAgIC8vIDEuIEFwcGx5IHRoZSBjb21wdXRlZCB3b3Jrc3BhY2UgaG9zdCBzbyBwb3J0ciArIHRoZSBTREsgYWdyZWUuIFRoZSBjb250ZXh0XG4gICAgLy8gICAgYWxyZWFkeSByZXNvbHZlZCBpdCAoZnJvbSB0aGUgZW52IC8gYXV0by1jb25maWcpOyBzZXQgaXQgb25seSB3aGVuIGl0IGlzXG4gICAgLy8gICAga25vd24gYW5kIG5vdCBhbHJlYWR5IHByZXNlbnQsIHNvIGFuIGV4cGxpY2l0IGVudiB3aW5zLlxuICAgIGlmIChjdHguZW52LmRhdGFicmlja3NIb3N0KSB7XG4gICAgICBwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX0hPU1QgPz89IGN0eC5lbnYuZGF0YWJyaWNrc0hvc3Q7XG4gICAgfVxuXG4gICAgLy8gMi4gUmVzb2x2ZSBwb3J0ciB3aXJpbmcuIE5vIHRva2VuIC8gZG9tYWluIC0+IG5vIHR1bm5lbDsgbGVhdmUgdGhlIGFwcCBhbG9uZS5cbiAgICAvLyAgICBgcmVzb2x2ZVBvcnRyQ29uZmlnYCBhbHJlYWR5IGZhbGxzIGJhY2sgdG8gVFVOTkVMX1BVQkxJQ19ET01BSU4gaXRzZWxmLCBzb1xuICAgIC8vICAgIHRoZSBleHBsaWNpdCBvcHRpb24gaXMgcGFzc2VkIHN0cmFpZ2h0IHRocm91Z2guXG4gICAgY29uc3QgcG9ydCA9IHJlc29sdmVQdWJsaWNQb3J0KG9wdGlvbnMucG9ydCk7XG4gICAgY29uc3QgcG9ydHJDb25maWcgPSByZXNvbHZlUG9ydHJDb25maWcoe1xuICAgICAgcHVibGljRG9tYWluOiBvcHRpb25zLnB1YmxpY0RvbWFpbixcbiAgICAgIHN1YmRvbWFpbjogb3B0aW9ucy5zdWJkb21haW4sXG4gICAgICBwb3J0LFxuICAgIH0pO1xuICAgIGlmICghcG9ydHJDb25maWcpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFwibm8gUE9SVFJfVE9LRU4vVFVOTkVMX1BVQkxJQ19ET01BSU4gLSB0aGUgYXBwIHJ1bnMgd2l0aG91dCBhIHB1YmxpYyB0dW5uZWxcIik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gMy4gSW5zdGFsbCArIGxhdW5jaCBwb3J0ciwgdGhlbiBiaW5kIGl0OiB0aGUgYXBwIGFuZCBwb3J0ciBub3cgc2hhcmUgYSBmYXRlLlxuICAgIGNvbnN0IHBvcnRyRW52ID0gaW5zdGFsbFBvcnRyKCk7XG4gICAgd3JpdGVQb3J0ckNvbmZpZyhwb3J0ckNvbmZpZywgcG9ydHJFbnYpO1xuICAgIGNvbnN0IHBvcnRyID0gc3RhcnRQb3J0cihwb3J0ckNvbmZpZywgcG9ydHJFbnYpO1xuICAgIGN0eC5iaW5kUHJvY2Vzcyhwb3J0cik7XG5cbiAgICAvLyA0LiBBbiBvcmRlcmx5IEFwcEtpdCBzaHV0ZG93biBhbHNvIHN0b3BzIHBvcnRyIChiZWx0LWFuZC1zdXNwZW5kZXJzIHdpdGggdGhlXG4gICAgLy8gICAgc2lnbmFsIHBhc3MtdGhyb3VnaCBgYmluZFByb2Nlc3NgIGFscmVhZHkgaW5zdGFsbGVkKS5cbiAgICBjdHgub25MaWZlY3ljbGUoXCJzaHV0ZG93blwiLCAoKSA9PiB7XG4gICAgICBpZiAoIXBvcnRyLmtpbGxlZCkgcG9ydHIua2lsbChcIlNJR1RFUk1cIik7XG4gICAgfSk7XG5cbiAgICBsb2dnZXIuaW5mbyhgdHVubmVsIGJvdW5kOiBwb3J0ciAtPiA6JHtwb3J0fSAoJHtwb3J0ckNvbmZpZy5zdWJkb21haW59LiR7cG9ydHJDb25maWcuc2VydmVyfSlgKTtcbiAgfTtcbn1cbiJdfQ==
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJjZXB0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW50ZXJjZXB0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdCRztBQUdILE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUU1RixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUM7QUFnQmhELHFGQUFxRjtBQUNyRixTQUFTLGlCQUFpQixDQUFDLElBQWE7SUFDdEMsT0FBTyxJQUFJLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLElBQUksSUFBSSxDQUFDLENBQUM7QUFDakUsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxVQUFvQyxFQUFFO0lBQ3RFLE9BQU8sQ0FBQyxHQUF1QixFQUFRLEVBQUU7UUFDdkMsNkVBQTZFO1FBQzdFLDhFQUE4RTtRQUM5RSw2REFBNkQ7UUFDN0QsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDO1FBQ3pELENBQUM7UUFFRCxnRkFBZ0Y7UUFDaEYsZ0ZBQWdGO1FBQ2hGLHFEQUFxRDtRQUNyRCxNQUFNLElBQUksR0FBRyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLENBQUM7WUFDckMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1lBQ2xDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztZQUM1QixJQUFJO1NBQ0wsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsNEVBQTRFLENBQUMsQ0FBQztZQUMxRixPQUFPO1FBQ1QsQ0FBQztRQUVELCtFQUErRTtRQUMvRSxNQUFNLFFBQVEsR0FBRyxZQUFZLEVBQUUsQ0FBQztRQUNoQyxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNoRCxHQUFHLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXZCLCtFQUErRTtRQUMvRSwyREFBMkQ7UUFDM0QsR0FBRyxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFO1lBQy9CLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtnQkFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsSUFBSSxLQUFLLFdBQVcsQ0FBQyxTQUFTLElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDbEcsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYHR1bm5lbEludGVyY2VwdG9yKClgIC0gdGhlIHtAbGluayBJbnRlcmNlcHRvcn0gdGhhdCBmcm9udHMgYW4gYXBwIHdpdGggYSBwdWJsaWNcbiAqIHBvcnRyIHR1bm5lbCwgY29uc3VtaW5nIHRoZSB7QGxpbmsgSW50ZXJjZXB0b3JDb250ZXh0fSBgQGRieC10b29scy9hcHBraXRgJ3NcbiAqIGBjcmVhdGVBcHBgIGhhbmRzIGl0LlxuICpcbiAqIFRoaXMgaXMgdGhlIGluLXByb2Nlc3MgcmVwbGFjZW1lbnQgZm9yIHRoZSBvbGQgYGRieHQtdHVubmVsIC0tIDxjbWQ+YCB3cmFwcGVyLlxuICogSW5zdGVhZCBvZiB0aGUgdHVubmVsIGJlaW5nIHRoZSBtYWluIHByb2Nlc3MgdGhhdCBzcGF3bnMgdGhlIGFwcCBhcyBhIGNoaWxkLCB0aGVcbiAqIEFQUCBpcyB0aGUgbWFpbiBwcm9jZXNzIGFuZCBoYW5kcyB0aGlzIGludGVyY2VwdG9yIGl0cyBjb250ZXh0LiBUaGUgaW50ZXJjZXB0b3I6XG4gKlxuICogICAxLiBhcHBsaWVzIHRoZSB3b3Jrc3BhY2UgaG9zdCB0aGUgY29udGV4dCBjb21wdXRlZCB0byBgcHJvY2Vzcy5lbnZgXG4gKiAgICAgIChgREFUQUJSSUNLU19IT1NUYCksIHNvIHBvcnRyIGFuZCBhbnkgbGF0ZXIgU0RLIGNhbGwgYWdyZWUgb24gdGhlIHdvcmtzcGFjZTtcbiAqICAgMi4gaW5zdGFsbHMgKyBsYXVuY2hlcyBwb3J0ciwgcG9pbnRlZCBhdCB0aGUgYXBwJ3MgUFVCTElDIHBvcnQ7XG4gKiAgIDMuIGBiaW5kUHJvY2Vzc2BlcyBwb3J0ciBzbyB0aGUgYXBwIGFuZCB0aGUgdHVubmVsIGxpdmUgYW5kIGRpZSBhcyBvbmUgLVxuICogICAgICBzaWduYWxzIHBhc3MgdGhyb3VnaCBhbmQgZWl0aGVyIGRlYXRoIHRlYXJzIHRoZSBwYWlyIGRvd24gKHRoZVxuICogICAgICBjb25jdXJyZW50bHktc3R5bGUgc3VwZXJ2aXNpb24gdGhhdCB1c2VkIHRvIGJlIGBzdXBlcnZpc2VFeGl0YCk7XG4gKiAgIDQuIHJlZ2lzdGVycyBhbiBBcHBLaXQgYHNodXRkb3duYCBsaWZlY3ljbGUgaGFuZGxlciBzbyBhbiBvcmRlcmx5IGFwcCBzaHV0ZG93blxuICogICAgICBhbHNvIHN0b3BzIHBvcnRyLlxuICpcbiAqIFRoZSBlbWFpbC1PVFAgR0FURSBpcyBhIHNlcGFyYXRlIGNvbmNlcm46IGl0IGlzIHRoZSBgYXV0aEdhdGVgIEFwcEtpdCBwbHVnaW4sXG4gKiB3aGljaCByZWdpc3RlcnMgdGhlIGxvZ2luIHJvdXRlcyArIGEgZ2F0aW5nIG1pZGRsZXdhcmUgb24gdGhlIGFwcCdzIG93biBzZXJ2ZXIuXG4gKiBSZWdpc3RlciBpdCBpbiB0aGUgYXBwJ3MgYHBsdWdpbnNgIGZvciBnYXRlZCB0cmFmZmljLiBUaGlzIGludGVyY2VwdG9yIGlzIG9ubHlcbiAqIHRoZSBwb3J0ciBoYWxmIC0gXCJ1cGRhdGUgdGhlIGhvc3QsIGJpbmQgcG9ydHJcIiAtIHRoZSBzbWFsbGVzdCB1c2VmdWwgdW5pdC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBJbnRlcmNlcHRvciwgSW50ZXJjZXB0b3JDb250ZXh0IH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG5pbXBvcnQgeyBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgaW5zdGFsbFBvcnRyLCByZXNvbHZlUG9ydHJDb25maWcsIHN0YXJ0UG9ydHIsIHdyaXRlUG9ydHJDb25maWcgfSBmcm9tIFwiLi9wb3J0ci50c1wiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwidHVubmVsOmludGVyY2VwdG9yXCIpO1xuXG4vKiogT3B0aW9ucyBmb3Ige0BsaW5rIHR1bm5lbEludGVyY2VwdG9yfSAoZWFjaCBhbHNvIHJlc29sdmFibGUgZnJvbSBlbnYpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUdW5uZWxJbnRlcmNlcHRvck9wdGlvbnMge1xuICAvKiogcG9ydHIgYDxzdWJkb21haW4+LjxzZXJ2ZXI+YCB0byBzZXJ2ZSBvbi4gRW52IGBUVU5ORUxfUFVCTElDX0RPTUFJTmAuICovXG4gIHB1YmxpY0RvbWFpbj86IHN0cmluZztcbiAgLyoqIHBvcnRyIHN1YmRvbWFpbiAoZWxzZSBkZXJpdmVkIGZyb20ge0BsaW5rIHB1YmxpY0RvbWFpbn0pLiAqL1xuICBzdWJkb21haW4/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgUFVCTElDIHBvcnQgcG9ydHIgZm9yd2FyZHMgdG8gLSB0aGUgcG9ydCB0aGUgYXBwIGl0c2VsZiBsaXN0ZW5zIG9uLlxuICAgKiBEZWZhdWx0cyB0byB0aGUgRGF0YWJyaWNrcyBBcHBzIHJ1bnRpbWUgY29udHJhY3QgYERBVEFCUklDS1NfQVBQX1BPUlRgXG4gICAqICh0aGVuIGA4MDAwYCksIHdoaWNoIGlzIHRoZSBwb3J0IHRoZSBwbGF0Zm9ybSByb3V0ZXMgdG8uXG4gICAqL1xuICBwb3J0PzogbnVtYmVyO1xufVxuXG4vKiogUmVzb2x2ZSB0aGUgcHVibGljIHBvcnQgcG9ydHIgc2hvdWxkIHRhcmdldDogZXhwbGljaXQsIGVsc2UgdGhlIEFwcHMgY29udHJhY3QuICovXG5mdW5jdGlvbiByZXNvbHZlUHVibGljUG9ydChwb3J0PzogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIHBvcnQgPz8gTnVtYmVyKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX1BPUlQgPz8gODAwMCk7XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIHR1bm5lbCB7QGxpbmsgSW50ZXJjZXB0b3J9LiBQYXNzIGl0IHRvIGBjcmVhdGVBcHAoeyBpbnRlcmNlcHRvciB9KWAuXG4gKlxuICogQSBuby1vcCAobG9ncyBhbmQgcmV0dXJucykgd2hlbiBubyBwb3J0ciB0dW5uZWwgaXMgY29uZmlndXJlZCAtIG5vIGBQT1JUUl9UT0tFTmBcbiAqIG9yIG5vIHJlc29sdmFibGUgYDxzdWJkb21haW4+LjxzZXJ2ZXI+YCAtIHNvIGFuIGFwcCBjYW4gcmVnaXN0ZXIgaXRcbiAqIHVuY29uZGl0aW9uYWxseSBhbmQgb25seSBhY3R1YWxseSB0dW5uZWxzIHdoZXJlIHRoZSBkZXBsb3ltZW50IHdpcmVkIHBvcnRyLlxuICpcbiAqIEBleGFtcGxlXG4gKiBpbXBvcnQgeyBjcmVhdGVBcHAgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXRcIjtcbiAqIGltcG9ydCB7IHR1bm5lbEludGVyY2VwdG9yIH0gZnJvbSBcIkBkYngtdG9vbHMvdHVubmVsXCI7XG4gKlxuICogYXdhaXQgY3JlYXRlQXBwKHtcbiAqICAgcGx1Z2luczogW3NlcnZlcih7IGhvc3QsIHN0YXRpY1BhdGggfSldLFxuICogICBpbnRlcmNlcHRvcjogdHVubmVsSW50ZXJjZXB0b3IoKSxcbiAqIH0pO1xuICovXG5leHBvcnQgZnVuY3Rpb24gdHVubmVsSW50ZXJjZXB0b3Iob3B0aW9uczogVHVubmVsSW50ZXJjZXB0b3JPcHRpb25zID0ge30pOiBJbnRlcmNlcHRvciB7XG4gIHJldHVybiAoY3R4OiBJbnRlcmNlcHRvckNvbnRleHQpOiB2b2lkID0+IHtcbiAgICAvLyAxLiBBcHBseSB0aGUgY29tcHV0ZWQgd29ya3NwYWNlIGhvc3Qgc28gcG9ydHIgKyB0aGUgU0RLIGFncmVlLiBUaGUgY29udGV4dFxuICAgIC8vICAgIGFscmVhZHkgcmVzb2x2ZWQgaXQgKGZyb20gdGhlIGVudiAvIGF1dG8tY29uZmlnKTsgc2V0IGl0IG9ubHkgd2hlbiBpdCBpc1xuICAgIC8vICAgIGtub3duIGFuZCBub3QgYWxyZWFkeSBwcmVzZW50LCBzbyBhbiBleHBsaWNpdCBlbnYgd2lucy5cbiAgICBpZiAoY3R4LmVudi5kYXRhYnJpY2tzSG9zdCkge1xuICAgICAgcHJvY2Vzcy5lbnYuREFUQUJSSUNLU19IT1NUID8/PSBjdHguZW52LmRhdGFicmlja3NIb3N0O1xuICAgIH1cblxuICAgIC8vIDIuIFJlc29sdmUgcG9ydHIgd2lyaW5nLiBObyB0b2tlbiAvIGRvbWFpbiAtPiBubyB0dW5uZWw7IGxlYXZlIHRoZSBhcHAgYWxvbmUuXG4gICAgLy8gICAgYHJlc29sdmVQb3J0ckNvbmZpZ2AgYWxyZWFkeSBmYWxscyBiYWNrIHRvIFRVTk5FTF9QVUJMSUNfRE9NQUlOIGl0c2VsZiwgc29cbiAgICAvLyAgICB0aGUgZXhwbGljaXQgb3B0aW9uIGlzIHBhc3NlZCBzdHJhaWdodCB0aHJvdWdoLlxuICAgIGNvbnN0IHBvcnQgPSByZXNvbHZlUHVibGljUG9ydChvcHRpb25zLnBvcnQpO1xuICAgIGNvbnN0IHBvcnRyQ29uZmlnID0gcmVzb2x2ZVBvcnRyQ29uZmlnKHtcbiAgICAgIHB1YmxpY0RvbWFpbjogb3B0aW9ucy5wdWJsaWNEb21haW4sXG4gICAgICBzdWJkb21haW46IG9wdGlvbnMuc3ViZG9tYWluLFxuICAgICAgcG9ydCxcbiAgICB9KTtcbiAgICBpZiAoIXBvcnRyQ29uZmlnKSB7XG4gICAgICBsb2dnZXIuaW5mbyhcIm5vIFBPUlRSX1RPS0VOL1RVTk5FTF9QVUJMSUNfRE9NQUlOIC0gdGhlIGFwcCBydW5zIHdpdGhvdXQgYSBwdWJsaWMgdHVubmVsXCIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIDMuIEluc3RhbGwgKyBsYXVuY2ggcG9ydHIsIHRoZW4gYmluZCBpdDogdGhlIGFwcCBhbmQgcG9ydHIgbm93IHNoYXJlIGEgZmF0ZS5cbiAgICBjb25zdCBwb3J0ckVudiA9IGluc3RhbGxQb3J0cigpO1xuICAgIHdyaXRlUG9ydHJDb25maWcocG9ydHJDb25maWcsIHBvcnRyRW52KTtcbiAgICBjb25zdCBwb3J0ciA9IHN0YXJ0UG9ydHIocG9ydHJDb25maWcsIHBvcnRyRW52KTtcbiAgICBjdHguYmluZFByb2Nlc3MocG9ydHIpO1xuXG4gICAgLy8gNC4gQW4gb3JkZXJseSBBcHBLaXQgc2h1dGRvd24gYWxzbyBzdG9wcyBwb3J0ciAoYmVsdC1hbmQtc3VzcGVuZGVycyB3aXRoIHRoZVxuICAgIC8vICAgIHNpZ25hbCBwYXNzLXRocm91Z2ggYGJpbmRQcm9jZXNzYCBhbHJlYWR5IGluc3RhbGxlZCkuXG4gICAgY3R4Lm9uTGlmZWN5Y2xlKFwic2h1dGRvd25cIiwgKCkgPT4ge1xuICAgICAgaWYgKCFwb3J0ci5raWxsZWQpIHBvcnRyLmtpbGwoXCJTSUdURVJNXCIpO1xuICAgIH0pO1xuXG4gICAgbG9nZ2VyLmluZm8oYHR1bm5lbCBib3VuZDogcG9ydHIgLT4gOiR7cG9ydH0gKCR7cG9ydHJDb25maWcuc3ViZG9tYWlufS4ke3BvcnRyQ29uZmlnLnNlcnZlcn0pYCk7XG4gIH07XG59XG4iXX0=
@@ -17,6 +17,14 @@
17
17
  */
18
18
  import { Plugin, type BasePluginConfig } from "@databricks/appkit";
19
19
  import type { AuthStatus } from "@dbx-tools/shared-email";
20
+ import type { RequestHandler } from "express";
21
+ import { type GateOptions } from "./gate.ts";
22
+ interface GateMountContext {
23
+ addRoute(method: string, path: string, handler: RequestHandler): void;
24
+ addMiddleware(path: string, handler: RequestHandler): void;
25
+ getPlugins(): ReadonlyMap<string, unknown>;
26
+ }
27
+ export declare function mountGateOnContext(context: GateMountContext, options: GateOptions): void;
20
28
  /** Options for the {@link authGate} plugin (all resolvable from env - see below). */
21
29
  export interface AuthGateConfig extends BasePluginConfig {
22
30
  /** Allow-list patterns (domain / glob / `/regex/`). Empty = allow nobody. Env TUNNEL_AUTH_ALLOW. */
@@ -72,8 +80,31 @@ export interface AuthGateConfig extends BasePluginConfig {
72
80
  * means no cutoff.
73
81
  */
74
82
  sessionCutoff?: string | number | Date;
75
- /** Deliver a code to an address. Wired by the app to the email plugin. */
83
+ /**
84
+ * Deliver a code to an address. Defaults to sending through the host app's
85
+ * shared `@dbx-tools/email` transport (see `./send-code`); override to wire a
86
+ * different delivery path.
87
+ */
76
88
  sendCode?: (email: string, code: string, opts: SendCodeOptions) => Promise<void>;
89
+ /**
90
+ * The public `<subdomain>.<server>` that identifies portr traffic by its `Host`
91
+ * header. Only requests whose `Host` matches this are gated; everything else
92
+ * (the platform front door, other local callers) passes through. Env
93
+ * `TUNNEL_PUBLIC_DOMAIN`. When absent, the gate is inert (nothing is tunnel
94
+ * traffic).
95
+ */
96
+ publicDomain?: string;
97
+ /**
98
+ * Extra `x-` request headers tunnel traffic may forward (literal / glob /
99
+ * `/regex/`), unioned with the built-in allow-list. Env `TUNNEL_FORWARD_HEADERS`.
100
+ */
101
+ forwardHeaders?: string | string[];
102
+ /**
103
+ * Run OPEN with no gate (env `TUNNEL_INSECURE=true`). The login routes and gate
104
+ * middleware are not mounted, and the SMTP fail-fast is skipped. Use only when
105
+ * the tunnel is deliberately public.
106
+ */
107
+ insecure?: boolean;
77
108
  }
78
109
  /** Branding/messaging passed to {@link AuthGateConfig.sendCode}. */
79
110
  export interface SendCodeOptions {
@@ -99,10 +130,16 @@ export interface ResolvedAuthGateConfig {
99
130
  maxAttempts: number;
100
131
  /** Force-clear cutoff in epoch ms; `0` when unset. */
101
132
  sessionCutoffMs: number;
133
+ /** Public domain that identifies portr traffic by `Host`; `undefined` = inert. */
134
+ publicDomain?: string;
135
+ /** Extra `x-` headers tunnel traffic may forward (unioned with the defaults). */
136
+ forwardHeaders: string[];
137
+ /** Run OPEN with no gate. */
138
+ insecure: boolean;
102
139
  }
103
140
  /** Merge {@link AuthGateConfig} over env over defaults into a resolved config. */
104
141
  export declare function resolveAuthGateConfig(config: AuthGateConfig): ResolvedAuthGateConfig;
105
- /** The handlers the proxy calls in-process (returned by {@link AuthGatePlugin.exports}). */
142
+ /** The handlers the gate middleware calls in-process (returned by {@link AuthGatePlugin.exports}). */
106
143
  export interface AuthGateApi {
107
144
  /** Handle a code request. Always resolves `{ ok: true }` (anti-enumeration). */
108
145
  request(email: string, ip: string): Promise<{
@@ -122,7 +159,13 @@ export interface AuthGateApi {
122
159
  /** The gate status payload (`enabled` is always true when this plugin runs). */
123
160
  status(token: string | undefined): Promise<AuthStatus>;
124
161
  }
125
- /** AppKit plugin owning the email-OTP gate's logic (no HTTP routes; proxy-driven). */
162
+ /**
163
+ * AppKit plugin owning the email-OTP gate. On `setup()` it registers the login
164
+ * routes (`/api/email/auth/*`) and a gating middleware on the app's OWN Express
165
+ * server via `this.context`, so a public portr caller must prove an email before
166
+ * reaching the app's `/api/*` - see `./gate`. Front-door (platform) traffic and
167
+ * other local callers pass through untouched (the gate keys on the `Host` header).
168
+ */
126
169
  export declare class AuthGatePlugin extends Plugin<AuthGateConfig> {
127
170
  static manifest: {
128
171
  name: "authGate";
@@ -139,9 +182,20 @@ export declare class AuthGatePlugin extends Plugin<AuthGateConfig> {
139
182
  private readonly requestLimiter;
140
183
  private readonly verifyLimiter;
141
184
  setup(): Promise<void>;
185
+ /**
186
+ * Register the login routes (`/api/email/auth/*`) and the gating middleware on
187
+ * the app's OWN Express server. At `setup:complete`, the deferred server plugin
188
+ * has constructed its Express app but has not injected plugin routes or static
189
+ * handling, so direct registration puts the gate first. The context's buffered
190
+ * route API remains a fallback for compatible non-standard server plugins.
191
+ */
192
+ private mountGateRoutes;
193
+ /** The code sender: the configured `sendCode`, else the shared-transport default. */
194
+ private get sendCode();
142
195
  exports(): AuthGateApi;
143
196
  private handleRequest;
144
197
  private handleVerify;
145
198
  }
146
199
  /** Factory: `authGate({ allow, subject, ... })` for an AppKit `plugins` array. */
147
200
  export declare const authGate: import("@databricks/appkit").ToPlugin<typeof AuthGatePlugin, AuthGateConfig, "authGate">;
201
+ export {};