@dbx-tools/lakebox 0.0.0-stage → 0.9.131

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,382 @@
1
+ import { mkdtemp, rm } from "node:fs/promises";
2
+ import { createConnection, createServer } from "node:net";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { setTimeout as delay } from "node:timers/promises";
6
+ import { exec } from "@dbx-tools/core";
7
+ import { errorUtils, log, stringUtils } from "@dbx-tools/shared-core";
8
+ import { SocksClient } from "socks";
9
+ import { PooledSshTransport, } from "./_ssh.js";
10
+ const SOCKS_HOST = "127.0.0.1";
11
+ const OPENSSH_HELPER_TIMEOUT_MS = 2_000;
12
+ const logger = log.logger("lakebox:openssh");
13
+ const nativeOpenSshSupportByCommand = new Map();
14
+ const activeNativeOpenSshProcesses = new Set();
15
+ const parentBoundNativeOpenSshProcesses = new WeakSet();
16
+ let stopParentTerminationSignal;
17
+ let processExitHookInstalled = false;
18
+ /** @internal JavaScript watchdog that terminates one child when its parent pipe closes. */
19
+ export const OPENSSH_PARENT_WATCH_SOURCE = stringUtils.dedent(// ============================================================================
20
+ /*js*/ `
21
+ const { spawn } = require("node:child_process");
22
+
23
+ const child = spawn(process.argv[1], process.argv.slice(2), {
24
+ stdio: ["ignore", "ignore", "inherit"],
25
+ });
26
+ let stopping = false;
27
+ const stopChild = () => {
28
+ if (stopping) return;
29
+ stopping = true;
30
+ child.kill("SIGKILL");
31
+ };
32
+
33
+ process.stdin.resume();
34
+ process.stdin.once("end", stopChild);
35
+ process.stdin.once("close", stopChild);
36
+ child.once("error", (error) => {
37
+ console.error(error);
38
+ process.exit(1);
39
+ });
40
+ child.once("exit", (code, signal) => {
41
+ process.stdin.pause();
42
+ process.exit(code ?? (signal ? 1 : 0));
43
+ });
44
+ `);
45
+ /** Exclusive native OpenSSH ControlMaster pool. */
46
+ export class OpenSshTransport extends PooledSshTransport {
47
+ kind = "openssh";
48
+ constructor(options, command, poolOptions = {}, lifecycle = openSshLifecycle(options, command)) {
49
+ super(lifecycle, {
50
+ acquireTimeoutMillis: options.connectTimeoutMs,
51
+ ...poolOptions,
52
+ });
53
+ }
54
+ runWithResource(resource, script, execution) {
55
+ return resource.run(script, execution);
56
+ }
57
+ connectWithResource(resource, remoteHost, remotePort) {
58
+ return resource.connect(remoteHost, remotePort);
59
+ }
60
+ }
61
+ /** Return whether an executable is OpenSSH and accepts dynamic SOCKS5 forwarding. */
62
+ export async function supportsNativeOpenSsh(command = "ssh") {
63
+ const cached = nativeOpenSshSupportByCommand.get(command);
64
+ if (cached)
65
+ return cached;
66
+ const probe = probeNativeOpenSsh(command);
67
+ nativeOpenSshSupportByCommand.set(command, probe);
68
+ return probe;
69
+ }
70
+ /** @internal OpenSSH arguments shared by pooled ControlMaster processes. */
71
+ export function nativeOpenSshArgs(options) {
72
+ return [
73
+ "-i",
74
+ options.privateKeyPath,
75
+ "-p",
76
+ String(options.port),
77
+ "-T",
78
+ "-o",
79
+ "BatchMode=yes",
80
+ "-o",
81
+ "IdentitiesOnly=yes",
82
+ "-o",
83
+ "ForwardAgent=no",
84
+ "-o",
85
+ "PreferredAuthentications=publickey",
86
+ "-o",
87
+ "StrictHostKeyChecking=yes",
88
+ "-o",
89
+ `UserKnownHostsFile=${options.knownHostsPath}`,
90
+ "-o",
91
+ `HostKeyAlias=[${options.host}]:${options.port}`,
92
+ "-o",
93
+ "LogLevel=ERROR",
94
+ "-o",
95
+ `ConnectTimeout=${Math.max(1, Math.ceil(options.connectTimeoutMs / 1_000))}`,
96
+ "-o",
97
+ "ServerAliveInterval=15",
98
+ "-o",
99
+ "ServerAliveCountMax=3",
100
+ ];
101
+ }
102
+ function openSshLifecycle(options, command) {
103
+ return {
104
+ create: () => NativeOpenSshResource.create(options, command),
105
+ destroy: (resource) => resource.close(),
106
+ test: (resource) => resource.test(),
107
+ };
108
+ }
109
+ class NativeOpenSshResource {
110
+ options;
111
+ command;
112
+ directory;
113
+ controlPath;
114
+ socksPort;
115
+ master;
116
+ alive = true;
117
+ closing;
118
+ constructor(options, command, directory, controlPath, socksPort, master) {
119
+ this.options = options;
120
+ this.command = command;
121
+ this.directory = directory;
122
+ this.controlPath = controlPath;
123
+ this.socksPort = socksPort;
124
+ this.master = master;
125
+ const closed = () => {
126
+ this.alive = false;
127
+ };
128
+ void master.then(closed, closed);
129
+ }
130
+ static async create(options, command) {
131
+ const directory = await mkdtemp(join(tmpdir(), "dbx-tools-ssh-"));
132
+ try {
133
+ const controlPath = join(directory, "control");
134
+ const socksPort = await availableLoopbackPort();
135
+ const target = `${options.username}@${options.connectHost}`;
136
+ const master = trackNativeOpenSshProcess(exec.spawn(process.execPath, [
137
+ "-e",
138
+ OPENSSH_PARENT_WATCH_SOURCE,
139
+ command,
140
+ ...nativeOpenSshArgs(options),
141
+ "-M",
142
+ "-N",
143
+ "-S",
144
+ controlPath,
145
+ "-o",
146
+ "ControlPersist=no",
147
+ "-o",
148
+ "ExitOnForwardFailure=yes",
149
+ "-D",
150
+ `${SOCKS_HOST}:${socksPort}`,
151
+ target,
152
+ ], {
153
+ stdin: "pipe",
154
+ stdout: "ignore",
155
+ stderr: "capture",
156
+ trim: false,
157
+ forwardTerminationSignals: false,
158
+ }), true);
159
+ const resource = new NativeOpenSshResource(options, command, directory, controlPath, socksPort, master);
160
+ try {
161
+ await resource.waitUntilReady();
162
+ return resource;
163
+ }
164
+ catch (error) {
165
+ await resource.close();
166
+ throw error;
167
+ }
168
+ }
169
+ catch (error) {
170
+ await rm(directory, { recursive: true, force: true });
171
+ throw error;
172
+ }
173
+ }
174
+ async run(script, execution) {
175
+ const child = trackNativeOpenSshProcess(exec.spawn(this.command, [
176
+ ...nativeOpenSshArgs(this.options),
177
+ "-S",
178
+ this.controlPath,
179
+ "-o",
180
+ "ControlMaster=no",
181
+ `${this.options.username}@${this.options.connectHost}`,
182
+ script,
183
+ ], {
184
+ stdin: "ignore",
185
+ stdout: "pipe",
186
+ stderr: "pipe",
187
+ trim: false,
188
+ forwardTerminationSignals: false,
189
+ }));
190
+ child.stdout?.on("data", execution.stdout);
191
+ child.stderr?.on("data", execution.stderr);
192
+ let shutdown;
193
+ execution.setCancel(() => {
194
+ shutdown ??= child.shutdown({ terminateTimeout: 0, killTimeout: 1_000 }).catch((error) => {
195
+ logger.warn("failed to stop native SSH command", { error: errorUtils.toError(error) });
196
+ });
197
+ return shutdown;
198
+ });
199
+ return (await child).exitCode;
200
+ }
201
+ async connect(remoteHost, remotePort) {
202
+ const connection = await SocksClient.createConnection({
203
+ command: "connect",
204
+ destination: { host: remoteHost, port: remotePort },
205
+ proxy: { host: SOCKS_HOST, port: this.socksPort, type: 5 },
206
+ timeout: this.options.connectTimeoutMs,
207
+ set_tcp_nodelay: true,
208
+ });
209
+ return connection.socket;
210
+ }
211
+ async test() {
212
+ if (!this.alive || this.master.exitCode !== null)
213
+ return false;
214
+ try {
215
+ return (await this.control("check")).exitCode === 0;
216
+ }
217
+ catch {
218
+ return false;
219
+ }
220
+ }
221
+ async close() {
222
+ if (this.closing)
223
+ return this.closing;
224
+ this.alive = false;
225
+ this.closing = this.closeResource();
226
+ return this.closing;
227
+ }
228
+ async closeResource() {
229
+ try {
230
+ await this.control("exit").catch(() => undefined);
231
+ }
232
+ finally {
233
+ await this.master.shutdown({ terminateTimeout: 0, killTimeout: 1_000 }).catch((error) => logger.warn("failed to stop native SSH ControlMaster", {
234
+ error: errorUtils.toError(error),
235
+ }));
236
+ await rm(this.directory, { recursive: true, force: true });
237
+ }
238
+ }
239
+ async waitUntilReady() {
240
+ const deadline = Date.now() + this.options.connectTimeoutMs;
241
+ while (Date.now() < deadline) {
242
+ if (this.master.exitCode !== null) {
243
+ const result = await this.master;
244
+ throw new Error(`Native OpenSSH ControlMaster exited (${result.exitCode}): ${result.stderr.trim()}`);
245
+ }
246
+ if ((await this.test()) && (await canConnectLoopback(this.socksPort)))
247
+ return;
248
+ await delay(50);
249
+ }
250
+ throw new Error(`Native OpenSSH ControlMaster did not become ready within ${this.options.connectTimeoutMs}ms`);
251
+ }
252
+ control(operation) {
253
+ const child = trackNativeOpenSshProcess(exec.spawn(this.command, [
254
+ "-p",
255
+ String(this.options.port),
256
+ "-S",
257
+ this.controlPath,
258
+ "-O",
259
+ operation,
260
+ `${this.options.username}@${this.options.connectHost}`,
261
+ ], {
262
+ stdin: "ignore",
263
+ stdout: "ignore",
264
+ stderr: "ignore",
265
+ forwardTerminationSignals: false,
266
+ }));
267
+ return waitForNativeOpenSshChild(child, `ssh -O ${operation}`);
268
+ }
269
+ }
270
+ async function probeNativeOpenSsh(command) {
271
+ try {
272
+ const version = await waitForNativeOpenSshChild(trackNativeOpenSshProcess(exec.spawn(command, ["-V"], {
273
+ stdin: "ignore",
274
+ stdout: "capture",
275
+ stderr: "capture",
276
+ forwardTerminationSignals: false,
277
+ })), "ssh -V");
278
+ const versionOutput = `${version.stdout}\n${version.stderr}`;
279
+ if (version.exitCode !== 0 || !/(?:^|\s)OpenSSH_/m.test(versionOutput))
280
+ return false;
281
+ const dynamicForward = await waitForNativeOpenSshChild(trackNativeOpenSshProcess(exec.spawn(command, ["-G", "-D", `${SOCKS_HOST}:1`, "localhost"], {
282
+ stdin: "ignore",
283
+ stdout: "ignore",
284
+ stderr: "ignore",
285
+ forwardTerminationSignals: false,
286
+ })), "ssh -G");
287
+ return dynamicForward.exitCode === 0;
288
+ }
289
+ catch {
290
+ return false;
291
+ }
292
+ }
293
+ async function waitForNativeOpenSshChild(child, operation) {
294
+ let timeout;
295
+ const timedOut = new Promise((_resolve, reject) => {
296
+ timeout = setTimeout(() => {
297
+ void child.shutdown({ terminateTimeout: 0, killTimeout: 1_000 }).then(() => reject(new Error(`${operation} timed out after ${OPENSSH_HELPER_TIMEOUT_MS}ms`)), (error) => reject(error));
298
+ }, OPENSSH_HELPER_TIMEOUT_MS);
299
+ timeout.unref?.();
300
+ });
301
+ try {
302
+ return await Promise.race([child, timedOut]);
303
+ }
304
+ finally {
305
+ clearTimeout(timeout);
306
+ }
307
+ }
308
+ function trackNativeOpenSshProcess(child, parentBound = false) {
309
+ activeNativeOpenSshProcesses.add(child);
310
+ if (parentBound)
311
+ parentBoundNativeOpenSshProcesses.add(child);
312
+ if (!stopParentTerminationSignal) {
313
+ stopParentTerminationSignal = exec.onParentTerminationSignal(forceStopNativeOpenSshProcesses);
314
+ }
315
+ if (!processExitHookInstalled) {
316
+ processExitHookInstalled = true;
317
+ process.once("exit", forceStopNativeOpenSshProcesses);
318
+ }
319
+ let tracked = true;
320
+ const untrack = () => {
321
+ if (!tracked)
322
+ return;
323
+ tracked = false;
324
+ void child.off("exit", untrack);
325
+ void child.off("error", untrack);
326
+ activeNativeOpenSshProcesses.delete(child);
327
+ if (activeNativeOpenSshProcesses.size === 0) {
328
+ stopParentTerminationSignal?.();
329
+ stopParentTerminationSignal = undefined;
330
+ process.off("exit", forceStopNativeOpenSshProcesses);
331
+ processExitHookInstalled = false;
332
+ }
333
+ };
334
+ void child.once("exit", untrack);
335
+ void child.once("error", untrack);
336
+ return child;
337
+ }
338
+ function forceStopNativeOpenSshProcesses() {
339
+ for (const child of activeNativeOpenSshProcesses) {
340
+ try {
341
+ if (parentBoundNativeOpenSshProcesses.has(child))
342
+ child.stdin?.end();
343
+ else
344
+ child.kill("SIGKILL");
345
+ }
346
+ catch {
347
+ // The child may have exited between the tracked-state check and kill.
348
+ }
349
+ }
350
+ }
351
+ async function availableLoopbackPort() {
352
+ const server = createServer();
353
+ await new Promise((resolve, reject) => {
354
+ server.once("error", reject);
355
+ server.listen(0, SOCKS_HOST, resolve);
356
+ });
357
+ const address = server.address();
358
+ if (!address || typeof address === "string") {
359
+ server.close();
360
+ throw new Error("Failed to allocate a loopback SOCKS5 port");
361
+ }
362
+ await new Promise((resolve) => server.close(() => resolve()));
363
+ return address.port;
364
+ }
365
+ function canConnectLoopback(port) {
366
+ return new Promise((resolve) => {
367
+ const socket = createConnection({ host: SOCKS_HOST, port });
368
+ let settled = false;
369
+ const finish = (connected) => {
370
+ if (settled)
371
+ return;
372
+ settled = true;
373
+ socket.destroy();
374
+ resolve(connected);
375
+ };
376
+ socket.unref();
377
+ socket.setTimeout(100, () => finish(false));
378
+ socket.once("error", () => finish(false));
379
+ socket.once("connect", () => finish(true));
380
+ });
381
+ }
382
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3NzaF9vcGVuc3NoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL19zc2hfb3BlbnNzaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDMUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNqQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRWpDLE9BQU8sRUFBRSxVQUFVLElBQUksS0FBSyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDM0QsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXZDLE9BQU8sRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxPQUFPLENBQUM7QUFDcEMsT0FBTyxFQUNMLGtCQUFrQixHQUtuQixNQUFNLFdBQVcsQ0FBQztBQUVuQixNQUFNLFVBQVUsR0FBRyxXQUFXLENBQUM7QUFDL0IsTUFBTSx5QkFBeUIsR0FBRyxLQUFLLENBQUM7QUFDeEMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBQzdDLE1BQU0sNkJBQTZCLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7QUFDMUUsTUFBTSw0QkFBNEIsR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztBQUNuRSxNQUFNLGlDQUFpQyxHQUFHLElBQUksT0FBTyxFQUFzQixDQUFDO0FBQzVFLElBQUksMkJBQXFELENBQUM7QUFDMUQsSUFBSSx3QkFBd0IsR0FBRyxLQUFLLENBQUM7QUFDckMsMkZBQTJGO0FBQzNGLE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixH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c1wiO1xuaW1wb3J0IHsgY3JlYXRlQ29ubmVjdGlvbiwgY3JlYXRlU2VydmVyIH0gZnJvbSBcIm5vZGU6bmV0XCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB0eXBlIHsgRHVwbGV4IH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5pbXBvcnQgeyBzZXRUaW1lb3V0IGFzIGRlbGF5IH0gZnJvbSBcIm5vZGU6dGltZXJzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSBcIkBkYngtdG9vbHMvY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBDaGlsZFByb2Nlc3NSZXN1bHQgfSBmcm9tIFwiQGRieC10b29scy9jb3JlL2V4ZWNcIjtcbmltcG9ydCB7IGVycm9yVXRpbHMsIGxvZywgc3RyaW5nVXRpbHMgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgU29ja3NDbGllbnQgfSBmcm9tIFwic29ja3NcIjtcbmltcG9ydCB7XG4gIFBvb2xlZFNzaFRyYW5zcG9ydCxcbiAgdHlwZSBTc2hDb21tYW5kRXhlY3V0aW9uLFxuICB0eXBlIFNzaFBvb2xPcHRpb25zLFxuICB0eXBlIFNzaFJlc291cmNlTGlmZWN5Y2xlLFxuICB0eXBlIFNzaFRyYW5zcG9ydE9wdGlvbnMsXG59IGZyb20gXCIuL19zc2gudHNcIjtcblxuY29uc3QgU09DS1NfSE9TVCA9IFwiMTI3LjAuMC4xXCI7XG5jb25zdCBPUEVOU1NIX0hFTFBFUl9USU1FT1VUX01TID0gMl8wMDA7XG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwibGFrZWJveDpvcGVuc3NoXCIpO1xuY29uc3QgbmF0aXZlT3BlblNzaFN1cHBvcnRCeUNvbW1hbmQgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxib29sZWFuPj4oKTtcbmNvbnN0IGFjdGl2ZU5hdGl2ZU9wZW5Tc2hQcm9jZXNzZXMgPSBuZXcgU2V0PENoaWxkUHJvY2Vzc1Jlc3VsdD4oKTtcbmNvbnN0IHBhcmVudEJvdW5kTmF0aXZlT3BlblNzaFByb2Nlc3NlcyA9IG5ldyBXZWFrU2V0PENoaWxkUHJvY2Vzc1Jlc3VsdD4oKTtcbmxldCBzdG9wUGFyZW50VGVybWluYXRpb25TaWduYWw6ICgoKSA9PiB2b2lkKSB8IHVuZGVmaW5lZDtcbmxldCBwcm9jZXNzRXhpdEhvb2tJbnN0YWxsZWQgPSBmYWxzZTtcbi8qKiBAaW50ZXJuYWwgSmF2YVNjcmlwdCB3YXRjaGRvZyB0aGF0IHRlcm1pbmF0ZXMgb25lIGNoaWxkIHdoZW4gaXRzIHBhcmVudCBwaXBlIGNsb3Nlcy4gKi9cbmV4cG9ydCBjb25zdCBPUEVOU1NIX1BBUkVOVF9XQVRDSF9TT1VSQ0UgPVxuICBzdHJpbmdVdGlscy5kZWRlbnQoLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvKmpzKi8gYFxuICAgIGNvbnN0IHsgc3Bhd24gfSA9IHJlcXVpcmUoXCJub2RlOmNoaWxkX3Byb2Nlc3NcIik7XG5cbiAgICBjb25zdCBjaGlsZCA9IHNwYXduKHByb2Nlc3MuYXJndlsxXSwgcHJvY2Vzcy5hcmd2LnNsaWNlKDIpLCB7XG4gICAgICBzdGRpbzogW1wiaWdub3JlXCIsIFwiaWdub3JlXCIsIFwiaW5oZXJpdFwiXSxcbiAgICB9KTtcbiAgICBsZXQgc3RvcHBpbmcgPSBmYWxzZTtcbiAgICBjb25zdCBzdG9wQ2hpbGQgPSAoKSA9PiB7XG4gICAgICBpZiAoc3RvcHBpbmcpIHJldHVybjtcbiAgICAgIHN0b3BwaW5nID0gdHJ1ZTtcbiAgICAgIGNoaWxkLmtpbGwoXCJTSUdLSUxMXCIpO1xuICAgIH07XG5cbiAgICBwcm9jZXNzLnN0ZGluLnJlc3VtZSgpO1xuICAgIHByb2Nlc3Muc3RkaW4ub25jZShcImVuZFwiLCBzdG9wQ2hpbGQpO1xuICAgIHByb2Nlc3Muc3RkaW4ub25jZShcImNsb3NlXCIsIHN0b3BDaGlsZCk7XG4gICAgY2hpbGQub25jZShcImVycm9yXCIsIChlcnJvcikgPT4ge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfSk7XG4gICAgY2hpbGQub25jZShcImV4aXRcIiwgKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgcHJvY2Vzcy5zdGRpbi5wYXVzZSgpO1xuICAgICAgcHJvY2Vzcy5leGl0KGNvZGUgPz8gKHNpZ25hbCA/IDEgOiAwKSk7XG4gICAgfSk7XG4gIGApO1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKiogT25lIGF1dGhlbnRpY2F0ZWQgbmF0aXZlIE9wZW5TU0ggQ29udHJvbE1hc3RlciByZXNvdXJjZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3BlblNzaFJlc291cmNlIHtcbiAgcnVuKHNjcmlwdDogc3RyaW5nLCBleGVjdXRpb246IFNzaENvbW1hbmRFeGVjdXRpb24pOiBQcm9taXNlPG51bWJlcj47XG4gIGNvbm5lY3QocmVtb3RlSG9zdDogc3RyaW5nLCByZW1vdGVQb3J0OiBudW1iZXIpOiBQcm9taXNlPER1cGxleD47XG4gIHRlc3QoKTogUHJvbWlzZTxib29sZWFuPjtcbiAgY2xvc2UoKTogUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqIEV4Y2x1c2l2ZSBuYXRpdmUgT3BlblNTSCBDb250cm9sTWFzdGVyIHBvb2wuICovXG5leHBvcnQgY2xhc3MgT3BlblNzaFRyYW5zcG9ydCBleHRlbmRzIFBvb2xlZFNzaFRyYW5zcG9ydDxPcGVuU3NoUmVzb3VyY2U+IHtcbiAgcmVhZG9ubHkga2luZCA9IFwib3BlbnNzaFwiIGFzIGNvbnN0O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIG9wdGlvbnM6IFNzaFRyYW5zcG9ydE9wdGlvbnMsXG4gICAgY29tbWFuZDogc3RyaW5nLFxuICAgIHBvb2xPcHRpb25zOiBTc2hQb29sT3B0aW9ucyA9IHt9LFxuICAgIGxpZmVjeWNsZTogU3NoUmVzb3VyY2VMaWZlY3ljbGU8T3BlblNzaFJlc291cmNlPiA9IG9wZW5Tc2hMaWZlY3ljbGUob3B0aW9ucywgY29tbWFuZCksXG4gICkge1xuICAgIHN1cGVyKGxpZmVjeWNsZSwge1xuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IG9wdGlvbnMuY29ubmVjdFRpbWVvdXRNcyxcbiAgICAgIC4uLnBvb2xPcHRpb25zLFxuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIHJ1bldpdGhSZXNvdXJjZShcbiAgICByZXNvdXJjZTogT3BlblNzaFJlc291cmNlLFxuICAgIHNjcmlwdDogc3RyaW5nLFxuICAgIGV4ZWN1dGlvbjogU3NoQ29tbWFuZEV4ZWN1dGlvbixcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICByZXR1cm4gcmVzb3VyY2UucnVuKHNjcmlwdCwgZXhlY3V0aW9uKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBjb25uZWN0V2l0aFJlc291cmNlKFxuICAgIHJlc291cmNlOiBPcGVuU3NoUmVzb3VyY2UsXG4gICAgcmVtb3RlSG9zdDogc3RyaW5nLFxuICAgIHJlbW90ZVBvcnQ6IG51bWJlcixcbiAgKTogUHJvbWlzZTxEdXBsZXg+IHtcbiAgICByZXR1cm4gcmVzb3VyY2UuY29ubmVjdChyZW1vdGVIb3N0LCByZW1vdGVQb3J0KTtcbiAgfVxufVxuXG4vKiogUmV0dXJuIHdoZXRoZXIgYW4gZXhlY3V0YWJsZSBpcyBPcGVuU1NIIGFuZCBhY2NlcHRzIGR5bmFtaWMgU09DS1M1IGZvcndhcmRpbmcuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3VwcG9ydHNOYXRpdmVPcGVuU3NoKGNvbW1hbmQgPSBcInNzaFwiKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IGNhY2hlZCA9IG5hdGl2ZU9wZW5Tc2hTdXBwb3J0QnlDb21tYW5kLmdldChjb21tYW5kKTtcbiAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcbiAgY29uc3QgcHJvYmUgPSBwcm9iZU5hdGl2ZU9wZW5Tc2goY29tbWFuZCk7XG4gIG5hdGl2ZU9wZW5Tc2hTdXBwb3J0QnlDb21tYW5kLnNldChjb21tYW5kLCBwcm9iZSk7XG4gIHJldHVybiBwcm9iZTtcbn1cblxuLyoqIEBpbnRlcm5hbCBPcGVuU1NIIGFyZ3VtZW50cyBzaGFyZWQgYnkgcG9vbGVkIENvbnRyb2xNYXN0ZXIgcHJvY2Vzc2VzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5hdGl2ZU9wZW5Tc2hBcmdzKG9wdGlvbnM6IFNzaFRyYW5zcG9ydE9wdGlvbnMpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBbXG4gICAgXCItaVwiLFxuICAgIG9wdGlvbnMucHJpdmF0ZUtleVBhdGgsXG4gICAgXCItcFwiLFxuICAgIFN0cmluZyhvcHRpb25zLnBvcnQpLFxuICAgIFwiLVRcIixcbiAgICBcIi1vXCIsXG4gICAgXCJCYXRjaE1vZGU9eWVzXCIsXG4gICAgXCItb1wiLFxuICAgIFwiSWRlbnRpdGllc09ubHk9eWVzXCIsXG4gICAgXCItb1wiLFxuICAgIFwiRm9yd2FyZEFnZW50PW5vXCIsXG4gICAgXCItb1wiLFxuICAgIFwiUHJlZmVycmVkQXV0aGVudGljYXRpb25zPXB1YmxpY2tleVwiLFxuICAgIFwiLW9cIixcbiAgICBcIlN0cmljdEhvc3RLZXlDaGVja2luZz15ZXNcIixcbiAgICBcIi1vXCIsXG4gICAgYFVzZXJLbm93bkhvc3RzRmlsZT0ke29wdGlvbnMua25vd25Ib3N0c1BhdGh9YCxcbiAgICBcIi1vXCIsXG4gICAgYEhvc3RLZXlBbGlhcz1bJHtvcHRpb25zLmhvc3R9XToke29wdGlvbnMucG9ydH1gLFxuICAgIFwiLW9cIixcbiAgICBcIkxvZ0xldmVsPUVSUk9SXCIsXG4gICAgXCItb1wiLFxuICAgIGBDb25uZWN0VGltZW91dD0ke01hdGgubWF4KDEsIE1hdGguY2VpbChvcHRpb25zLmNvbm5lY3RUaW1lb3V0TXMgLyAxXzAwMCkpfWAsXG4gICAgXCItb1wiLFxuICAgIFwiU2VydmVyQWxpdmVJbnRlcnZhbD0xNVwiLFxuICAgIFwiLW9cIixcbiAgICBcIlNlcnZlckFsaXZlQ291bnRNYXg9M1wiLFxuICBdO1xufVxuXG5mdW5jdGlvbiBvcGVuU3NoTGlmZWN5Y2xlKFxuICBvcHRpb25zOiBTc2hUcmFuc3BvcnRPcHRpb25zLFxuICBjb21tYW5kOiBzdHJpbmcsXG4pOiBTc2hSZXNvdXJjZUxpZmVjeWNsZTxPcGVuU3NoUmVzb3VyY2U+IHtcbiAgcmV0dXJuIHtcbiAgICBjcmVhdGU6ICgpID0+IE5hdGl2ZU9wZW5Tc2hSZXNvdXJjZS5jcmVhdGUob3B0aW9ucywgY29tbWFuZCksXG4gICAgZGVzdHJveTogKHJlc291cmNlKSA9PiByZXNvdXJjZS5jbG9zZSgpLFxuICAgIHRlc3Q6IChyZXNvdXJjZSkgPT4gcmVzb3VyY2UudGVzdCgpLFxuICB9O1xufVxuXG5jbGFzcyBOYXRpdmVPcGVuU3NoUmVzb3VyY2UgaW1wbGVtZW50cyBPcGVuU3NoUmVzb3VyY2Uge1xuICBwcml2YXRlIGFsaXZlID0gdHJ1ZTtcbiAgcHJpdmF0ZSBjbG9zaW5nPzogUHJvbWlzZTx2b2lkPjtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogU3NoVHJhbnNwb3J0T3B0aW9ucyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbW1hbmQ6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY29udHJvbFBhdGg6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNvY2tzUG9ydDogbnVtYmVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbWFzdGVyOiBDaGlsZFByb2Nlc3NSZXN1bHQsXG4gICkge1xuICAgIGNvbnN0IGNsb3NlZCA9ICgpID0+IHtcbiAgICAgIHRoaXMuYWxpdmUgPSBmYWxzZTtcbiAgICB9O1xuICAgIHZvaWQgbWFzdGVyLnRoZW4oY2xvc2VkLCBjbG9zZWQpO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGNyZWF0ZShcbiAgICBvcHRpb25zOiBTc2hUcmFuc3BvcnRPcHRpb25zLFxuICAgIGNvbW1hbmQ6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxOYXRpdmVPcGVuU3NoUmVzb3VyY2U+IHtcbiAgICBjb25zdCBkaXJlY3RvcnkgPSBhd2FpdCBta2R0ZW1wKGpvaW4odG1wZGlyKCksIFwiZGJ4LXRvb2xzLXNzaC1cIikpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250cm9sUGF0aCA9IGpvaW4oZGlyZWN0b3J5LCBcImNvbnRyb2xcIik7XG4gICAgICBjb25zdCBzb2Nrc1BvcnQgPSBhd2FpdCBhdmFpbGFibGVMb29wYmFja1BvcnQoKTtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGAke29wdGlvbnMudXNlcm5hbWV9QCR7b3B0aW9ucy5jb25uZWN0SG9zdH1gO1xuICAgICAgY29uc3QgbWFzdGVyID0gdHJhY2tOYXRpdmVPcGVuU3NoUHJvY2VzcyhcbiAgICAgICAgZXhlYy5zcGF3bihcbiAgICAgICAgICBwcm9jZXNzLmV4ZWNQYXRoLFxuICAgICAgICAgIFtcbiAgICAgICAgICAgIFwiLWVcIixcbiAgICAgICAgICAgIE9QRU5TU0hfUEFSRU5UX1dBVENIX1NPVVJDRSxcbiAgICAgICAgICAgIGNvbW1hbmQsXG4gICAgICAgICAgICAuLi5uYXRpdmVPcGVuU3NoQXJncyhvcHRpb25zKSxcbiAgICAgICAgICAgIFwiLU1cIixcbiAgICAgICAgICAgIFwiLU5cIixcbiAgICAgICAgICAgIFwiLVNcIixcbiAgICAgICAgICAgIGNvbnRyb2xQYXRoLFxuICAgICAgICAgICAgXCItb1wiLFxuICAgICAgICAgICAgXCJDb250cm9sUGVyc2lzdD1ub1wiLFxuICAgICAgICAgICAgXCItb1wiLFxuICAgICAgICAgICAgXCJFeGl0T25Gb3J3YXJkRmFpbHVyZT15ZXNcIixcbiAgICAgICAgICAgIFwiLURcIixcbiAgICAgICAgICAgIGAke1NPQ0tTX0hPU1R9OiR7c29ja3NQb3J0fWAsXG4gICAgICAgICAgICB0YXJnZXQsXG4gICAgICAgICAgXSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzdGRpbjogXCJwaXBlXCIsXG4gICAgICAgICAgICBzdGRvdXQ6IFwiaWdub3JlXCIsXG4gICAgICAgICAgICBzdGRlcnI6IFwiY2FwdHVyZVwiLFxuICAgICAgICAgICAgdHJpbTogZmFsc2UsXG4gICAgICAgICAgICBmb3J3YXJkVGVybWluYXRpb25TaWduYWxzOiBmYWxzZSxcbiAgICAgICAgICB9LFxuICAgICAgICApLFxuICAgICAgICB0cnVlLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlc291cmNlID0gbmV3IE5hdGl2ZU9wZW5Tc2hSZXNvdXJjZShcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgY29tbWFuZCxcbiAgICAgICAgZGlyZWN0b3J5LFxuICAgICAgICBjb250cm9sUGF0aCxcbiAgICAgICAgc29ja3NQb3J0LFxuICAgICAgICBtYXN0ZXIsXG4gICAgICApO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgcmVzb3VyY2Uud2FpdFVudGlsUmVhZHkoKTtcbiAgICAgICAgcmV0dXJuIHJlc291cmNlO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgYXdhaXQgcmVzb3VyY2UuY2xvc2UoKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGF3YWl0IHJtKGRpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcnVuKHNjcmlwdDogc3RyaW5nLCBleGVjdXRpb246IFNzaENvbW1hbmRFeGVjdXRpb24pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGNoaWxkID0gdHJhY2tOYXRpdmVPcGVuU3NoUHJvY2VzcyhcbiAgICAgIGV4ZWMuc3Bhd24oXG4gICAgICAgIHRoaXMuY29tbWFuZCxcbiAgICAgICAgW1xuICAgICAgICAgIC4uLm5hdGl2ZU9wZW5Tc2hBcmdzKHRoaXMub3B0aW9ucyksXG4gICAgICAgICAgXCItU1wiLFxuICAgICAgICAgIHRoaXMuY29udHJvbFBhdGgsXG4gICAgICAgICAgXCItb1wiLFxuICAgICAgICAgIFwiQ29udHJvbE1hc3Rlcj1ub1wiLFxuICAgICAgICAgIGAke3RoaXMub3B0aW9ucy51c2VybmFtZX1AJHt0aGlzLm9wdGlvbnMuY29ubmVjdEhvc3R9YCxcbiAgICAgICAgICBzY3JpcHQsXG4gICAgICAgIF0sXG4gICAgICAgIHtcbiAgICAgICAgICBzdGRpbjogXCJpZ25vcmVcIixcbiAgICAgICAgICBzdGRvdXQ6IFwicGlwZVwiLFxuICAgICAgICAgIHN0ZGVycjogXCJwaXBlXCIsXG4gICAgICAgICAgdHJpbTogZmFsc2UsXG4gICAgICAgICAgZm9yd2FyZFRlcm1pbmF0aW9uU2lnbmFsczogZmFsc2UsXG4gICAgICAgIH0sXG4gICAgICApLFxuICAgICk7XG4gICAgY2hpbGQuc3Rkb3V0Py5vbihcImRhdGFcIiwgZXhlY3V0aW9uLnN0ZG91dCk7XG4gICAgY2hpbGQuc3RkZXJyPy5vbihcImRhdGFcIiwgZXhlY3V0aW9uLnN0ZGVycik7XG4gICAgbGV0IHNodXRkb3duOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICAgIGV4ZWN1dGlvbi5zZXRDYW5jZWwoKCkgPT4ge1xuICAgICAgc2h1dGRvd24gPz89IGNoaWxkLnNodXRkb3duKHsgdGVybWluYXRlVGltZW91dDogMCwga2lsbFRpbWVvdXQ6IDFfMDAwIH0pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byBzdG9wIG5hdGl2ZSBTU0ggY29tbWFuZFwiLCB7IGVycm9yOiBlcnJvclV0aWxzLnRvRXJyb3IoZXJyb3IpIH0pO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gc2h1dGRvd247XG4gICAgfSk7XG4gICAgcmV0dXJuIChhd2FpdCBjaGlsZCkuZXhpdENvZGU7XG4gIH1cblxuICBhc3luYyBjb25uZWN0KHJlbW90ZUhvc3Q6IHN0cmluZywgcmVtb3RlUG9ydDogbnVtYmVyKTogUHJvbWlzZTxEdXBsZXg+IHtcbiAgICBjb25zdCBjb25uZWN0aW9uID0gYXdhaXQgU29ja3NDbGllbnQuY3JlYXRlQ29ubmVjdGlvbih7XG4gICAgICBjb21tYW5kOiBcImNvbm5lY3RcIixcbiAgICAgIGRlc3RpbmF0aW9uOiB7IGhvc3Q6IHJlbW90ZUhvc3QsIHBvcnQ6IHJlbW90ZVBvcnQgfSxcbiAgICAgIHByb3h5OiB7IGhvc3Q6IFNPQ0tTX0hPU1QsIHBvcnQ6IHRoaXMuc29ja3NQb3J0LCB0eXBlOiA1IH0sXG4gICAgICB0aW1lb3V0OiB0aGlzLm9wdGlvbnMuY29ubmVjdFRpbWVvdXRNcyxcbiAgICAgIHNldF90Y3Bfbm9kZWxheTogdHJ1ZSxcbiAgICB9KTtcbiAgICByZXR1cm4gY29ubmVjdGlvbi5zb2NrZXQ7XG4gIH1cblxuICBhc3luYyB0ZXN0KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghdGhpcy5hbGl2ZSB8fCB0aGlzLm1hc3Rlci5leGl0Q29kZSAhPT0gbnVsbCkgcmV0dXJuIGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gKGF3YWl0IHRoaXMuY29udHJvbChcImNoZWNrXCIpKS5leGl0Q29kZSA9PT0gMDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jbG9zaW5nKSByZXR1cm4gdGhpcy5jbG9zaW5nO1xuICAgIHRoaXMuYWxpdmUgPSBmYWxzZTtcbiAgICB0aGlzLmNsb3NpbmcgPSB0aGlzLmNsb3NlUmVzb3VyY2UoKTtcbiAgICByZXR1cm4gdGhpcy5jbG9zaW5nO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjbG9zZVJlc291cmNlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbnRyb2woXCJleGl0XCIpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHRoaXMubWFzdGVyLnNodXRkb3duKHsgdGVybWluYXRlVGltZW91dDogMCwga2lsbFRpbWVvdXQ6IDFfMDAwIH0pLmNhdGNoKChlcnJvcikgPT5cbiAgICAgICAgbG9nZ2VyLndhcm4oXCJmYWlsZWQgdG8gc3RvcCBuYXRpdmUgU1NIIENvbnRyb2xNYXN0ZXJcIiwge1xuICAgICAgICAgIGVycm9yOiBlcnJvclV0aWxzLnRvRXJyb3IoZXJyb3IpLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgICBhd2FpdCBybSh0aGlzLmRpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd2FpdFVudGlsUmVhZHkoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgdGhpcy5vcHRpb25zLmNvbm5lY3RUaW1lb3V0TXM7XG4gICAgd2hpbGUgKERhdGUubm93KCkgPCBkZWFkbGluZSkge1xuICAgICAgaWYgKHRoaXMubWFzdGVyLmV4aXRDb2RlICE9PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMubWFzdGVyO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYE5hdGl2ZSBPcGVuU1NIIENvbnRyb2xNYXN0ZXIgZXhpdGVkICgke3Jlc3VsdC5leGl0Q29kZX0pOiAke3Jlc3VsdC5zdGRlcnIudHJpbSgpfWAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAoKGF3YWl0IHRoaXMudGVzdCgpKSAmJiAoYXdhaXQgY2FuQ29ubmVjdExvb3BiYWNrKHRoaXMuc29ja3NQb3J0KSkpIHJldHVybjtcbiAgICAgIGF3YWl0IGRlbGF5KDUwKTtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYE5hdGl2ZSBPcGVuU1NIIENvbnRyb2xNYXN0ZXIgZGlkIG5vdCBiZWNvbWUgcmVhZHkgd2l0aGluICR7dGhpcy5vcHRpb25zLmNvbm5lY3RUaW1lb3V0TXN9bXNgLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGNvbnRyb2wob3BlcmF0aW9uOiBcImNoZWNrXCIgfCBcImV4aXRcIikge1xuICAgIGNvbnN0IGNoaWxkID0gdHJhY2tOYXRpdmVPcGVuU3NoUHJvY2VzcyhcbiAgICAgIGV4ZWMuc3Bhd24oXG4gICAgICAgIHRoaXMuY29tbWFuZCxcbiAgICAgICAgW1xuICAgICAgICAgIFwiLXBcIixcbiAgICAgICAgICBTdHJpbmcodGhpcy5vcHRpb25zLnBvcnQpLFxuICAgICAgICAgIFwiLVNcIixcbiAgICAgICAgICB0aGlzLmNvbnRyb2xQYXRoLFxuICAgICAgICAgIFwiLU9cIixcbiAgICAgICAgICBvcGVyYXRpb24sXG4gICAgICAgICAgYCR7dGhpcy5vcHRpb25zLnVzZXJuYW1lfUAke3RoaXMub3B0aW9ucy5jb25uZWN0SG9zdH1gLFxuICAgICAgICBdLFxuICAgICAgICB7XG4gICAgICAgICAgc3RkaW46IFwiaWdub3JlXCIsXG4gICAgICAgICAgc3Rkb3V0OiBcImlnbm9yZVwiLFxuICAgICAgICAgIHN0ZGVycjogXCJpZ25vcmVcIixcbiAgICAgICAgICBmb3J3YXJkVGVybWluYXRpb25TaWduYWxzOiBmYWxzZSxcbiAgICAgICAgfSxcbiAgICAgICksXG4gICAgKTtcbiAgICByZXR1cm4gd2FpdEZvck5hdGl2ZU9wZW5Tc2hDaGlsZChjaGlsZCwgYHNzaCAtTyAke29wZXJhdGlvbn1gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBwcm9iZU5hdGl2ZU9wZW5Tc2goY29tbWFuZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgdmVyc2lvbiA9IGF3YWl0IHdhaXRGb3JOYXRpdmVPcGVuU3NoQ2hpbGQoXG4gICAgICB0cmFja05hdGl2ZU9wZW5Tc2hQcm9jZXNzKFxuICAgICAgICBleGVjLnNwYXduKGNvbW1hbmQsIFtcIi1WXCJdLCB7XG4gICAgICAgICAgc3RkaW46IFwiaWdub3JlXCIsXG4gICAgICAgICAgc3Rkb3V0OiBcImNhcHR1cmVcIixcbiAgICAgICAgICBzdGRlcnI6IFwiY2FwdHVyZVwiLFxuICAgICAgICAgIGZvcndhcmRUZXJtaW5hdGlvblNpZ25hbHM6IGZhbHNlLFxuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgICBcInNzaCAtVlwiLFxuICAgICk7XG4gICAgY29uc3QgdmVyc2lvbk91dHB1dCA9IGAke3ZlcnNpb24uc3Rkb3V0fVxcbiR7dmVyc2lvbi5zdGRlcnJ9YDtcbiAgICBpZiAodmVyc2lvbi5leGl0Q29kZSAhPT0gMCB8fCAhLyg/Ol58XFxzKU9wZW5TU0hfL20udGVzdCh2ZXJzaW9uT3V0cHV0KSkgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IGR5bmFtaWNGb3J3YXJkID0gYXdhaXQgd2FpdEZvck5hdGl2ZU9wZW5Tc2hDaGlsZChcbiAgICAgIHRyYWNrTmF0aXZlT3BlblNzaFByb2Nlc3MoXG4gICAgICAgIGV4ZWMuc3Bhd24oY29tbWFuZCwgW1wiLUdcIiwgXCItRFwiLCBgJHtTT0NLU19IT1NUfToxYCwgXCJsb2NhbGhvc3RcIl0sIHtcbiAgICAgICAgICBzdGRpbjogXCJpZ25vcmVcIixcbiAgICAgICAgICBzdGRvdXQ6IFwiaWdub3JlXCIsXG4gICAgICAgICAgc3RkZXJyOiBcImlnbm9yZVwiLFxuICAgICAgICAgIGZvcndhcmRUZXJtaW5hdGlvblNpZ25hbHM6IGZhbHNlLFxuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgICBcInNzaCAtR1wiLFxuICAgICk7XG4gICAgcmV0dXJuIGR5bmFtaWNGb3J3YXJkLmV4aXRDb2RlID09PSAwO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvck5hdGl2ZU9wZW5Tc2hDaGlsZChcbiAgY2hpbGQ6IENoaWxkUHJvY2Vzc1Jlc3VsdCxcbiAgb3BlcmF0aW9uOiBzdHJpbmcsXG4pOiBQcm9taXNlPEF3YWl0ZWQ8Q2hpbGRQcm9jZXNzUmVzdWx0Pj4ge1xuICBsZXQgdGltZW91dDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gIGNvbnN0IHRpbWVkT3V0ID0gbmV3IFByb21pc2U8bmV2ZXI+KChfcmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdm9pZCBjaGlsZC5zaHV0ZG93bih7IHRlcm1pbmF0ZVRpbWVvdXQ6IDAsIGtpbGxUaW1lb3V0OiAxXzAwMCB9KS50aGVuKFxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEVycm9yKGAke29wZXJhdGlvbn0gdGltZWQgb3V0IGFmdGVyICR7T1BFTlNTSF9IRUxQRVJfVElNRU9VVF9NU31tc2ApKSxcbiAgICAgICAgKGVycm9yKSA9PiByZWplY3QoZXJyb3IpLFxuICAgICAgKTtcbiAgICB9LCBPUEVOU1NIX0hFTFBFUl9USU1FT1VUX01TKTtcbiAgICB0aW1lb3V0LnVucmVmPy4oKTtcbiAgfSk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IFByb21pc2UucmFjZShbY2hpbGQsIHRpbWVkT3V0XSk7XG4gIH0gZmluYWxseSB7XG4gICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQhKTtcbiAgfVxufVxuXG5mdW5jdGlvbiB0cmFja05hdGl2ZU9wZW5Tc2hQcm9jZXNzKFxuICBjaGlsZDogQ2hpbGRQcm9jZXNzUmVzdWx0LFxuICBwYXJlbnRCb3VuZCA9IGZhbHNlLFxuKTogQ2hpbGRQcm9jZXNzUmVzdWx0IHtcbiAgYWN0aXZlTmF0aXZlT3BlblNzaFByb2Nlc3Nlcy5hZGQoY2hpbGQpO1xuICBpZiAocGFyZW50Qm91bmQpIHBhcmVudEJvdW5kTmF0aXZlT3BlblNzaFByb2Nlc3Nlcy5hZGQoY2hpbGQpO1xuICBpZiAoIXN0b3BQYXJlbnRUZXJtaW5hdGlvblNpZ25hbCkge1xuICAgIHN0b3BQYXJlbnRUZXJtaW5hdGlvblNpZ25hbCA9IGV4ZWMub25QYXJlbnRUZXJtaW5hdGlvblNpZ25hbChmb3JjZVN0b3BOYXRpdmVPcGVuU3NoUHJvY2Vzc2VzKTtcbiAgfVxuICBpZiAoIXByb2Nlc3NFeGl0SG9va0luc3RhbGxlZCkge1xuICAgIHByb2Nlc3NFeGl0SG9va0luc3RhbGxlZCA9IHRydWU7XG4gICAgcHJvY2Vzcy5vbmNlKFwiZXhpdFwiLCBmb3JjZVN0b3BOYXRpdmVPcGVuU3NoUHJvY2Vzc2VzKTtcbiAgfVxuICBsZXQgdHJhY2tlZCA9IHRydWU7XG4gIGNvbnN0IHVudHJhY2sgPSAoKSA9PiB7XG4gICAgaWYgKCF0cmFja2VkKSByZXR1cm47XG4gICAgdHJhY2tlZCA9IGZhbHNlO1xuICAgIHZvaWQgY2hpbGQub2ZmKFwiZXhpdFwiLCB1bnRyYWNrKTtcbiAgICB2b2lkIGNoaWxkLm9mZihcImVycm9yXCIsIHVudHJhY2spO1xuICAgIGFjdGl2ZU5hdGl2ZU9wZW5Tc2hQcm9jZXNzZXMuZGVsZXRlKGNoaWxkKTtcbiAgICBpZiAoYWN0aXZlTmF0aXZlT3BlblNzaFByb2Nlc3Nlcy5zaXplID09PSAwKSB7XG4gICAgICBzdG9wUGFyZW50VGVybWluYXRpb25TaWduYWw/LigpO1xuICAgICAgc3RvcFBhcmVudFRlcm1pbmF0aW9uU2lnbmFsID0gdW5kZWZpbmVkO1xuICAgICAgcHJvY2Vzcy5vZmYoXCJleGl0XCIsIGZvcmNlU3RvcE5hdGl2ZU9wZW5Tc2hQcm9jZXNzZXMpO1xuICAgICAgcHJvY2Vzc0V4aXRIb29rSW5zdGFsbGVkID0gZmFsc2U7XG4gICAgfVxuICB9O1xuICB2b2lkIGNoaWxkLm9uY2UoXCJleGl0XCIsIHVudHJhY2spO1xuICB2b2lkIGNoaWxkLm9uY2UoXCJlcnJvclwiLCB1bnRyYWNrKTtcbiAgcmV0dXJuIGNoaWxkO1xufVxuXG5mdW5jdGlvbiBmb3JjZVN0b3BOYXRpdmVPcGVuU3NoUHJvY2Vzc2VzKCk6IHZvaWQge1xuICBmb3IgKGNvbnN0IGNoaWxkIG9mIGFjdGl2ZU5hdGl2ZU9wZW5Tc2hQcm9jZXNzZXMpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKHBhcmVudEJvdW5kTmF0aXZlT3BlblNzaFByb2Nlc3Nlcy5oYXMoY2hpbGQpKSBjaGlsZC5zdGRpbj8uZW5kKCk7XG4gICAgICBlbHNlIGNoaWxkLmtpbGwoXCJTSUdLSUxMXCIpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gVGhlIGNoaWxkIG1heSBoYXZlIGV4aXRlZCBiZXR3ZWVuIHRoZSB0cmFja2VkLXN0YXRlIGNoZWNrIGFuZCBraWxsLlxuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBhdmFpbGFibGVMb29wYmFja1BvcnQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgY29uc3Qgc2VydmVyID0gY3JlYXRlU2VydmVyKCk7XG4gIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBzZXJ2ZXIub25jZShcImVycm9yXCIsIHJlamVjdCk7XG4gICAgc2VydmVyLmxpc3RlbigwLCBTT0NLU19IT1NULCByZXNvbHZlKTtcbiAgfSk7XG4gIGNvbnN0IGFkZHJlc3MgPSBzZXJ2ZXIuYWRkcmVzcygpO1xuICBpZiAoIWFkZHJlc3MgfHwgdHlwZW9mIGFkZHJlc3MgPT09IFwic3RyaW5nXCIpIHtcbiAgICBzZXJ2ZXIuY2xvc2UoKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJGYWlsZWQgdG8gYWxsb2NhdGUgYSBsb29wYmFjayBTT0NLUzUgcG9ydFwiKTtcbiAgfVxuICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gc2VydmVyLmNsb3NlKCgpID0+IHJlc29sdmUoKSkpO1xuICByZXR1cm4gYWRkcmVzcy5wb3J0O1xufVxuXG5mdW5jdGlvbiBjYW5Db25uZWN0TG9vcGJhY2socG9ydDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IHNvY2tldCA9IGNyZWF0ZUNvbm5lY3Rpb24oeyBob3N0OiBTT0NLU19IT1NULCBwb3J0IH0pO1xuICAgIGxldCBzZXR0bGVkID0gZmFsc2U7XG4gICAgY29uc3QgZmluaXNoID0gKGNvbm5lY3RlZDogYm9vbGVhbikgPT4ge1xuICAgICAgaWYgKHNldHRsZWQpIHJldHVybjtcbiAgICAgIHNldHRsZWQgPSB0cnVlO1xuICAgICAgc29ja2V0LmRlc3Ryb3koKTtcbiAgICAgIHJlc29sdmUoY29ubmVjdGVkKTtcbiAgICB9O1xuICAgIHNvY2tldC51bnJlZigpO1xuICAgIHNvY2tldC5zZXRUaW1lb3V0KDEwMCwgKCkgPT4gZmluaXNoKGZhbHNlKSk7XG4gICAgc29ja2V0Lm9uY2UoXCJlcnJvclwiLCAoKSA9PiBmaW5pc2goZmFsc2UpKTtcbiAgICBzb2NrZXQub25jZShcImNvbm5lY3RcIiwgKCkgPT4gZmluaXNoKHRydWUpKTtcbiAgfSk7XG59XG4iXX0=
@@ -0,0 +1,16 @@
1
+ import type { Duplex } from "node:stream";
2
+ import type { Client as Ssh2Client } from "ssh2";
3
+ import { PooledSshTransport, type SshCommandExecution, type SshPoolOptions, type SshTransportOptions } from "./_ssh.ts";
4
+ interface Ssh2Resource {
5
+ readonly client: Ssh2Client;
6
+ alive: boolean;
7
+ }
8
+ /** Exclusive ssh2 connection pool for commands and direct TCP forwarding. */
9
+ export declare class Ssh2Transport extends PooledSshTransport<Ssh2Resource> {
10
+ readonly kind: "ssh2";
11
+ private readonly connectTimeoutMs;
12
+ constructor(options: SshTransportOptions, poolOptions?: SshPoolOptions);
13
+ protected runWithResource(resource: Ssh2Resource, script: string, execution: SshCommandExecution): Promise<number>;
14
+ protected connectWithResource(resource: Ssh2Resource, remoteHost: string, remotePort: number): Promise<Duplex>;
15
+ }
16
+ export {};