@dbx-tools/cli-tunnel 0.6.59 → 0.6.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -364
- package/index.ts +2 -19
- package/lib/index.d.ts +2 -19
- package/lib/index.js +2 -15
- package/lib/src/app.d.ts +12 -123
- package/lib/src/app.js +22 -250
- package/lib/src/cli.d.ts +19 -22
- package/lib/src/cli.js +143 -128
- package/lib/src/options.d.ts +46 -0
- package/lib/src/options.js +51 -0
- package/lib/src/proxy.d.ts +27 -37
- package/lib/src/proxy.js +115 -220
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -81
- package/src/app.ts +20 -282
- package/src/cli.ts +152 -162
- package/src/options.ts +85 -0
- package/src/proxy.ts +139 -261
- package/bin/dbx-tools-tunnel.ts +0 -13
- package/lib/bin/dbx-tools-tunnel.d.ts +0 -2
- package/lib/bin/dbx-tools-tunnel.js +0 -14
- package/lib/src/allowlist.d.ts +0 -32
- package/lib/src/allowlist.js +0 -57
- package/lib/src/env.d.ts +0 -57
- package/lib/src/env.js +0 -60
- package/lib/src/headers.d.ts +0 -108
- package/lib/src/headers.js +0 -140
- package/lib/src/otp.d.ts +0 -49
- package/lib/src/otp.js +0 -124
- package/lib/src/plugin.d.ts +0 -147
- package/lib/src/plugin.js +0 -138
- package/lib/src/portr.d.ts +0 -40
- package/lib/src/portr.js +0 -93
- package/lib/src/rate-limit.d.ts +0 -35
- package/lib/src/rate-limit.js +0 -53
- package/lib/src/signing-key.d.ts +0 -86
- package/lib/src/signing-key.js +0 -170
- package/src/allowlist.ts +0 -60
- package/src/env.ts +0 -72
- package/src/headers.ts +0 -155
- package/src/otp.ts +0 -137
- package/src/plugin.ts +0 -269
- package/src/portr.ts +0 -113
- package/src/rate-limit.ts +0 -59
- package/src/signing-key.ts +0 -201
package/lib/src/cli.js
CHANGED
|
@@ -1,159 +1,174 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `dbx
|
|
2
|
+
* `dbx tunnel` - front a command with a public portr tunnel and an email-OTP gate.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* This is the WRAPPER path, and it exists for one case: a project that does not
|
|
5
|
+
* use `@dbx-tools/appkit`'s `createApp`, and therefore cannot register
|
|
6
|
+
* `tunnelInterceptor()` + the `authGate` plugin in-process. An AppKit app should
|
|
7
|
+
* still take the plugin path - one process, no proxy hop, no duplicated header
|
|
8
|
+
* handling.
|
|
6
9
|
*
|
|
7
|
-
*
|
|
10
|
+
* The wrapper claims the PUBLIC port (`DATABRICKS_APP_PORT`, the port the
|
|
11
|
+
* platform and portr route to), moves the wrapped app to a private one, and
|
|
12
|
+
* reverse-proxies between them so the gate sits in front of traffic it would
|
|
13
|
+
* otherwise have no way to intercept. Everything else is delegated: the gate
|
|
14
|
+
* config comes from `plugin.resolveAuthGateConfig`, the portr lifecycle from
|
|
15
|
+
* `portr.*` - both the same functions the in-process path uses.
|
|
8
16
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* platform-neutral and honours whatever port it finds there.
|
|
14
|
-
* 2. Boot the tiny gate AppKit app (no server): inits `CacheManager` + the
|
|
15
|
-
* email transport, yields the in-process gate API.
|
|
16
|
-
* 3. Start the gate PROXY on the ORIGINAL public port, forwarding to the app.
|
|
17
|
-
* 4. Install + run portr pointed at the public port (when a tunnel is
|
|
18
|
-
* configured; otherwise the proxy still gates nothing and forwards).
|
|
19
|
-
*
|
|
20
|
-
* Supervision: the app child, portr child, and this process are tied together -
|
|
21
|
-
* if ANY exits, everything comes down (concurrently-style `killOthers`).
|
|
22
|
-
*
|
|
23
|
-
* Options come from flags OR env; see the option definitions below.
|
|
17
|
+
* Ships no bin. `@dbx-tools/cli` mounts `buildProgram()` as `dbx tunnel` lazily,
|
|
18
|
+
* so `dbx dev` pays for none of this, and `--insecure` / `status` / `install`
|
|
19
|
+
* never load AppKit or the SMTP stack either (the gate app is behind a dynamic
|
|
20
|
+
* import).
|
|
24
21
|
*
|
|
25
22
|
* @module
|
|
26
23
|
*/
|
|
27
24
|
import { spawn } from "node:child_process";
|
|
28
|
-
import {
|
|
25
|
+
import { createServer } from "node:net";
|
|
26
|
+
import { log } from "@dbx-tools/shared-core";
|
|
27
|
+
import { portr } from "@dbx-tools/tunnel";
|
|
29
28
|
import { Command, CommanderError } from "commander";
|
|
30
|
-
import {
|
|
31
|
-
import { FORWARD_HEADERS_ENV, INSECURE_ENV } from "./env.js";
|
|
32
|
-
import { installPortr, resolvePortrConfig, startPortr, writePortrConfig } from "./portr.js";
|
|
29
|
+
import { resolveTunnelOptions } from "./options.js";
|
|
33
30
|
import { startProxy } from "./proxy.js";
|
|
34
31
|
export { CommanderError };
|
|
35
32
|
const logger = log.logger("tunnel");
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
/** How long a child gets to exit on SIGTERM before the wrapper leaves anyway. */
|
|
34
|
+
const SHUTDOWN_GRACE_MS = 3_000;
|
|
35
|
+
/**
|
|
36
|
+
* A free loopback port, from the OS rather than a random guess: binding `0` and
|
|
37
|
+
* reading back what was assigned is the only way to know the port is actually
|
|
38
|
+
* available, so two tunnels can run side by side without colliding.
|
|
39
|
+
*/
|
|
40
|
+
function freePort() {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const probe = createServer();
|
|
43
|
+
probe.on("error", reject);
|
|
44
|
+
probe.listen(0, "127.0.0.1", () => {
|
|
45
|
+
const address = probe.address();
|
|
46
|
+
const port = typeof address === "object" && address ? address.port : 0;
|
|
47
|
+
probe.close(() => (port > 0 ? resolve(port) : reject(new Error("no free port"))));
|
|
48
|
+
});
|
|
49
|
+
});
|
|
39
50
|
}
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.option("--
|
|
48
|
-
.option("--
|
|
49
|
-
.option("--
|
|
50
|
-
.option("--
|
|
51
|
-
.option("--
|
|
52
|
-
.option("--
|
|
53
|
-
.option("--
|
|
54
|
-
.option("--
|
|
55
|
-
.option("--
|
|
56
|
-
.
|
|
57
|
-
.
|
|
51
|
+
/**
|
|
52
|
+
* Every gate/portr flag. Declared on the root command AND on `run`/`status` so
|
|
53
|
+
* `dbx tunnel --allow x -- cmd` and `dbx tunnel run --allow x -- cmd` behave
|
|
54
|
+
* identically - commander does not inherit options downward.
|
|
55
|
+
*/
|
|
56
|
+
function addOptions(command) {
|
|
57
|
+
return command
|
|
58
|
+
.option("--public-domain <host>", "portr public domain (<subdomain>.<server>)")
|
|
59
|
+
.option("--subdomain <name>", "portr subdomain (else derived from the public domain)")
|
|
60
|
+
.option("--port <port>", "public port the wrapper listens on")
|
|
61
|
+
.option("--app-port <port>", "private port the wrapped app is told to bind")
|
|
62
|
+
.option("--allow <patterns...>", "email allow-list (domain / glob / /regex/)")
|
|
63
|
+
.option("--subject <text>", "verification email subject")
|
|
64
|
+
.option("--brand-name <name>", "verification email brand name")
|
|
65
|
+
.option("--message <text>", "verification email message")
|
|
66
|
+
.option("--session-ttl <seconds>", "session lifetime")
|
|
67
|
+
.option("--code-ttl <seconds>", "one-time-code lifetime")
|
|
68
|
+
.option("--session-cutoff <when>", "invalidate every session issued before this")
|
|
69
|
+
.option("--forward-headers <patterns...>", "extra x- headers tunnel traffic may forward")
|
|
70
|
+
.option("--insecure", "run open, with no gate");
|
|
58
71
|
}
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Tie the wrapper's lifetime to its children's, in both directions: a child that
|
|
74
|
+
* exits takes the wrapper down with its code, and a signal to the wrapper is
|
|
75
|
+
* forwarded before it leaves. Without this a crashed app leaves a portr tunnel
|
|
76
|
+
* serving a dead port, which looks like a hang rather than a failure.
|
|
77
|
+
*/
|
|
78
|
+
function supervise(children) {
|
|
79
|
+
let stopping = false;
|
|
80
|
+
const stop = (code) => {
|
|
81
|
+
if (stopping)
|
|
64
82
|
return;
|
|
65
|
-
|
|
66
|
-
for (const child of children)
|
|
83
|
+
stopping = true;
|
|
84
|
+
for (const child of children)
|
|
67
85
|
if (!child.killed)
|
|
68
86
|
child.kill("SIGTERM");
|
|
69
|
-
|
|
70
|
-
// Give children a moment, then exit with the first non-zero code seen.
|
|
71
|
-
setTimeout(() => process.exit(code), 3000).unref();
|
|
87
|
+
setTimeout(() => process.exit(code), SHUTDOWN_GRACE_MS).unref();
|
|
72
88
|
};
|
|
73
|
-
for (const child of children)
|
|
74
|
-
child.on("exit", (code) =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
for (const sig of ["SIGTERM", "SIGINT", "SIGHUP"]) {
|
|
80
|
-
process.on(sig, () => shutdown(0));
|
|
89
|
+
for (const child of children)
|
|
90
|
+
child.on("exit", (code) => stop(code ?? 1));
|
|
91
|
+
for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"]) {
|
|
92
|
+
process.on(signal, () => stop(0));
|
|
81
93
|
}
|
|
82
94
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const flags = sep >= 0 ? argv.slice(0, sep) : argv;
|
|
88
|
-
const command = sep >= 0 ? argv.slice(sep + 1) : [];
|
|
89
|
-
const prog = program();
|
|
90
|
-
prog.parse(flags);
|
|
91
|
-
const opts = prog.opts();
|
|
92
|
-
if (command.length === 0) {
|
|
93
|
-
throw new CommanderError(1, "tunnel.no-command", "no start command given after `--`");
|
|
95
|
+
async function run(raw, command) {
|
|
96
|
+
const [executable, ...args] = command;
|
|
97
|
+
if (!executable) {
|
|
98
|
+
throw new CommanderError(1, "tunnel.no-command", "no command given - pass it after `--`");
|
|
94
99
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
logger.info(`spawning app on private port ${appPort}: ${command.join(" ")}`);
|
|
109
|
-
const [cmd, ...args] = command;
|
|
110
|
-
const app = spawn(cmd, args, {
|
|
111
|
-
env: { ...process.env, DATABRICKS_APP_PORT: String(appPort), HOST: "127.0.0.1" },
|
|
100
|
+
const resolved = resolveTunnelOptions(raw);
|
|
101
|
+
// The wrapped app must not be reachable from outside: it binds loopback on a
|
|
102
|
+
// private port, and the wrapper is the only thing that talks to it. An
|
|
103
|
+
// unresolved `--app-port` becomes a free ephemeral port rather than a fixed
|
|
104
|
+
// guess, so two tunnels can run side by side.
|
|
105
|
+
const appPort = resolved.appPort ?? (await freePort());
|
|
106
|
+
const app = spawn(executable, args, {
|
|
107
|
+
env: {
|
|
108
|
+
...process.env,
|
|
109
|
+
DATABRICKS_APP_PORT: String(appPort),
|
|
110
|
+
PORT: String(appPort),
|
|
111
|
+
HOST: "127.0.0.1",
|
|
112
|
+
},
|
|
112
113
|
stdio: "inherit",
|
|
113
114
|
});
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
else {
|
|
123
|
-
try {
|
|
124
|
-
gate = await startGateApp(gateConfig);
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
// Fail fast: don't silently expose an ungated tunnel. The operator must fix
|
|
128
|
-
// SMTP or explicitly opt into `--insecure`.
|
|
129
|
-
logger.error("cannot start the OTP gate", { error: error.message });
|
|
130
|
-
throw error;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// 3. Start the gate proxy on the public port (open when `gate` is undefined).
|
|
134
|
-
// `forwardHeaders` only ADDS to the built-in allow-list; see `./headers.ts`.
|
|
115
|
+
const children = [app];
|
|
116
|
+
// Dynamic import: the gate is the only thing here that needs AppKit + SMTP, so
|
|
117
|
+
// an `--insecure` run never loads either.
|
|
118
|
+
const gate = resolved.gate.insecure
|
|
119
|
+
? undefined
|
|
120
|
+
: await (await import("./app.js")).startGateApp(resolved.gateConfig);
|
|
121
|
+
if (!gate)
|
|
122
|
+
logger.warn("running OPEN - no gate is in front of this tunnel");
|
|
135
123
|
await startProxy({
|
|
136
|
-
publicPort,
|
|
124
|
+
publicPort: resolved.publicPort,
|
|
137
125
|
appPort,
|
|
138
126
|
gate,
|
|
139
|
-
forwardHeaders:
|
|
140
|
-
});
|
|
141
|
-
// 4. Install + run portr when a tunnel is configured.
|
|
142
|
-
const portrConfig = resolvePortrConfig({
|
|
143
|
-
publicDomain: opts.publicDomain,
|
|
144
|
-
subdomain: opts.subdomain,
|
|
145
|
-
port: publicPort,
|
|
127
|
+
forwardHeaders: resolved.gate.forwardHeaders,
|
|
146
128
|
});
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
children.push(startPortr(portrConfig, portrEnv));
|
|
129
|
+
if (resolved.portr) {
|
|
130
|
+
const portrEnv = await portr.installPortr();
|
|
131
|
+
await portr.writePortrConfig(resolved.portr, portrEnv);
|
|
132
|
+
children.push(await portr.startPortr(resolved.portr, portrEnv));
|
|
152
133
|
}
|
|
153
134
|
else {
|
|
154
|
-
logger.info("no PORTR_TOKEN/TUNNEL_PUBLIC_DOMAIN - serving
|
|
135
|
+
logger.info("no PORTR_TOKEN / TUNNEL_PUBLIC_DOMAIN - serving locally only", {
|
|
136
|
+
publicPort: resolved.publicPort,
|
|
137
|
+
});
|
|
155
138
|
}
|
|
156
|
-
|
|
157
|
-
|
|
139
|
+
supervise(children);
|
|
140
|
+
}
|
|
141
|
+
/** The `dbx tunnel` program. No side effects until parsed. */
|
|
142
|
+
export function buildProgram(name = "dbx tunnel") {
|
|
143
|
+
const program = addOptions(new Command()
|
|
144
|
+
.name(name)
|
|
145
|
+
.description("Front a command with a portr tunnel and an email-OTP gate"));
|
|
146
|
+
// `run` is the DEFAULT action as well as a named subcommand, preserving the old
|
|
147
|
+
// wrapper's ergonomics (`dbx tunnel --allow x -- bun src/server.ts`) while
|
|
148
|
+
// leaving somewhere for `status` and `install` to live.
|
|
149
|
+
program
|
|
150
|
+
.argument("[command...]", "the command to wrap, after `--`")
|
|
151
|
+
.action(async (command, _options, cmd) => {
|
|
152
|
+
await run(cmd.opts(), command);
|
|
153
|
+
});
|
|
154
|
+
addOptions(program.command("run").description("Wrap a command (the default action)"))
|
|
155
|
+
.argument("<command...>", "the command to wrap, after `--`")
|
|
156
|
+
.action(async (command, _options, cmd) => {
|
|
157
|
+
await run(cmd.opts(), command);
|
|
158
|
+
});
|
|
159
|
+
// Worth its own command: the most common failure is a tunnel that silently
|
|
160
|
+
// does nothing because no token or domain resolved, and this prints exactly
|
|
161
|
+
// what would happen without starting anything.
|
|
162
|
+
addOptions(program.command("status").description("Resolve the configuration and print it")).action((_options, cmd) => {
|
|
163
|
+
const resolved = resolveTunnelOptions(cmd.opts());
|
|
164
|
+
process.stdout.write(`${JSON.stringify(resolved, null, 2)}\n`);
|
|
165
|
+
});
|
|
166
|
+
program
|
|
167
|
+
.command("install")
|
|
168
|
+
.description("Install the portr binary and exit")
|
|
169
|
+
.action(async () => {
|
|
170
|
+
await portr.installPortr();
|
|
171
|
+
});
|
|
172
|
+
return program;
|
|
158
173
|
}
|
|
159
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlCRztBQUVILE9BQU8sRUFBcUIsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDOUQsT0FBTyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxZQUFZLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDNUYsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUV4QyxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUM7QUFFMUIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVwQyxxRkFBcUY7QUFDckYsU0FBUyxVQUFVO0lBQ2pCLE9BQU8sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDO0FBQ25ELENBQUM7QUFnQkQsb0ZBQW9GO0FBQ3BGLFNBQVMsT0FBTztJQUNkLE9BQU8sSUFBSSxPQUFPLEVBQUU7U0FDakIsSUFBSSxDQUFDLGtCQUFrQixDQUFDO1NBQ3hCLFdBQVcsQ0FBQywwREFBMEQsQ0FBQztTQUN2RSxNQUFNLENBQUMsa0JBQWtCLEVBQUUsMkRBQTJELENBQUM7U0FDdkYsTUFBTSxDQUNMLG9CQUFvQixFQUNwQixtRkFBbUYsQ0FDcEY7U0FDQSxNQUFN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Q0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDbkQsQ0FBQztTQUFNLENBQUM7UUFDTixNQUFNLENBQUMsSUFBSSxDQUNULHNGQUFzRixDQUN2RixDQUFDO0lBQ0osQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDMUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYGRieC10b29scy10dW5uZWxgIC8gYGRieHQtdHVubmVsYCBDTEkuXG4gKlxuICogV3JhcHMgYW4gYXBwJ3Mgc3RhcnQgY29tbWFuZCB3aXRoIGEgcHVibGljIHBvcnRyIHR1bm5lbCBhbmQgYW4gZW1haWwtT1RQXG4gKiBhY2Nlc3MgZ2F0ZS4gRXZlcnl0aGluZyBhZnRlciBgLS1gIGlzIHRoZSBSRUFMIGFwcCBzdGFydCBjb21tYW5kOlxuICpcbiAqICAgZGJ4dC10dW5uZWwgLS1zdWJqZWN0IFwiSGVyZSdzIHlvdXIgT1RQXCIgLS1hbGxvdyBleGFtcGxlLmNvbSAtLSBidW4gc3JjL3NlcnZlci50c1xuICpcbiAqIEJvb3Qgc2VxdWVuY2U6XG4gKiAgIDEuIFBpY2sgYSByYW5kb20gUFJJVkFURSBwb3J0IGFuZCBzcGF3biB0aGUgYXBwIGNvbW1hbmQgd2l0aFxuICogICAgICBgREFUQUJSSUNLU19BUFBfUE9SVGAgc2V0IHRvIGl0IChzbyB0aGUgYXBwIGJpbmRzIGxvb3BiYWNrLXByaXZhdGUpLiBUaGF0XG4gKiAgICAgIHZhcmlhYmxlIG5hbWUgaXMgdGhlIERhdGFicmlja3MgQXBwcyBydW50aW1lIGNvbnRyYWN0OyB0aGUgZ2F0ZSBpdHNlbGYgaXNcbiAqICAgICAgcGxhdGZvcm0tbmV1dHJhbCBhbmQgaG9ub3VycyB3aGF0ZXZlciBwb3J0IGl0IGZpbmRzIHRoZXJlLlxuICogICAyLiBCb290IHRoZSB0aW55IGdhdGUgQXBwS2l0IGFwcCAobm8gc2VydmVyKTogaW5pdHMgYENhY2hlTWFuYWdlcmAgKyB0aGVcbiAqICAgICAgZW1haWwgdHJhbnNwb3J0LCB5aWVsZHMgdGhlIGluLXByb2Nlc3MgZ2F0ZSBBUEkuXG4gKiAgIDMuIFN0YXJ0IHRoZSBnYXRlIFBST1hZIG9uIHRoZSBPUklHSU5BTCBwdWJsaWMgcG9ydCwgZm9yd2FyZGluZyB0byB0aGUgYXBwLlxuICogICA0LiBJbnN0YWxsICsgcnVuIHBvcnRyIHBvaW50ZWQgYXQgdGhlIHB1YmxpYyBwb3J0ICh3aGVuIGEgdHVubmVsIGlzXG4gKiAgICAgIGNvbmZpZ3VyZWQ7IG90aGVyd2lzZSB0aGUgcHJveHkgc3RpbGwgZ2F0ZXMgbm90aGluZyBhbmQgZm9yd2FyZHMpLlxuICpcbiAqIFN1cGVydmlzaW9uOiB0aGUgYXBwIGNoaWxkLCBwb3J0ciBjaGlsZCwgYW5kIHRoaXMgcHJvY2VzcyBhcmUgdGllZCB0b2dldGhlciAtXG4gKiBpZiBBTlkgZXhpdHMsIGV2ZXJ5dGhpbmcgY29tZXMgZG93biAoY29uY3VycmVudGx5LXN0eWxlIGBraWxsT3RoZXJzYCkuXG4gKlxuICogT3B0aW9ucyBjb21lIGZyb20gZmxhZ3MgT1IgZW52OyBzZWUgdGhlIG9wdGlvbiBkZWZpbml0aW9ucyBiZWxvdy5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgdHlwZSBDaGlsZFByb2Nlc3MsIHNwYXduIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgZW52LCBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgQ29tbWFuZCwgQ29tbWFuZGVyRXJyb3IgfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyBzdGFydEdhdGVBcHAgfSBmcm9tIFwiLi9hcHAudHNcIjtcbmltcG9ydCB7IEZPUldBUkRfSEVBREVSU19FTlYsIElOU0VDVVJFX0VOViB9IGZyb20gXCIuL2Vudi50c1wiO1xuaW1wb3J0IHR5cGUgeyBBdXRoR2F0ZUNvbmZpZyB9IGZyb20gXCIuL3BsdWdpbi50c1wiO1xuaW1wb3J0IHsgaW5zdGFsbFBvcnRyLCByZXNvbHZlUG9ydHJDb25maWcsIHN0YXJ0UG9ydHIsIHdyaXRlUG9ydHJDb25maWcgfSBmcm9tIFwiLi9wb3J0ci50c1wiO1xuaW1wb3J0IHsgc3RhcnRQcm94eSB9IGZyb20gXCIuL3Byb3h5LnRzXCI7XG5cbmV4cG9ydCB7IENvbW1hbmRlckVycm9yIH07XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0dW5uZWxcIik7XG5cbi8qKiBBIHJhbmRvbSBlcGhlbWVyYWwgcG9ydCBmb3IgdGhlIGFwcCB0byBiaW5kICh0aGUgcHJveHkgZnJvbnRzIHRoZSBwdWJsaWMgb25lKS4gKi9cbmZ1bmN0aW9uIHJhbmRvbVBvcnQoKTogbnVtYmVyIHtcbiAgcmV0dXJuIDIwMDAwICsgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjAwMDApO1xufVxuXG5pbnRlcmZhY2UgVHVubmVsT3B0cyB7XG4gIHN1YmplY3Q/OiBzdHJpbmc7XG4gIGFsbG93Pzogc3RyaW5nO1xuICBzdWJkb21haW4/OiBzdHJpbmc7XG4gIHB1YmxpY0RvbWFpbj86IHN0cmluZztcbiAgYnJhbmROYW1lPzogc3RyaW5nO1xuICBtZXNzYWdlPzogc3RyaW5nO1xuICBzZXNzaW9uVHRsPzogc3RyaW5nO1xuICBjb2RlVHRsPzogc3RyaW5nO1xuICBzZXNzaW9uQ3V0b2ZmPzogc3RyaW5nO1xuICBpbnNlY3VyZT86IGJvb2xlYW47XG4gIGZvcndhcmRIZWFkZXJzPzogc3RyaW5nO1xufVxuXG4vKiogQnVpbGQgdGhlIGNvbW1hbmRlciBwcm9ncmFtLiBgLS1gIHNlcGFyYXRlcyBmbGFncyBmcm9tIHRoZSBhcHAgc3RhcnQgY29tbWFuZC4gKi9cbmZ1bmN0aW9uIHByb2dyYW0oKTogQ29tbWFuZCB7XG4gIHJldHVybiBuZXcgQ29tbWFuZCgpXG4gICAgLm5hbWUoXCJkYngtdG9vbHMtdHVubmVsXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiRnJvbnQgYW4gYXBwIHdpdGggYSBwdWJsaWMgcG9ydHIgdHVubmVsICsgZW1haWwtT1RQIGdhdGVcIilcbiAgICAub3B0aW9uKFwiLS1zdWJqZWN0IDx0ZXh0PlwiLCBcIlN1YmplY3QgbGluZSBmb3IgdGhlIGNvZGUgZW1haWwgKGVudiBUVU5ORUxfQVVUSF9TVUJKRUNUKVwiKVxuICAgIC5vcHRpb24oXG4gICAgICBcIi0tYWxsb3cgPHBhdHRlcm5zPlwiLFxuICAgICAgXCJDb21tYS9zcGFjZS1zZXBhcmF0ZWQgYWxsb3ctbGlzdDogZG9tYWluIC8gZ2xvYiAvIC9yZWdleC8gKGVudiBUVU5ORUxfQVVUSF9BTExPVylcIixcbiAgICApXG4gICAgLm9wdGlvbihcIi0tc3ViZG9tYWluIDxuYW1lPlwiLCBcInBvcnRyIHN1YmRvbWFpbiAoZWxzZSBkZXJpdmVkIGZyb20gVFVOTkVMX1BVQkxJQ19ET01BSU4pXCIpXG4gICAgLm9wdGlvbihcIi0tcHVibGljLWRvbWFpbiA8aG9zdD5cIiwgXCJwb3J0ciA8c3ViZG9tYWluPi48c2VydmVyPiAoZW52IFRVTk5FTF9QVUJMSUNfRE9NQUlOKVwiKVxuICAgIC5vcHRpb24oXG4gICAgICBcIi0tYnJhbmQtbmFtZSA8bmFtZT5cIixcbiAgICAgIFwiRGlzcGxheSBuYW1lIGluIHRoZSBjb2RlIGVtYWlsIGNvcHkgKGVudiBUVU5ORUxfQVVUSF9CUkFORF9OQU1FOyBkZWZhdWx0cyB0byB0aGUgYnJhbmQgY29udGV4dCBuYW1lKVwiLFxuICAgIClcbiAgICAub3B0aW9uKFwiLS1tZXNzYWdlIDx0ZXh0PlwiLCBcIkxpbmUgc2hvd24gYWJvdmUgdGhlIGNvZGUgaW4gdGhlIGVtYWlsIChlbnYgVFVOTkVMX0FVVEhfTUVTU0FHRSlcIilcbiAgICAub3B0aW9uKFwiLS1zZXNzaW9uLXR0bCA8c2Vjb25kcz5cIiwgXCJTZXNzaW9uIGxpZmV0aW1lIChlbnYgVFVOTkVMX0FVVEhfU0VTU0lPTl9UVEwpXCIpXG4gICAgLm9wdGlvbihcIi0tY29kZS10dGwgPHNlY29uZHM+XCIsIFwiT25lLXRpbWUtY29kZSBsaWZldGltZSAoZW52IFRVTk5FTF9BVVRIX0NPREVfVFRMKVwiKVxuICAgIC5vcHRpb24oXG4gICAgICBcIi0tc2Vzc2lvbi1jdXRvZmYgPHdoZW4+XCIsXG4gICAgICBcIkludmFsaWRhdGUgc2Vzc2lvbnMgaXNzdWVkIGJlZm9yZSB0aGlzIHBvaW50LCBzaWduaW5nIGV2ZXJ5b25lIG91dDogYSBkYXRlLCBJU08gaW5zdGFudCwgZXBvY2ggc2Vjb25kcywgb3IgcmVsYXRpdmUgZHVyYXRpb24gbGlrZSAtMzBkIChlbnYgVFVOTkVMX0FVVEhfU0VTU0lPTl9DVVRPRkYpXCIsXG4gICAgKVxuICAgIC5vcHRpb24oXG4gICAgICBcIi0tZm9yd2FyZC1oZWFkZXJzIDxwYXR0ZXJucz5cIixcbiAgICAgIFwiRXh0cmEgeC0gcmVxdWVzdCBoZWFkZXJzIHR1bm5lbCB0cmFmZmljIG1heSBmb3J3YXJkOiBsaXRlcmFsIC8gZ2xvYiAvIC9yZWdleC8gKGVudiBUVU5ORUxfRk9SV0FSRF9IRUFERVJTKVwiLFxuICAgIClcbiAgICAub3B0aW9uKFxuICAgICAgXCItLWluc2VjdXJlXCIsXG4gICAgICBcIlJ1biB0aGUgdHVubmVsIE9QRU4gd2l0aCBubyBnYXRlIChlbnYgVFVOTkVMX0lOU0VDVVJFPXRydWUpLiBPdGhlcndpc2UgdGhlIENMSSBmYWlscyBmYXN0IHdoZW4gZW1haWwgU01UUCBpcyBub3QgY29uZmlndXJlZC5cIixcbiAgICApXG4gICAgLmFsbG93RXhjZXNzQXJndW1lbnRzKHRydWUpXG4gICAgLmhlbHBPcHRpb24oXCItaCwgLS1oZWxwXCIsIFwiU2hvdyBoZWxwXCIpO1xufVxuXG4vKiogVGllIGEgY2hpbGQncyBleGl0IHRvIGZ1bGwgdGVhcmRvd246IGFueSBleGl0IGJyaW5ncyB0aGUgd2hvbGUgdHVubmVsIGRvd24uICovXG5mdW5jdGlvbiBzdXBlcnZpc2VFeGl0KGNoaWxkcmVuOiBDaGlsZFByb2Nlc3NbXSk6IHZvaWQge1xuICBsZXQgc2h1dHRpbmdEb3duID0gZmFsc2U7XG4gIGNvbnN0IHNodXRkb3duID0gKGNvZGU6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgIGlmIChzaHV0dGluZ0Rvd24pIHJldHVybjtcbiAgICBzaHV0dGluZ0Rvd24gPSB0cnVlO1xuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRyZW4pIHtcbiAgICAgIGlmICghY2hpbGQua2lsbGVkKSBjaGlsZC5raWxsKFwiU0lHVEVSTVwiKTtcbiAgICB9XG4gICAgLy8gR2l2ZSBjaGlsZHJlbiBhIG1vbWVudCwgdGhlbiBleGl0IHdpdGggdGhlIGZpcnN0IG5vbi16ZXJvIGNvZGUgc2Vlbi5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHByb2Nlc3MuZXhpdChjb2RlKSwgMzAwMCkudW5yZWYoKTtcbiAgfTtcbiAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikge1xuICAgIGNoaWxkLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgICAgbG9nZ2VyLndhcm4oYGNoaWxkIGV4aXRlZCAoJHtjb2RlID8/IFwic2lnbmFsXCJ9KTsgYnJpbmdpbmcgdHVubmVsIGRvd25gKTtcbiAgICAgIHNodXRkb3duKGNvZGUgPz8gMSk7XG4gICAgfSk7XG4gIH1cbiAgZm9yIChjb25zdCBzaWcgb2YgW1wiU0lHVEVSTVwiLCBcIlNJR0lOVFwiLCBcIlNJR0hVUFwiXSBhcyBjb25zdCkge1xuICAgIHByb2Nlc3Mub24oc2lnLCAoKSA9PiBzaHV0ZG93bigwKSk7XG4gIH1cbn1cblxuLyoqIFBhcnNlIGFyZ3YgYW5kIHJ1biB0aGUgdHVubmVsLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkNsaShhcmd2OiBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAvLyBTcGxpdCBmbGFncyBmcm9tIHRoZSB3cmFwcGVkIGNvbW1hbmQgYXQgdGhlIGZpcnN0IGAtLWAuXG4gIGNvbnN0IHNlcCA9IGFyZ3YuaW5kZXhPZihcIi0tXCIpO1xuICBjb25zdCBmbGFncyA9IHNlcCA+PSAwID8gYXJndi5zbGljZSgwLCBzZXApIDogYXJndjtcbiAgY29uc3QgY29tbWFuZCA9IHNlcCA+PSAwID8gYXJndi5zbGljZShzZXAgKyAxKSA6IFtdO1xuXG4gIGNvbnN0IHByb2cgPSBwcm9ncmFtKCk7XG4gIHByb2cucGFyc2UoZmxhZ3MpO1xuICBjb25zdCBvcHRzID0gcHJvZy5vcHRzPFR1bm5lbE9wdHM+KCk7XG5cbiAgaWYgKGNvbW1hbmQubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IENvbW1hbmRlckVycm9yKDEsIFwidHVubmVsLm5vLWNvbW1hbmRcIiwgXCJubyBzdGFydCBjb21tYW5kIGdpdmVuIGFmdGVyIGAtLWBcIik7XG4gIH1cblxuICBjb25zdCBwdWJsaWNQb3J0ID0gTnVtYmVyKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQVBQX1BPUlQgPz8gODAwMCk7XG4gIGNvbnN0IGFwcFBvcnQgPSByYW5kb21Qb3J0KCk7XG5cbiAgY29uc3QgZ2F0ZUNvbmZpZzogQXV0aEdhdGVDb25maWcgPSB7XG4gICAgYWxsb3c6IG9wdHMuYWxsb3csXG4gICAgc3ViamVjdDogb3B0cy5zdWJqZWN0LFxuICAgIGJyYW5kTmFtZTogb3B0cy5icmFuZE5hbWUsXG4gICAgbWVzc2FnZTogb3B0cy5tZXNzYWdlLFxuICAgIHNlc3Npb25UdGxTZWNvbmRzOiBvcHRzLnNlc3Npb25UdGwgPyBOdW1iZXIob3B0cy5zZXNzaW9uVHRsKSA6IHVuZGVmaW5lZCxcbiAgICBjb2RlVHRsU2Vjb25kczogb3B0cy5jb2RlVHRsID8gTnVtYmVyKG9wdHMuY29kZVR0bCkgOiB1bmRlZmluZWQsXG4gICAgc2Vzc2lvbkN1dG9mZjogb3B0cy5zZXNzaW9uQ3V0b2ZmLFxuICB9O1xuXG4gIC8vIDEuIFNwYXduIHRoZSB3cmFwcGVkIGFwcCB3aXRoIHRoZSBQUklWQVRFIHBvcnQuIEl0IGJpbmRzIGxvb3BiYWNrOyBvbmx5IHRoZVxuICAvLyAgICBwcm94eSByZWFjaGVzIGl0LlxuICBsb2dnZXIuaW5mbyhgc3Bhd25pbmcgYXBwIG9uIHByaXZhdGUgcG9ydCAke2FwcFBvcnR9OiAke2NvbW1hbmQuam9pbihcIiBcIil9YCk7XG4gIGNvbnN0IFtjbWQsIC4uLmFyZ3NdID0gY29tbWFuZDtcbiAgY29uc3QgYXBwID0gc3Bhd24oY21kISwgYXJncywge1xuICAgIGVudjogeyAuLi5wcm9jZXNzLmVudiwgREFUQUJSSUNLU19BUFBfUE9SVDogU3RyaW5nKGFwcFBvcnQpLCBIT1NUOiBcIjEyNy4wLjAuMVwiIH0sXG4gICAgc3RkaW86IFwiaW5oZXJpdFwiLFxuICB9KTtcblxuICAvLyAyLiBCb290IHRoZSBnYXRlIGFwcCAoY2FjaGUgKyBlbWFpbCB0cmFuc3BvcnQgKyBnYXRlIEFQSSkuIGBzdGFydEdhdGVBcHBgXG4gIC8vICAgIEZBSUxTIEZBU1Qgd2hlbiBlbWFpbCBjYW4ndCBzZW5kIGNvZGVzIChubyBTTVRQKS4gSW5zZWN1cmUgbW9kZVxuICAvLyAgICAoYC0taW5zZWN1cmVgIC8gVFVOTkVMX0lOU0VDVVJFKSBza2lwcyB0aGUgZ2F0ZSBhbmQgcnVucyB0aGUgdHVubmVsIG9wZW4uXG4gIGNvbnN0IGluc2VjdXJlID0gZW52LmJvb2xlYW4ob3B0cy5pbnNlY3VyZSwgSU5TRUNVUkVfRU5WKSA/PyBmYWxzZTtcbiAgbGV0IGdhdGU6IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2Ygc3RhcnRHYXRlQXBwPj4gfCB1bmRlZmluZWQ7XG4gIGlmIChpbnNlY3VyZSkge1xuICAgIGxvZ2dlci53YXJuKFwiaW5zZWN1cmUgbW9kZSAtIHR1bm5lbCBydW5zIE9QRU4gd2l0aCBubyBlbWFpbC1PVFAgZ2F0ZVwiKTtcbiAgfSBlbHNlIHtcbiAgICB0cnkge1xuICAgICAgZ2F0ZSA9IGF3YWl0IHN0YXJ0R2F0ZUFwcChnYXRlQ29uZmlnKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gRmFpbCBmYXN0OiBkb24ndCBzaWxlbnRseSBleHBvc2UgYW4gdW5nYXRlZCB0dW5uZWwuIFRoZSBvcGVyYXRvciBtdXN0IGZpeFxuICAgICAgLy8gU01UUCBvciBleHBsaWNpdGx5IG9wdCBpbnRvIGAtLWluc2VjdXJlYC5cbiAgICAgIGxvZ2dlci5lcnJvcihcImNhbm5vdCBzdGFydCB0aGUgT1RQIGdhdGVcIiwgeyBlcnJvcjogKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlIH0pO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLy8gMy4gU3RhcnQgdGhlIGdhdGUgcHJveHkgb24gdGhlIHB1YmxpYyBwb3J0IChvcGVuIHdoZW4gYGdhdGVgIGlzIHVuZGVmaW5lZCkuXG4gIC8vICAgIGBmb3J3YXJkSGVhZGVyc2Agb25seSBBRERTIHRvIHRoZSBidWlsdC1pbiBhbGxvdy1saXN0OyBzZWUgYC4vaGVhZGVycy50c2AuXG4gIGF3YWl0IHN0YXJ0UHJveHkoe1xuICAgIHB1YmxpY1BvcnQsXG4gICAgYXBwUG9ydCxcbiAgICBnYXRlLFxuICAgIGZvcndhcmRIZWFkZXJzOiBlbnYubGlzdChvcHRzLmZvcndhcmRIZWFkZXJzLCBGT1JXQVJEX0hFQURFUlNfRU5WKSxcbiAgfSk7XG5cbiAgLy8gNC4gSW5zdGFsbCArIHJ1biBwb3J0ciB3aGVuIGEgdHVubmVsIGlzIGNvbmZpZ3VyZWQuXG4gIGNvbnN0IHBvcnRyQ29uZmlnID0gcmVzb2x2ZVBvcnRyQ29uZmlnKHtcbiAgICBwdWJsaWNEb21haW46IG9wdHMucHVibGljRG9tYWluLFxuICAgIHN1YmRvbWFpbjogb3B0cy5zdWJkb21haW4sXG4gICAgcG9ydDogcHVibGljUG9ydCxcbiAgfSk7XG4gIGNvbnN0IGNoaWxkcmVuOiBDaGlsZFByb2Nlc3NbXSA9IFthcHBdO1xuICBpZiAocG9ydHJDb25maWcpIHtcbiAgICBjb25zdCBwb3J0ckVudiA9IGluc3RhbGxQb3J0cigpO1xuICAgIHdyaXRlUG9ydHJDb25maWcocG9ydHJDb25maWcsIHBvcnRyRW52KTtcbiAgICBjaGlsZHJlbi5wdXNoKHN0YXJ0UG9ydHIocG9ydHJDb25maWcsIHBvcnRyRW52KSk7XG4gIH0gZWxzZSB7XG4gICAgbG9nZ2VyLmluZm8oXG4gICAgICBcIm5vIFBPUlRSX1RPS0VOL1RVTk5FTF9QVUJMSUNfRE9NQUlOIC0gc2VydmluZyB0aGUgZ2F0ZSBwcm94eSB3aXRob3V0IGEgcHVibGljIHR1bm5lbFwiLFxuICAgICk7XG4gIH1cblxuICAvLyBBbnkgY2hpbGQgZXhpdCAob3IgYSBzaWduYWwpIHRlYXJzIHRoZSB3aG9sZSB0aGluZyBkb3duLlxuICBzdXBlcnZpc2VFeGl0KGNoaWxkcmVuKTtcbn1cbiJdfQ==
|
|
174
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFBcUIsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3BELE9BQU8sRUFBRSxvQkFBb0IsRUFBc0IsTUFBTSxjQUFjLENBQUM7QUFDeEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUV4QyxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUM7QUFFMUIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVwQyxpRkFBaUY7QUFDakYsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUM7QUFFaEM7Ozs7R0FJRztBQUNILFNBQVMsUUFBUTtJQUNmLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDckMsTUFBTSxLQUFLLEdBQUcsWUFBWSxFQUFFLENBQUM7UUFDN0IsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDMUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLEdBQUcsRUFBRTtZQUNoQyxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxD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Q0FBQyxDQUFDLENBQUM7SUFFTCwyRUFBMkU7SUFDM0UsNEVBQTRFO0lBQzVFLCtDQUErQztJQUMvQyxVQUFVLENBQ1IsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxXQUFXLENBQUMsd0NBQXdDLENBQUMsQ0FDaEYsQ0FBQyxNQUFNLENBQUMsQ0FBQyxRQUF1QixFQUFFLEdBQVksRUFBRSxFQUFFO1FBQ2pELE1BQU0sUUFBUSxHQUFHLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQWlCLENBQUMsQ0FBQztRQUNqRSxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakUsQ0FBQyxDQUFDLENBQUM7SUFFSCxPQUFPO1NBQ0osT0FBTyxDQUFDLFNBQVMsQ0FBQztTQUNsQixXQUFXLENBQUMsbUNBQW1DLENBQUM7U0FDaEQsTUFBTSxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2pCLE1BQU0sS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzdCLENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYGRieCB0dW5uZWxgIC0gZnJvbnQgYSBjb21tYW5kIHdpdGggYSBwdWJsaWMgcG9ydHIgdHVubmVsIGFuZCBhbiBlbWFpbC1PVFAgZ2F0ZS5cbiAqXG4gKiBUaGlzIGlzIHRoZSBXUkFQUEVSIHBhdGgsIGFuZCBpdCBleGlzdHMgZm9yIG9uZSBjYXNlOiBhIHByb2plY3QgdGhhdCBkb2VzIG5vdFxuICogdXNlIGBAZGJ4LXRvb2xzL2FwcGtpdGAncyBgY3JlYXRlQXBwYCwgYW5kIHRoZXJlZm9yZSBjYW5ub3QgcmVnaXN0ZXJcbiAqIGB0dW5uZWxJbnRlcmNlcHRvcigpYCArIHRoZSBgYXV0aEdhdGVgIHBsdWdpbiBpbi1wcm9jZXNzLiBBbiBBcHBLaXQgYXBwIHNob3VsZFxuICogc3RpbGwgdGFrZSB0aGUgcGx1Z2luIHBhdGggLSBvbmUgcHJvY2Vzcywgbm8gcHJveHkgaG9wLCBubyBkdXBsaWNhdGVkIGhlYWRlclxuICogaGFuZGxpbmcuXG4gKlxuICogVGhlIHdyYXBwZXIgY2xhaW1zIHRoZSBQVUJMSUMgcG9ydCAoYERBVEFCUklDS1NfQVBQX1BPUlRgLCB0aGUgcG9ydCB0aGVcbiAqIHBsYXRmb3JtIGFuZCBwb3J0ciByb3V0ZSB0byksIG1vdmVzIHRoZSB3cmFwcGVkIGFwcCB0byBhIHByaXZhdGUgb25lLCBhbmRcbiAqIHJldmVyc2UtcHJveGllcyBiZXR3ZWVuIHRoZW0gc28gdGhlIGdhdGUgc2l0cyBpbiBmcm9udCBvZiB0cmFmZmljIGl0IHdvdWxkXG4gKiBvdGhlcndpc2UgaGF2ZSBubyB3YXkgdG8gaW50ZXJjZXB0LiBFdmVyeXRoaW5nIGVsc2UgaXMgZGVsZWdhdGVkOiB0aGUgZ2F0ZVxuICogY29uZmlnIGNvbWVzIGZyb20gYHBsdWdpbi5yZXNvbHZlQXV0aEdhdGVDb25maWdgLCB0aGUgcG9ydHIgbGlmZWN5Y2xlIGZyb21cbiAqIGBwb3J0ci4qYCAtIGJvdGggdGhlIHNhbWUgZnVuY3Rpb25zIHRoZSBpbi1wcm9jZXNzIHBhdGggdXNlcy5cbiAqXG4gKiBTaGlwcyBubyBiaW4uIGBAZGJ4LXRvb2xzL2NsaWAgbW91bnRzIGBidWlsZFByb2dyYW0oKWAgYXMgYGRieCB0dW5uZWxgIGxhemlseSxcbiAqIHNvIGBkYnggZGV2YCBwYXlzIGZvciBub25lIG9mIHRoaXMsIGFuZCBgLS1pbnNlY3VyZWAgLyBgc3RhdHVzYCAvIGBpbnN0YWxsYFxuICogbmV2ZXIgbG9hZCBBcHBLaXQgb3IgdGhlIFNNVFAgc3RhY2sgZWl0aGVyICh0aGUgZ2F0ZSBhcHAgaXMgYmVoaW5kIGEgZHluYW1pY1xuICogaW1wb3J0KS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgdHlwZSBDaGlsZFByb2Nlc3MsIHNwYXduIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSBcIm5vZGU6bmV0XCI7XG5pbXBvcnQgeyBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgcG9ydHIgfSBmcm9tIFwiQGRieC10b29scy90dW5uZWxcIjtcbmltcG9ydCB7IENvbW1hbmQsIENvbW1hbmRlckVycm9yIH0gZnJvbSBcImNvbW1hbmRlclwiO1xuaW1wb3J0IHsgcmVzb2x2ZVR1bm5lbE9wdGlvbnMsIHR5cGUgVHVubmVsT3B0aW9ucyB9IGZyb20gXCIuL29wdGlvbnMudHNcIjtcbmltcG9ydCB7IHN0YXJ0UHJveHkgfSBmcm9tIFwiLi9wcm94eS50c1wiO1xuXG5leHBvcnQgeyBDb21tYW5kZXJFcnJvciB9O1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwidHVubmVsXCIpO1xuXG4vKiogSG93IGxvbmcgYSBjaGlsZCBnZXRzIHRvIGV4aXQgb24gU0lHVEVSTSBiZWZvcmUgdGhlIHdyYXBwZXIgbGVhdmVzIGFueXdheS4gKi9cbmNvbnN0IFNIVVRET1dOX0dSQUNFX01TID0gM18wMDA7XG5cbi8qKlxuICogQSBmcmVlIGxvb3BiYWNrIHBvcnQsIGZyb20gdGhlIE9TIHJhdGhlciB0aGFuIGEgcmFuZG9tIGd1ZXNzOiBiaW5kaW5nIGAwYCBhbmRcbiAqIHJlYWRpbmcgYmFjayB3aGF0IHdhcyBhc3NpZ25lZCBpcyB0aGUgb25seSB3YXkgdG8ga25vdyB0aGUgcG9ydCBpcyBhY3R1YWxseVxuICogYXZhaWxhYmxlLCBzbyB0d28gdHVubmVscyBjYW4gcnVuIHNpZGUgYnkgc2lkZSB3aXRob3V0IGNvbGxpZGluZy5cbiAqL1xuZnVuY3Rpb24gZnJlZVBvcnQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm9iZSA9IGNyZWF0ZVNlcnZlcigpO1xuICAgIHByb2JlLm9uKFwiZXJyb3JcIiwgcmVqZWN0KTtcbiAgICBwcm9iZS5saXN0ZW4oMCwgXCIxMjcuMC4wLjFcIiwgKCkgPT4ge1xuICAgICAgY29uc3QgYWRkcmVzcyA9IHByb2JlLmFkZHJlc3MoKTtcbiAgICAgIGNvbnN0IHBvcnQgPSB0eXBlb2YgYWRkcmVzcyA9PT0gXCJvYmplY3RcIiAmJiBhZGRyZXNzID8gYWRkcmVzcy5wb3J0IDogMDtcbiAgICAgIHByb2JlLmNsb3NlKCgpID0+IChwb3J0ID4gMCA/IHJlc29sdmUocG9ydCkgOiByZWplY3QobmV3IEVycm9yKFwibm8gZnJlZSBwb3J0XCIpKSkpO1xuICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBFdmVyeSBnYXRlL3BvcnRyIGZsYWcuIERlY2xhcmVkIG9uIHRoZSByb290IGNvbW1hbmQgQU5EIG9uIGBydW5gL2BzdGF0dXNgIHNvXG4gKiBgZGJ4IHR1bm5lbCAtLWFsbG93IHggLS0gY21kYCBhbmQgYGRieCB0dW5uZWwgcnVuIC0tYWxsb3cgeCAtLSBjbWRgIGJlaGF2ZVxuICogaWRlbnRpY2FsbHkgLSBjb21tYW5kZXIgZG9lcyBub3QgaW5oZXJpdCBvcHRpb25zIGRvd253YXJkLlxuICovXG5mdW5jdGlvbiBhZGRPcHRpb25zKGNvbW1hbmQ6IENvbW1hbmQpOiBDb21tYW5kIHtcbiAgcmV0dXJuIGNvbW1hbmRcbiAgICAub3B0aW9uKFwiLS1wdWJsaWMtZG9tYWluIDxob3N0PlwiLCBcInBvcnRyIHB1YmxpYyBkb21haW4gKDxzdWJkb21haW4+LjxzZXJ2ZXI+KVwiKVxuICAgIC5vcHRpb24oXCItLXN1YmRvbWFpbiA8bmFtZT5cIiwgXCJwb3J0ciBzdWJkb21haW4gKGVsc2UgZGVyaXZlZCBmcm9tIHRoZSBwdWJsaWMgZG9tYWluKVwiKVxuICAgIC5vcHRpb24oXCItLXBvcnQgPHBvcnQ+XCIsIFwicHVibGljIHBvcnQgdGhlIHdyYXBwZXIgbGlzdGVucyBvblwiKVxuICAgIC5vcHRpb24oXCItLWFwcC1wb3J0IDxwb3J0PlwiLCBcInByaXZhdGUgcG9ydCB0aGUgd3JhcHBlZCBhcHAgaXMgdG9sZCB0byBiaW5kXCIpXG4gICAgLm9wdGlvbihcIi0tYWxsb3cgPHBhdHRlcm5zLi4uPlwiLCBcImVtYWlsIGFsbG93LWxpc3QgKGRvbWFpbiAvIGdsb2IgLyAvcmVnZXgvKVwiKVxuICAgIC5vcHRpb24oXCItLXN1YmplY3QgPHRleHQ+XCIsIFwidmVyaWZpY2F0aW9uIGVtYWlsIHN1YmplY3RcIilcbiAgICAub3B0aW9uKFwiLS1icmFuZC1uYW1lIDxuYW1lPlwiLCBcInZlcmlmaWNhdGlvbiBlbWFpbCBicmFuZCBuYW1lXCIpXG4gICAgLm9wdGlvbihcIi0tbWVzc2FnZSA8dGV4dD5cIiwgXCJ2ZXJpZmljYXRpb24gZW1haWwgbWVzc2FnZVwiKVxuICAgIC5vcHRpb24oXCItLXNlc3Npb24tdHRsIDxzZWNvbmRzPlwiLCBcInNlc3Npb24gbGlmZXRpbWVcIilcbiAgICAub3B0aW9uKFwiLS1jb2RlLXR0bCA8c2Vjb25kcz5cIiwgXCJvbmUtdGltZS1jb2RlIGxpZmV0aW1lXCIpXG4gICAgLm9wdGlvbihcIi0tc2Vzc2lvbi1jdXRvZmYgPHdoZW4+XCIsIFwiaW52YWxpZGF0ZSBldmVyeSBzZXNzaW9uIGlzc3VlZCBiZWZvcmUgdGhpc1wiKVxuICAgIC5vcHRpb24oXCItLWZvcndhcmQtaGVhZGVycyA8cGF0dGVybnMuLi4+XCIsIFwiZXh0cmEgeC0gaGVhZGVycyB0dW5uZWwgdHJhZmZpYyBtYXkgZm9yd2FyZFwiKVxuICAgIC5vcHRpb24oXCItLWluc2VjdXJlXCIsIFwicnVuIG9wZW4sIHdpdGggbm8gZ2F0ZVwiKTtcbn1cblxuLyoqXG4gKiBUaWUgdGhlIHdyYXBwZXIncyBsaWZldGltZSB0byBpdHMgY2hpbGRyZW4ncywgaW4gYm90aCBkaXJlY3Rpb25zOiBhIGNoaWxkIHRoYXRcbiAqIGV4aXRzIHRha2VzIHRoZSB3cmFwcGVyIGRvd24gd2l0aCBpdHMgY29kZSwgYW5kIGEgc2lnbmFsIHRvIHRoZSB3cmFwcGVyIGlzXG4gKiBmb3J3YXJkZWQgYmVmb3JlIGl0IGxlYXZlcy4gV2l0aG91dCB0aGlzIGEgY3Jhc2hlZCBhcHAgbGVhdmVzIGEgcG9ydHIgdHVubmVsXG4gKiBzZXJ2aW5nIGEgZGVhZCBwb3J0LCB3aGljaCBsb29rcyBsaWtlIGEgaGFuZyByYXRoZXIgdGhhbiBhIGZhaWx1cmUuXG4gKi9cbmZ1bmN0aW9uIHN1cGVydmlzZShjaGlsZHJlbjogcmVhZG9ubHkgQ2hpbGRQcm9jZXNzW10pOiB2b2lkIHtcbiAgbGV0IHN0b3BwaW5nID0gZmFsc2U7XG4gIGNvbnN0IHN0b3AgPSAoY29kZTogbnVtYmVyKTogdm9pZCA9PiB7XG4gICAgaWYgKHN0b3BwaW5nKSByZXR1cm47XG4gICAgc3RvcHBpbmcgPSB0cnVlO1xuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRyZW4pIGlmICghY2hpbGQua2lsbGVkKSBjaGlsZC5raWxsKFwiU0lHVEVSTVwiKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHByb2Nlc3MuZXhpdChjb2RlKSwgU0hVVERPV05fR1JBQ0VfTVMpLnVucmVmKCk7XG4gIH07XG4gIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRyZW4pIGNoaWxkLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4gc3RvcChjb2RlID8/IDEpKTtcbiAgZm9yIChjb25zdCBzaWduYWwgb2YgW1wiU0lHVEVSTVwiLCBcIlNJR0lOVFwiLCBcIlNJR0hVUFwiXSBhcyBjb25zdCkge1xuICAgIHByb2Nlc3Mub24oc2lnbmFsLCAoKSA9PiBzdG9wKDApKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBydW4ocmF3OiBUdW5uZWxPcHRpb25zLCBjb21tYW5kOiByZWFkb25seSBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBbZXhlY3V0YWJsZSwgLi4uYXJnc10gPSBjb21tYW5kO1xuICBpZiAoIWV4ZWN1dGFibGUpIHtcbiAgICB0aHJvdyBuZXcgQ29tbWFuZGVyRXJyb3IoMSwgXCJ0dW5uZWwubm8tY29tbWFuZFwiLCBcIm5vIGNvbW1hbmQgZ2l2ZW4gLSBwYXNzIGl0IGFmdGVyIGAtLWBcIik7XG4gIH1cbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlVHVubmVsT3B0aW9ucyhyYXcpO1xuXG4gIC8vIFRoZSB3cmFwcGVkIGFwcCBtdXN0IG5vdCBiZSByZWFjaGFibGUgZnJvbSBvdXRzaWRlOiBpdCBiaW5kcyBsb29wYmFjayBvbiBhXG4gIC8vIHByaXZhdGUgcG9ydCwgYW5kIHRoZSB3cmFwcGVyIGlzIHRoZSBvbmx5IHRoaW5nIHRoYXQgdGFsa3MgdG8gaXQuIEFuXG4gIC8vIHVucmVzb2x2ZWQgYC0tYXBwLXBvcnRgIGJlY29tZXMgYSBmcmVlIGVwaGVtZXJhbCBwb3J0IHJhdGhlciB0aGFuIGEgZml4ZWRcbiAgLy8gZ3Vlc3MsIHNvIHR3byB0dW5uZWxzIGNhbiBydW4gc2lkZSBieSBzaWRlLlxuICBjb25zdCBhcHBQb3J0ID0gcmVzb2x2ZWQuYXBwUG9ydCA/PyAoYXdhaXQgZnJlZVBvcnQoKSk7XG4gIGNvbnN0IGFwcCA9IHNwYXduKGV4ZWN1dGFibGUsIGFyZ3MsIHtcbiAgICBlbnY6IHtcbiAgICAgIC4uLnByb2Nlc3MuZW52LFxuICAgICAgREFUQUJSSUNLU19BUFBfUE9SVDogU3RyaW5nKGFwcFBvcnQpLFxuICAgICAgUE9SVDogU3RyaW5nKGFwcFBvcnQpLFxuICAgICAgSE9TVDogXCIxMjcuMC4wLjFcIixcbiAgICB9LFxuICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgfSk7XG4gIGNvbnN0IGNoaWxkcmVuOiBDaGlsZFByb2Nlc3NbXSA9IFthcHBdO1xuXG4gIC8vIER5bmFtaWMgaW1wb3J0OiB0aGUgZ2F0ZSBpcyB0aGUgb25seSB0aGluZyBoZXJlIHRoYXQgbmVlZHMgQXBwS2l0ICsgU01UUCwgc29cbiAgLy8gYW4gYC0taW5zZWN1cmVgIHJ1biBuZXZlciBsb2FkcyBlaXRoZXIuXG4gIGNvbnN0IGdhdGUgPSByZXNvbHZlZC5nYXRlLmluc2VjdXJlXG4gICAgPyB1bmRlZmluZWRcbiAgICA6IGF3YWl0IChhd2FpdCBpbXBvcnQoXCIuL2FwcC50c1wiKSkuc3RhcnRHYXRlQXBwKHJlc29sdmVkLmdhdGVDb25maWcpO1xuICBpZiAoIWdhdGUpIGxvZ2dlci53YXJuKFwicnVubmluZyBPUEVOIC0gbm8gZ2F0ZSBpcyBpbiBmcm9udCBvZiB0aGlzIHR1bm5lbFwiKTtcblxuICBhd2FpdCBzdGFydFByb3h5KHtcbiAgICBwdWJsaWNQb3J0OiByZXNvbHZlZC5wdWJsaWNQb3J0LFxuICAgIGFwcFBvcnQsXG4gICAgZ2F0ZSxcbiAgICBmb3J3YXJkSGVhZGVyczogcmVzb2x2ZWQuZ2F0ZS5mb3J3YXJkSGVhZGVycyxcbiAgfSk7XG5cbiAgaWYgKHJlc29sdmVkLnBvcnRyKSB7XG4gICAgY29uc3QgcG9ydHJFbnYgPSBhd2FpdCBwb3J0ci5pbnN0YWxsUG9ydHIoKTtcbiAgICBhd2FpdCBwb3J0ci53cml0ZVBvcnRyQ29uZmlnKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudik7XG4gICAgY2hpbGRyZW4ucHVzaChhd2FpdCBwb3J0ci5zdGFydFBvcnRyKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudikpO1xuICB9IGVsc2Uge1xuICAgIGxvZ2dlci5pbmZvKFwibm8gUE9SVFJfVE9LRU4gLyBUVU5ORUxfUFVCTElDX0RPTUFJTiAtIHNlcnZpbmcgbG9jYWxseSBvbmx5XCIsIHtcbiAgICAgIHB1YmxpY1BvcnQ6IHJlc29sdmVkLnB1YmxpY1BvcnQsXG4gICAgfSk7XG4gIH1cbiAgc3VwZXJ2aXNlKGNoaWxkcmVuKTtcbn1cblxuLyoqIFRoZSBgZGJ4IHR1bm5lbGAgcHJvZ3JhbS4gTm8gc2lkZSBlZmZlY3RzIHVudGlsIHBhcnNlZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZFByb2dyYW0obmFtZSA9IFwiZGJ4IHR1bm5lbFwiKTogQ29tbWFuZCB7XG4gIGNvbnN0IHByb2dyYW0gPSBhZGRPcHRpb25zKFxuICAgIG5ldyBDb21tYW5kKClcbiAgICAgIC5uYW1lKG5hbWUpXG4gICAgICAuZGVzY3JpcHRpb24oXCJGcm9udCBhIGNvbW1hbmQgd2l0aCBhIHBvcnRyIHR1bm5lbCBhbmQgYW4gZW1haWwtT1RQIGdhdGVcIiksXG4gICk7XG5cbiAgLy8gYHJ1bmAgaXMgdGhlIERFRkFVTFQgYWN0aW9uIGFzIHdlbGwgYXMgYSBuYW1lZCBzdWJjb21tYW5kLCBwcmVzZXJ2aW5nIHRoZSBvbGRcbiAgLy8gd3JhcHBlcidzIGVyZ29ub21pY3MgKGBkYnggdHVubmVsIC0tYWxsb3cgeCAtLSBidW4gc3JjL3NlcnZlci50c2ApIHdoaWxlXG4gIC8vIGxlYXZpbmcgc29tZXdoZXJlIGZvciBgc3RhdHVzYCBhbmQgYGluc3RhbGxgIHRvIGxpdmUuXG4gIHByb2dyYW1cbiAgICAuYXJndW1lbnQoXCJbY29tbWFuZC4uLl1cIiwgXCJ0aGUgY29tbWFuZCB0byB3cmFwLCBhZnRlciBgLS1gXCIpXG4gICAgLmFjdGlvbihhc3luYyAoY29tbWFuZDogc3RyaW5nW10sIF9vcHRpb25zOiBUdW5uZWxPcHRpb25zLCBjbWQ6IENvbW1hbmQpID0+IHtcbiAgICAgIGF3YWl0IHJ1bihjbWQub3B0czxUdW5uZWxPcHRpb25zPigpLCBjb21tYW5kKTtcbiAgICB9KTtcblxuICBhZGRPcHRpb25zKFxuICAgIHByb2dyYW0uY29tbWFuZChcInJ1blwiKS5kZXNjcmlwdGlvbihcIldyYXAgYSBjb21tYW5kICh0aGUgZGVmYXVsdCBhY3Rpb24pXCIpLFxuICApXG4gICAgLmFyZ3VtZW50KFwiPGNvbW1hbmQuLi4+XCIsIFwidGhlIGNvbW1hbmQgdG8gd3JhcCwgYWZ0ZXIgYC0tYFwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKGNvbW1hbmQ6IHN0cmluZ1tdLCBfb3B0aW9uczogVHVubmVsT3B0aW9ucywgY21kOiBDb21tYW5kKSA9PiB7XG4gICAgICBhd2FpdCBydW4oY21kLm9wdHM8VHVubmVsT3B0aW9ucz4oKSwgY29tbWFuZCk7XG4gICAgfSk7XG5cbiAgLy8gV29ydGggaXRzIG93biBjb21tYW5kOiB0aGUgbW9zdCBjb21tb24gZmFpbHVyZSBpcyBhIHR1bm5lbCB0aGF0IHNpbGVudGx5XG4gIC8vIGRvZXMgbm90aGluZyBiZWNhdXNlIG5vIHRva2VuIG9yIGRvbWFpbiByZXNvbHZlZCwgYW5kIHRoaXMgcHJpbnRzIGV4YWN0bHlcbiAgLy8gd2hhdCB3b3VsZCBoYXBwZW4gd2l0aG91dCBzdGFydGluZyBhbnl0aGluZy5cbiAgYWRkT3B0aW9ucyhcbiAgICBwcm9ncmFtLmNvbW1hbmQoXCJzdGF0dXNcIikuZGVzY3JpcHRpb24oXCJSZXNvbHZlIHRoZSBjb25maWd1cmF0aW9uIGFuZCBwcmludCBpdFwiKSxcbiAgKS5hY3Rpb24oKF9vcHRpb25zOiBUdW5uZWxPcHRpb25zLCBjbWQ6IENvbW1hbmQpID0+IHtcbiAgICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVUdW5uZWxPcHRpb25zKGNtZC5vcHRzPFR1bm5lbE9wdGlvbnM+KCkpO1xuICAgIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KHJlc29sdmVkLCBudWxsLCAyKX1cXG5gKTtcbiAgfSk7XG5cbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiaW5zdGFsbFwiKVxuICAgIC5kZXNjcmlwdGlvbihcIkluc3RhbGwgdGhlIHBvcnRyIGJpbmFyeSBhbmQgZXhpdFwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgcG9ydHIuaW5zdGFsbFBvcnRyKCk7XG4gICAgfSk7XG5cbiAgcmV0dXJuIHByb2dyYW07XG59XG4iXX0=
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flag -> config -> default resolution for `dbx tunnel`.
|
|
3
|
+
*
|
|
4
|
+
* The point of this module is that it does almost NOTHING itself: every gate
|
|
5
|
+
* setting is handed straight to `@dbx-tools/tunnel`'s own
|
|
6
|
+
* `plugin.resolveAuthGateConfig`, which is the same function the in-process
|
|
7
|
+
* plugin path calls. The CLI therefore cannot drift from the plugin on a default,
|
|
8
|
+
* an env name, or a coercion rule - a flag is just a value passed where the
|
|
9
|
+
* plugin's `config` object would go, and `config.*` fills the rest in from the
|
|
10
|
+
* environment, a `.env` file, or `databricks.yml`.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { type AuthGateConfig, plugin, portr } from "@dbx-tools/tunnel";
|
|
15
|
+
/** Raw commander flag values (every numeric flag arrives as a string). */
|
|
16
|
+
export interface TunnelOptions {
|
|
17
|
+
publicDomain?: string;
|
|
18
|
+
subdomain?: string;
|
|
19
|
+
port?: string | number;
|
|
20
|
+
appPort?: string | number;
|
|
21
|
+
allow?: string[];
|
|
22
|
+
subject?: string;
|
|
23
|
+
brandName?: string;
|
|
24
|
+
message?: string;
|
|
25
|
+
sessionTtl?: string | number;
|
|
26
|
+
codeTtl?: string | number;
|
|
27
|
+
sessionCutoff?: string;
|
|
28
|
+
forwardHeaders?: string[];
|
|
29
|
+
insecure?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ResolvedTunnelOptions {
|
|
32
|
+
/** The port the wrapper itself listens on - what portr forwards to. */
|
|
33
|
+
publicPort: number;
|
|
34
|
+
/** The private port the wrapped app is told to bind. Unset means "pick one". */
|
|
35
|
+
appPort?: number;
|
|
36
|
+
/**
|
|
37
|
+
* The gate config as the `authGate` PLUGIN takes it - flags only, nothing
|
|
38
|
+
* resolved. Passed straight to the plugin so it applies its own fallbacks
|
|
39
|
+
* exactly once, in the one place that owns them.
|
|
40
|
+
*/
|
|
41
|
+
gateConfig: AuthGateConfig;
|
|
42
|
+
/** The same config after the plugin's resolution, for `status` and for routing. */
|
|
43
|
+
gate: plugin.ResolvedAuthGateConfig;
|
|
44
|
+
portr: ReturnType<typeof portr.resolvePortrConfig>;
|
|
45
|
+
}
|
|
46
|
+
export declare function resolveTunnelOptions(options: TunnelOptions): ResolvedTunnelOptions;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flag -> config -> default resolution for `dbx tunnel`.
|
|
3
|
+
*
|
|
4
|
+
* The point of this module is that it does almost NOTHING itself: every gate
|
|
5
|
+
* setting is handed straight to `@dbx-tools/tunnel`'s own
|
|
6
|
+
* `plugin.resolveAuthGateConfig`, which is the same function the in-process
|
|
7
|
+
* plugin path calls. The CLI therefore cannot drift from the plugin on a default,
|
|
8
|
+
* an env name, or a coercion rule - a flag is just a value passed where the
|
|
9
|
+
* plugin's `config` object would go, and `config.*` fills the rest in from the
|
|
10
|
+
* environment, a `.env` file, or `databricks.yml`.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { config } from "@dbx-tools/core";
|
|
15
|
+
import { object } from "@dbx-tools/shared-core";
|
|
16
|
+
import { plugin, portr } from "@dbx-tools/tunnel";
|
|
17
|
+
export function resolveTunnelOptions(options) {
|
|
18
|
+
// The Databricks Apps runtime contract: the platform routes to
|
|
19
|
+
// DATABRICKS_APP_PORT, so the WRAPPER claims it and the wrapped app is moved
|
|
20
|
+
// to a private one.
|
|
21
|
+
const publicPort = config.positiveInt(options.port, "DATABRICKS_APP_PORT", 8000);
|
|
22
|
+
const appPort = config.positiveInt(options.appPort, "APP_PORT", 0, { prefix: "TUNNEL" });
|
|
23
|
+
const gateConfig = {
|
|
24
|
+
allow: options.allow,
|
|
25
|
+
subject: options.subject,
|
|
26
|
+
brandName: options.brandName,
|
|
27
|
+
message: options.message,
|
|
28
|
+
// Coerced, not resolved: the plugin owns the env name and the default for
|
|
29
|
+
// these, so the flag is passed through as the `config` value it expects and
|
|
30
|
+
// only needs a string -> number nudge on the way.
|
|
31
|
+
sessionTtlSeconds: object.toNumber(options.sessionTtl),
|
|
32
|
+
codeTtlSeconds: object.toNumber(options.codeTtl),
|
|
33
|
+
sessionCutoff: options.sessionCutoff,
|
|
34
|
+
forwardHeaders: options.forwardHeaders,
|
|
35
|
+
insecure: options.insecure,
|
|
36
|
+
publicDomain: options.publicDomain,
|
|
37
|
+
};
|
|
38
|
+
const gate = plugin.resolveAuthGateConfig(gateConfig);
|
|
39
|
+
return {
|
|
40
|
+
publicPort,
|
|
41
|
+
...(appPort > 0 ? { appPort } : {}),
|
|
42
|
+
gateConfig,
|
|
43
|
+
gate,
|
|
44
|
+
portr: portr.resolvePortrConfig({
|
|
45
|
+
publicDomain: gate.publicDomain,
|
|
46
|
+
subdomain: options.subdomain,
|
|
47
|
+
port: publicPort,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcHRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7R0FZRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEQsT0FBTyxFQUF1QixNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFtQ3ZFLE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxPQUFzQjtJQUN6RCwrREFBK0Q7SUFDL0QsNkVBQTZFO0lBQzdFLG9CQUFvQjtJQUNwQixNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUscUJBQXFCLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDakYsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUN6RixNQUFNLFVBQVUsR0FBbUI7UUFDakMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1FBQ3BCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztRQUN4QixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7UUFDNUIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLDBFQUEwRTtRQUMxRSw0RUFBNEU7UUFDNUUsa0RBQWtEO1FBQ2xELGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztRQUN0RCxjQUFjLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1FBQ2hELGFBQWEsRUFBRSxPQUFPLENBQUMsYUFBYTtRQUNwQyxjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWM7UUFDdEMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1FBQzFCLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtLQUNuQyxDQUFDO0lBQ0YsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RELE9BQU87UUFDTCxVQUFVO1FBQ1YsR0FBRyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNuQyxVQUFVO1FBQ1YsSUFBSTtRQUNKLEtBQUssRUFBRSxLQUFLLENBQUMsa0JBQWtCLENBQUM7WUFDOUIsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZO1lBQy9CLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztZQUM1QixJQUFJLEVBQUUsVUFBVTtTQUNqQixDQUFDO0tBQ0gsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZsYWcgLT4gY29uZmlnIC0+IGRlZmF1bHQgcmVzb2x1dGlvbiBmb3IgYGRieCB0dW5uZWxgLlxuICpcbiAqIFRoZSBwb2ludCBvZiB0aGlzIG1vZHVsZSBpcyB0aGF0IGl0IGRvZXMgYWxtb3N0IE5PVEhJTkcgaXRzZWxmOiBldmVyeSBnYXRlXG4gKiBzZXR0aW5nIGlzIGhhbmRlZCBzdHJhaWdodCB0byBgQGRieC10b29scy90dW5uZWxgJ3Mgb3duXG4gKiBgcGx1Z2luLnJlc29sdmVBdXRoR2F0ZUNvbmZpZ2AsIHdoaWNoIGlzIHRoZSBzYW1lIGZ1bmN0aW9uIHRoZSBpbi1wcm9jZXNzXG4gKiBwbHVnaW4gcGF0aCBjYWxscy4gVGhlIENMSSB0aGVyZWZvcmUgY2Fubm90IGRyaWZ0IGZyb20gdGhlIHBsdWdpbiBvbiBhIGRlZmF1bHQsXG4gKiBhbiBlbnYgbmFtZSwgb3IgYSBjb2VyY2lvbiBydWxlIC0gYSBmbGFnIGlzIGp1c3QgYSB2YWx1ZSBwYXNzZWQgd2hlcmUgdGhlXG4gKiBwbHVnaW4ncyBgY29uZmlnYCBvYmplY3Qgd291bGQgZ28sIGFuZCBgY29uZmlnLipgIGZpbGxzIHRoZSByZXN0IGluIGZyb20gdGhlXG4gKiBlbnZpcm9ubWVudCwgYSBgLmVudmAgZmlsZSwgb3IgYGRhdGFicmlja3MueW1sYC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSBcIkBkYngtdG9vbHMvY29yZVwiO1xuaW1wb3J0IHsgb2JqZWN0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IHR5cGUgQXV0aEdhdGVDb25maWcsIHBsdWdpbiwgcG9ydHIgfSBmcm9tIFwiQGRieC10b29scy90dW5uZWxcIjtcblxuLyoqIFJhdyBjb21tYW5kZXIgZmxhZyB2YWx1ZXMgKGV2ZXJ5IG51bWVyaWMgZmxhZyBhcnJpdmVzIGFzIGEgc3RyaW5nKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHVubmVsT3B0aW9ucyB7XG4gIHB1YmxpY0RvbWFpbj86IHN0cmluZztcbiAgc3ViZG9tYWluPzogc3RyaW5nO1xuICBwb3J0Pzogc3RyaW5nIHwgbnVtYmVyO1xuICBhcHBQb3J0Pzogc3RyaW5nIHwgbnVtYmVyO1xuICBhbGxvdz86IHN0cmluZ1tdO1xuICBzdWJqZWN0Pzogc3RyaW5nO1xuICBicmFuZE5hbWU/OiBzdHJpbmc7XG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG4gIHNlc3Npb25UdGw/OiBzdHJpbmcgfCBudW1iZXI7XG4gIGNvZGVUdGw/OiBzdHJpbmcgfCBudW1iZXI7XG4gIHNlc3Npb25DdXRvZmY/OiBzdHJpbmc7XG4gIGZvcndhcmRIZWFkZXJzPzogc3RyaW5nW107XG4gIGluc2VjdXJlPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZFR1bm5lbE9wdGlvbnMge1xuICAvKiogVGhlIHBvcnQgdGhlIHdyYXBwZXIgaXRzZWxmIGxpc3RlbnMgb24gLSB3aGF0IHBvcnRyIGZvcndhcmRzIHRvLiAqL1xuICBwdWJsaWNQb3J0OiBudW1iZXI7XG4gIC8qKiBUaGUgcHJpdmF0ZSBwb3J0IHRoZSB3cmFwcGVkIGFwcCBpcyB0b2xkIHRvIGJpbmQuIFVuc2V0IG1lYW5zIFwicGljayBvbmVcIi4gKi9cbiAgYXBwUG9ydD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBnYXRlIGNvbmZpZyBhcyB0aGUgYGF1dGhHYXRlYCBQTFVHSU4gdGFrZXMgaXQgLSBmbGFncyBvbmx5LCBub3RoaW5nXG4gICAqIHJlc29sdmVkLiBQYXNzZWQgc3RyYWlnaHQgdG8gdGhlIHBsdWdpbiBzbyBpdCBhcHBsaWVzIGl0cyBvd24gZmFsbGJhY2tzXG4gICAqIGV4YWN0bHkgb25jZSwgaW4gdGhlIG9uZSBwbGFjZSB0aGF0IG93bnMgdGhlbS5cbiAgICovXG4gIGdhdGVDb25maWc6IEF1dGhHYXRlQ29uZmlnO1xuICAvKiogVGhlIHNhbWUgY29uZmlnIGFmdGVyIHRoZSBwbHVnaW4ncyByZXNvbHV0aW9uLCBmb3IgYHN0YXR1c2AgYW5kIGZvciByb3V0aW5nLiAqL1xuICBnYXRlOiBwbHVnaW4uUmVzb2x2ZWRBdXRoR2F0ZUNvbmZpZztcbiAgcG9ydHI6IFJldHVyblR5cGU8dHlwZW9mIHBvcnRyLnJlc29sdmVQb3J0ckNvbmZpZz47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlVHVubmVsT3B0aW9ucyhvcHRpb25zOiBUdW5uZWxPcHRpb25zKTogUmVzb2x2ZWRUdW5uZWxPcHRpb25zIHtcbiAgLy8gVGhlIERhdGFicmlja3MgQXBwcyBydW50aW1lIGNvbnRyYWN0OiB0aGUgcGxhdGZvcm0gcm91dGVzIHRvXG4gIC8vIERBVEFCUklDS1NfQVBQX1BPUlQsIHNvIHRoZSBXUkFQUEVSIGNsYWltcyBpdCBhbmQgdGhlIHdyYXBwZWQgYXBwIGlzIG1vdmVkXG4gIC8vIHRvIGEgcHJpdmF0ZSBvbmUuXG4gIGNvbnN0IHB1YmxpY1BvcnQgPSBjb25maWcucG9zaXRpdmVJbnQob3B0aW9ucy5wb3J0LCBcIkRBVEFCUklDS1NfQVBQX1BPUlRcIiwgODAwMCk7XG4gIGNvbnN0IGFwcFBvcnQgPSBjb25maWcucG9zaXRpdmVJbnQob3B0aW9ucy5hcHBQb3J0LCBcIkFQUF9QT1JUXCIsIDAsIHsgcHJlZml4OiBcIlRVTk5FTFwiIH0pO1xuICBjb25zdCBnYXRlQ29uZmlnOiBBdXRoR2F0ZUNvbmZpZyA9IHtcbiAgICBhbGxvdzogb3B0aW9ucy5hbGxvdyxcbiAgICBzdWJqZWN0OiBvcHRpb25zLnN1YmplY3QsXG4gICAgYnJhbmROYW1lOiBvcHRpb25zLmJyYW5kTmFtZSxcbiAgICBtZXNzYWdlOiBvcHRpb25zLm1lc3NhZ2UsXG4gICAgLy8gQ29lcmNlZCwgbm90IHJlc29sdmVkOiB0aGUgcGx1Z2luIG93bnMgdGhlIGVudiBuYW1lIGFuZCB0aGUgZGVmYXVsdCBmb3JcbiAgICAvLyB0aGVzZSwgc28gdGhlIGZsYWcgaXMgcGFzc2VkIHRocm91Z2ggYXMgdGhlIGBjb25maWdgIHZhbHVlIGl0IGV4cGVjdHMgYW5kXG4gICAgLy8gb25seSBuZWVkcyBhIHN0cmluZyAtPiBudW1iZXIgbnVkZ2Ugb24gdGhlIHdheS5cbiAgICBzZXNzaW9uVHRsU2Vjb25kczogb2JqZWN0LnRvTnVtYmVyKG9wdGlvbnMuc2Vzc2lvblR0bCksXG4gICAgY29kZVR0bFNlY29uZHM6IG9iamVjdC50b051bWJlcihvcHRpb25zLmNvZGVUdGwpLFxuICAgIHNlc3Npb25DdXRvZmY6IG9wdGlvbnMuc2Vzc2lvbkN1dG9mZixcbiAgICBmb3J3YXJkSGVhZGVyczogb3B0aW9ucy5mb3J3YXJkSGVhZGVycyxcbiAgICBpbnNlY3VyZTogb3B0aW9ucy5pbnNlY3VyZSxcbiAgICBwdWJsaWNEb21haW46IG9wdGlvbnMucHVibGljRG9tYWluLFxuICB9O1xuICBjb25zdCBnYXRlID0gcGx1Z2luLnJlc29sdmVBdXRoR2F0ZUNvbmZpZyhnYXRlQ29uZmlnKTtcbiAgcmV0dXJuIHtcbiAgICBwdWJsaWNQb3J0LFxuICAgIC4uLihhcHBQb3J0ID4gMCA/IHsgYXBwUG9ydCB9IDoge30pLFxuICAgIGdhdGVDb25maWcsXG4gICAgZ2F0ZSxcbiAgICBwb3J0cjogcG9ydHIucmVzb2x2ZVBvcnRyQ29uZmlnKHtcbiAgICAgIHB1YmxpY0RvbWFpbjogZ2F0ZS5wdWJsaWNEb21haW4sXG4gICAgICBzdWJkb21haW46IG9wdGlvbnMuc3ViZG9tYWluLFxuICAgICAgcG9ydDogcHVibGljUG9ydCxcbiAgICB9KSxcbiAgfTtcbn1cbiJdfQ==
|
package/lib/src/proxy.d.ts
CHANGED
|
@@ -1,49 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The reverse proxy that makes the wrapper path possible.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The wrapper claims the PUBLIC port and the wrapped app runs as a child process
|
|
5
|
+
* on a private loopback port, so - unlike the in-process plugin - there is no
|
|
6
|
+
* middleware chain to insert the gate into. This proxy is that insertion point: it
|
|
7
|
+
* answers the login routes itself, applies the gate to everything else, and
|
|
8
|
+
* forwards what survives to the child.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* that path; the gate exists for the tunnel, which nothing else protects.
|
|
15
|
-
*
|
|
16
|
-
* The distinguisher is the connection's source address: a loopback
|
|
17
|
-
* `req.socket.remoteAddress` is the portr client; anything else is the platform.
|
|
18
|
-
*
|
|
19
|
-
* For portr traffic the gate is a standard SPA gate: static assets + the login
|
|
20
|
-
* flow (`/api/email/auth/*`, answered IN-PROCESS by this proxy via the
|
|
21
|
-
* {@link AuthGateApi}) are open so the browser can load the client and render the
|
|
22
|
-
* `<AuthGate>`; every other `/api/*` needs a valid session cookie or gets 401.
|
|
23
|
-
* WebSocket upgrades are gated the same way and forwarded with `http-proxy-3`.
|
|
10
|
+
* The gating DECISION is not reimplemented here. `@dbx-tools/tunnel`'s
|
|
11
|
+
* `gate.gateRequest` makes it - the same function the Express middleware calls -
|
|
12
|
+
* and this module only differs in how the outcome is written: a proxied request
|
|
13
|
+
* instead of `next()`, a `writeHead` instead of `res.json`. That is deliberate:
|
|
14
|
+
* two independent implementations of "which requests are gated and which headers
|
|
15
|
+
* are stripped" is the one way this package could become a security bug.
|
|
24
16
|
*
|
|
25
17
|
* @module
|
|
26
18
|
*/
|
|
27
|
-
import type
|
|
28
|
-
/** Options for {@link startProxy}. */
|
|
19
|
+
import { type AuthGateApi } from "@dbx-tools/tunnel";
|
|
29
20
|
export interface ProxyOptions {
|
|
30
|
-
/**
|
|
21
|
+
/** The port this proxy listens on - the port portr and the platform route to. */
|
|
31
22
|
publicPort: number;
|
|
32
|
-
/**
|
|
23
|
+
/** The private loopback port the wrapped app listens on. */
|
|
33
24
|
appPort: number;
|
|
34
|
-
/**
|
|
35
|
-
* The in-process gate API, or `undefined` to run OPEN (insecure mode): every
|
|
36
|
-
* request - including portr traffic - is forwarded ungated. Used when the
|
|
37
|
-
* operator passed `--insecure` / `TUNNEL_INSECURE=true`.
|
|
38
|
-
*/
|
|
25
|
+
/** The gate handlers. Omitted (an `--insecure` run) forwards everything. */
|
|
39
26
|
gate?: AuthGateApi;
|
|
40
|
-
/**
|
|
41
|
-
* Extra `x-` request headers tunnel traffic may forward, as literals, globs, or
|
|
42
|
-
* `/regex/`es - unioned with {@link DEFAULT_FORWARD_HEADERS}. Every other `x-`
|
|
43
|
-
* header is stripped, and {@link PROTECTED_HEADERS} is stripped regardless. See
|
|
44
|
-
* `./headers.ts` for why the policy is an allow-list.
|
|
45
|
-
*/
|
|
27
|
+
/** Extra `x-` headers tunnel traffic may forward. */
|
|
46
28
|
forwardHeaders?: readonly string[];
|
|
47
29
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Start the proxy and resolve once it is listening.
|
|
32
|
+
*
|
|
33
|
+
* `publicDomain` is intentionally NOT passed to `gateRequest`: on this path every
|
|
34
|
+
* request arrived on the public port, so it IS tunnel traffic by construction -
|
|
35
|
+
* whereas the in-process gate shares a port with the platform front door and has
|
|
36
|
+
* to tell them apart by `Host`. Passing the request's own host keeps the shared
|
|
37
|
+
* decision function's contract satisfied without weakening it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function startProxy(options: ProxyOptions): Promise<void>;
|