@dbx-tools/lakebox 0.0.0-stage → 0.9.132
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/LICENSE +202 -0
- package/README.md +146 -2
- package/index.ts +18 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +15 -0
- package/lib/src/_ssh.d.ts +152 -0
- package/lib/src/_ssh.js +489 -0
- package/lib/src/_ssh_openssh.d.ts +18 -0
- package/lib/src/_ssh_openssh.js +382 -0
- package/lib/src/_ssh_ssh2.d.ts +16 -0
- package/lib/src/_ssh_ssh2.js +225 -0
- package/lib/src/key-store.d.ts +39 -0
- package/lib/src/key-store.js +145 -0
- package/lib/src/lifecycle.d.ts +18 -0
- package/lib/src/lifecycle.js +75 -0
- package/lib/src/rest.d.ts +81 -0
- package/lib/src/rest.js +199 -0
- package/lib/src/session.d.ts +89 -0
- package/lib/src/session.js +309 -0
- package/lib/src/transport.d.ts +15 -0
- package/lib/src/transport.js +16 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +117 -4
- package/src/_ssh.ts +610 -0
- package/src/_ssh_openssh.ts +471 -0
- package/src/_ssh_ssh2.ts +273 -0
- package/src/key-store.ts +177 -0
- package/src/lifecycle.ts +88 -0
- package/src/rest.ts +264 -0
- package/src/session.ts +371 -0
- package/src/transport.ts +25 -0
|
@@ -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 {};
|