bdy 1.11.0-dev → 1.12.0-dev
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/distTs/package.json +16 -5
- package/distTs/src/agent/agent.js +62 -36
- package/distTs/src/agent/linux.js +9 -4
- package/distTs/src/agent/manager.js +61 -42
- package/distTs/src/agent/osx.js +12 -5
- package/distTs/src/agent/socket/client.js +26 -7
- package/distTs/src/agent/socket/tunnel.js +56 -32
- package/distTs/src/agent/socket.js +83 -63
- package/distTs/src/agent/system.js +3 -1
- package/distTs/src/agent/windows.js +6 -6
- package/distTs/src/command/agent/install.js +4 -4
- package/distTs/src/command/agent/run.js +2 -2
- package/distTs/src/command/agent/status.js +6 -7
- package/distTs/src/command/agent/tunnel/http.js +4 -5
- package/distTs/src/command/agent/tunnel/tcp.js +3 -3
- package/distTs/src/command/agent/tunnel/tls.js +3 -3
- package/distTs/src/command/config/add/http.js +3 -3
- package/distTs/src/command/config/add/tcp.js +3 -3
- package/distTs/src/command/config/add/tls.js +3 -3
- package/distTs/src/command/config/get/region.js +1 -1
- package/distTs/src/command/pre.js +1 -1
- package/distTs/src/command/tunnel/http.js +2 -1
- package/distTs/src/command/tunnel/tcp.js +3 -3
- package/distTs/src/command/tunnel/tls.js +4 -4
- package/distTs/src/format.js +14 -15
- package/distTs/src/index.js +1 -1
- package/distTs/src/input.js +13 -12
- package/distTs/src/logger.js +12 -13
- package/distTs/src/tunnel/agent.js +3 -1
- package/distTs/src/tunnel/api/agent.js +1 -0
- package/distTs/src/tunnel/api/buddy.js +2 -0
- package/distTs/src/tunnel/cfg.js +6 -2
- package/distTs/src/tunnel/compression.js +17 -14
- package/distTs/src/tunnel/dns.js +20 -29
- package/distTs/src/tunnel/html.js +2 -0
- package/distTs/src/tunnel/http/log.js +30 -8
- package/distTs/src/tunnel/http/serve.js +3 -2
- package/distTs/src/tunnel/http/stream.js +5 -1
- package/distTs/src/tunnel/http.js +67 -26
- package/distTs/src/tunnel/identification.js +21 -14
- package/distTs/src/tunnel/latency.js +19 -11
- package/distTs/src/tunnel/output/interactive/tunnel.js +16 -9
- package/distTs/src/tunnel/output/noninteractive/agent/tunnels.js +4 -2
- package/distTs/src/tunnel/output/noninteractive/config/tunnel.js +6 -4
- package/distTs/src/tunnel/output/noninteractive/config/tunnels.js +2 -0
- package/distTs/src/tunnel/output/noninteractive/tunnel.js +13 -11
- package/distTs/src/tunnel/server/cert.js +2 -0
- package/distTs/src/tunnel/server/http1.js +15 -10
- package/distTs/src/tunnel/server/http2.js +18 -12
- package/distTs/src/tunnel/server/sftp.js +32 -15
- package/distTs/src/tunnel/server/ssh.js +49 -31
- package/distTs/src/tunnel/server/tls.js +11 -5
- package/distTs/src/tunnel/ssh/client.js +45 -31
- package/distTs/src/tunnel/tcp.js +61 -42
- package/distTs/src/tunnel/tunnel.js +196 -112
- package/distTs/src/types/tunnel.js +135 -0
- package/distTs/src/utils.js +2 -87
- package/package.json +16 -5
|
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const utils_1 = require("../../../utils");
|
|
7
6
|
const format_1 = __importDefault(require("../../../format"));
|
|
7
|
+
const tunnel_1 = require("../../../types/tunnel");
|
|
8
8
|
class OutputNoninteractiveTunnel {
|
|
9
|
+
tunnel;
|
|
10
|
+
terminal;
|
|
9
11
|
constructor(terminal, tunnel) {
|
|
10
12
|
this.tunnel = tunnel;
|
|
11
13
|
this.terminal = terminal;
|
|
@@ -44,16 +46,16 @@ class OutputNoninteractiveTunnel {
|
|
|
44
46
|
process.exit();
|
|
45
47
|
}
|
|
46
48
|
start() {
|
|
47
|
-
this.tunnel.on(
|
|
48
|
-
this.tunnel.on(
|
|
49
|
-
this.tunnel.on(
|
|
50
|
-
this.tunnel.on(
|
|
51
|
-
this.tunnel.on(
|
|
52
|
-
this.tunnel.on(
|
|
53
|
-
this.tunnel.on(
|
|
54
|
-
this.tunnel.on(
|
|
55
|
-
this.tunnel.on(
|
|
56
|
-
this.tunnel.on(
|
|
49
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.OPEN, (t) => this.onOpen(t));
|
|
50
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.CLOSED, (t) => this.onClosed(t));
|
|
51
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.TCP_OPEN, (t) => this.onTcpOpen(t));
|
|
52
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.TCP_CLOSED, (t) => this.onTcpClosed(t));
|
|
53
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.TLS_OPEN, (t) => this.onTlsOpen(t));
|
|
54
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.TLS_CLOSED, (t) => this.onTlsClosed(t));
|
|
55
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.HTTP_IDENTIFIED, (t, type) => this.onHttpIdentified(t, type));
|
|
56
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.HTTP_REQUEST, (t, logRequest) => this.onHttpRequest(t, logRequest));
|
|
57
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.HTTP_RESPONSE, (t, logRequest) => this.onHttpResponse(t, logRequest));
|
|
58
|
+
this.tunnel.on(tunnel_1.TUNNEL_EVENT.STOPPED, () => this.onStopped());
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
exports.default = OutputNoninteractiveTunnel;
|
|
@@ -13,6 +13,8 @@ const toPositiveHex = (hexString) => {
|
|
|
13
13
|
return hexAsInt.toString() + hexString.substring(1);
|
|
14
14
|
};
|
|
15
15
|
class ServerCert {
|
|
16
|
+
key;
|
|
17
|
+
cert;
|
|
16
18
|
constructor() {
|
|
17
19
|
const keyPair = node_forge_1.default.pki.rsa.generateKeyPair(2048);
|
|
18
20
|
const cert = node_forge_1.default.pki.createCertificate();
|
|
@@ -8,32 +8,36 @@ const logger_1 = __importDefault(require("../../logger"));
|
|
|
8
8
|
const uuid_1 = require("uuid");
|
|
9
9
|
const http_1 = __importDefault(require("http"));
|
|
10
10
|
const texts_1 = require("../../texts");
|
|
11
|
-
const
|
|
11
|
+
const tunnel_1 = require("../../types/tunnel");
|
|
12
12
|
class ServerHttp1 extends events_1.default {
|
|
13
|
+
server;
|
|
13
14
|
constructor(host) {
|
|
14
15
|
super();
|
|
15
16
|
this.server = http_1.default.createServer((req, res) => this.processRequest(req, res, host));
|
|
16
17
|
this.server.on('connection', (socket) => {
|
|
17
18
|
socket.id = (0, uuid_1.v4)();
|
|
18
|
-
this.emit(
|
|
19
|
+
this.emit(tunnel_1.TUNNEL_HTTP_SOCKET.OPEN, socket);
|
|
19
20
|
socket.once('close', () => {
|
|
20
|
-
this.emit(
|
|
21
|
+
this.emit(tunnel_1.TUNNEL_HTTP_SOCKET.CLOSED, socket);
|
|
21
22
|
});
|
|
22
23
|
});
|
|
23
24
|
this.server.listen();
|
|
24
25
|
}
|
|
25
26
|
stop() {
|
|
26
|
-
this.server
|
|
27
|
-
|
|
27
|
+
if (this.server) {
|
|
28
|
+
this.server.close();
|
|
29
|
+
this.server.removeAllListeners();
|
|
30
|
+
}
|
|
28
31
|
this.server = null;
|
|
29
32
|
}
|
|
30
|
-
handleSshTunnel(stream,
|
|
33
|
+
handleSshTunnel(stream, _, ip) {
|
|
31
34
|
logger_1.default.debug((0, texts_1.LOG_HTTP1_CONNECTION)(ip));
|
|
32
35
|
stream.remoteAddress = ip;
|
|
33
|
-
this.server
|
|
36
|
+
if (this.server)
|
|
37
|
+
this.server.emit('connection', stream);
|
|
34
38
|
}
|
|
35
39
|
retryRequest(logRequest) {
|
|
36
|
-
const address = this.server
|
|
40
|
+
const address = this.server?.address();
|
|
37
41
|
if (!address || !address.port)
|
|
38
42
|
return;
|
|
39
43
|
let req = http_1.default.request({
|
|
@@ -50,7 +54,8 @@ class ServerHttp1 extends events_1.default {
|
|
|
50
54
|
res.resume();
|
|
51
55
|
});
|
|
52
56
|
req.on('close', () => {
|
|
53
|
-
req
|
|
57
|
+
if (req)
|
|
58
|
+
req.removeAllListeners();
|
|
54
59
|
req = null;
|
|
55
60
|
});
|
|
56
61
|
req.end();
|
|
@@ -69,7 +74,7 @@ class ServerHttp1 extends events_1.default {
|
|
|
69
74
|
if (!this.checkHostHeader(req, res, host))
|
|
70
75
|
return;
|
|
71
76
|
logger_1.default.debug((0, texts_1.LOG_HTTP1_REQUEST)(req.method, req.url));
|
|
72
|
-
this.emit(
|
|
77
|
+
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_REQUEST, req, res);
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
exports.default = ServerHttp1;
|
|
@@ -8,51 +8,57 @@ const http2_1 = __importDefault(require("http2"));
|
|
|
8
8
|
const logger_js_1 = __importDefault(require("../../logger.js"));
|
|
9
9
|
const uuid_1 = require("uuid");
|
|
10
10
|
const texts_1 = require("../../texts");
|
|
11
|
-
const
|
|
11
|
+
const tunnel_1 = require("../../types/tunnel");
|
|
12
12
|
class ServerHttp2 extends events_1.default {
|
|
13
|
+
server;
|
|
13
14
|
constructor(host) {
|
|
14
15
|
super();
|
|
15
16
|
this.server = http2_1.default.createServer((req, res) => this.processRequest(req, res, host));
|
|
16
17
|
this.server.on('session', (session) => {
|
|
17
18
|
session.id = (0, uuid_1.v4)();
|
|
18
|
-
this.emit(
|
|
19
|
+
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_SESSION_OPEN, session);
|
|
19
20
|
session.once('close', () => {
|
|
20
|
-
this.emit(
|
|
21
|
+
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_SESSION_CLOSED, session);
|
|
21
22
|
});
|
|
22
23
|
});
|
|
23
24
|
this.server.listen();
|
|
24
25
|
}
|
|
25
26
|
stop() {
|
|
26
|
-
this.server
|
|
27
|
-
|
|
27
|
+
if (this.server) {
|
|
28
|
+
this.server.close();
|
|
29
|
+
this.server.removeAllListeners();
|
|
30
|
+
}
|
|
28
31
|
this.server = null;
|
|
29
32
|
}
|
|
30
33
|
handleSshTunnel(stream, info, ip) {
|
|
31
34
|
logger_js_1.default.debug((0, texts_1.LOG_HTTP2_CONNECTION)(ip));
|
|
32
35
|
stream.remoteAddress = ip;
|
|
33
|
-
this.server
|
|
36
|
+
if (this.server)
|
|
37
|
+
this.server.emit('connection', stream);
|
|
34
38
|
}
|
|
35
39
|
retryRequest(logRequest) {
|
|
36
|
-
const address = this.server
|
|
40
|
+
const address = this.server?.address();
|
|
37
41
|
if (!address || !address.port)
|
|
38
42
|
return;
|
|
39
43
|
let client = http2_1.default.connect(`http://localhost:${address.port}`, {
|
|
40
44
|
maxSessionMemory: 100,
|
|
41
|
-
noDelay: true
|
|
42
45
|
});
|
|
43
46
|
let req = client.request(logRequest.headers);
|
|
44
47
|
if (logRequest.requestBody.data.length > 0)
|
|
45
48
|
req.write(logRequest.requestBody.data);
|
|
46
49
|
req.on('response', () => {
|
|
47
|
-
req
|
|
50
|
+
if (req)
|
|
51
|
+
req.resume();
|
|
48
52
|
});
|
|
49
53
|
req.on('error', (err) => {
|
|
50
54
|
logger_js_1.default.debug(texts_1.LOG_ERROR);
|
|
51
55
|
logger_js_1.default.debug(err);
|
|
52
56
|
});
|
|
53
57
|
req.on('close', () => {
|
|
54
|
-
req
|
|
55
|
-
|
|
58
|
+
if (req)
|
|
59
|
+
req.removeAllListeners();
|
|
60
|
+
if (client)
|
|
61
|
+
client.close();
|
|
56
62
|
req = null;
|
|
57
63
|
client = null;
|
|
58
64
|
});
|
|
@@ -72,7 +78,7 @@ class ServerHttp2 extends events_1.default {
|
|
|
72
78
|
if (!this.checkHostHeader(req, res, host))
|
|
73
79
|
return;
|
|
74
80
|
logger_js_1.default.debug((0, texts_1.LOG_HTTP2_REQUEST)(req.method, req.url));
|
|
75
|
-
this.emit(
|
|
81
|
+
this.emit(tunnel_1.TUNNEL_EVENT.HTTP_REQUEST, req, res);
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
exports.default = ServerHttp2;
|
|
@@ -6,10 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const logger_1 = __importDefault(require("../../logger"));
|
|
7
7
|
const ssh2_1 = __importDefault(require("ssh2"));
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
-
const path_1 =
|
|
9
|
+
const path_1 = require("path");
|
|
10
10
|
const node_os_1 = require("node:os");
|
|
11
11
|
const { flagsToString, STATUS_CODE } = ssh2_1.default.utils.sftp;
|
|
12
12
|
class ServerSftp {
|
|
13
|
+
openHandlers;
|
|
14
|
+
count;
|
|
15
|
+
sftp;
|
|
13
16
|
constructor(sftp) {
|
|
14
17
|
logger_1.default.debug('Creating sftp server');
|
|
15
18
|
this.openHandlers = new Map();
|
|
@@ -79,11 +82,7 @@ class ServerSftp {
|
|
|
79
82
|
}
|
|
80
83
|
const fd = this.openHandlers.get(id);
|
|
81
84
|
const buffer = Buffer.alloc(length);
|
|
82
|
-
const r = await fd.read(buffer,
|
|
83
|
-
offset: 0,
|
|
84
|
-
length,
|
|
85
|
-
position: offset,
|
|
86
|
-
});
|
|
85
|
+
const r = await fd.read(buffer, 0, length, offset);
|
|
87
86
|
if (r.bytesRead <= 0) {
|
|
88
87
|
this.sftp.status(reqId, STATUS_CODE.EOF);
|
|
89
88
|
}
|
|
@@ -142,6 +141,16 @@ class ServerSftp {
|
|
|
142
141
|
this.debugEnd('SFTP close handler failed', s, err);
|
|
143
142
|
}
|
|
144
143
|
}
|
|
144
|
+
stats2attributes(stat) {
|
|
145
|
+
return {
|
|
146
|
+
mode: stat.mode,
|
|
147
|
+
uid: stat.uid,
|
|
148
|
+
gid: stat.gid,
|
|
149
|
+
size: stat.size,
|
|
150
|
+
atime: stat.atime.getTime() / 1000,
|
|
151
|
+
mtime: stat.mtime.getTime() / 1000
|
|
152
|
+
};
|
|
153
|
+
}
|
|
145
154
|
async fstat(reqId, handle) {
|
|
146
155
|
const s = this.debugStart('SFTP want to stat file');
|
|
147
156
|
try {
|
|
@@ -153,7 +162,7 @@ class ServerSftp {
|
|
|
153
162
|
}
|
|
154
163
|
const fd = this.openHandlers.get(id);
|
|
155
164
|
const attrs = await fd.stat();
|
|
156
|
-
this.sftp.attrs(reqId, attrs);
|
|
165
|
+
this.sftp.attrs(reqId, this.stats2attributes(attrs));
|
|
157
166
|
this.debugEnd('SFTP stat file succeed', s);
|
|
158
167
|
}
|
|
159
168
|
catch (err) {
|
|
@@ -287,13 +296,13 @@ class ServerSftp {
|
|
|
287
296
|
}
|
|
288
297
|
else {
|
|
289
298
|
const name = dir.name;
|
|
290
|
-
const fullPath = path_1.
|
|
299
|
+
const fullPath = (0, path_1.join)(fd.path, name);
|
|
291
300
|
const stat = await promises_1.default.lstat(fullPath);
|
|
292
301
|
const longname = await this.longname(fullPath, name, stat);
|
|
293
302
|
names.push({
|
|
294
303
|
filename: name,
|
|
295
304
|
longname,
|
|
296
|
-
attrs: stat,
|
|
305
|
+
attrs: this.stats2attributes(stat),
|
|
297
306
|
});
|
|
298
307
|
r += 1;
|
|
299
308
|
}
|
|
@@ -310,7 +319,7 @@ class ServerSftp {
|
|
|
310
319
|
const s = this.debugStart(`SFTP want to stat ${path}`);
|
|
311
320
|
try {
|
|
312
321
|
const attrs = await promises_1.default.stat(path);
|
|
313
|
-
this.sftp.attrs(reqId, attrs);
|
|
322
|
+
this.sftp.attrs(reqId, this.stats2attributes(attrs));
|
|
314
323
|
this.debugEnd('SFTP stat path succeed', s);
|
|
315
324
|
}
|
|
316
325
|
catch (err) {
|
|
@@ -352,9 +361,14 @@ class ServerSftp {
|
|
|
352
361
|
p = p.replaceAll('~', (0, node_os_1.homedir)());
|
|
353
362
|
}
|
|
354
363
|
const realPath = await promises_1.default.realpath(p);
|
|
364
|
+
const name = (0, path_1.basename)(realPath);
|
|
365
|
+
const stat = await promises_1.default.lstat(realPath);
|
|
366
|
+
const longname = await this.longname(realPath, name, stat);
|
|
355
367
|
this.sftp.name(reqId, [
|
|
356
368
|
{
|
|
357
369
|
filename: realPath,
|
|
370
|
+
longname,
|
|
371
|
+
attrs: this.stats2attributes(stat)
|
|
358
372
|
},
|
|
359
373
|
]);
|
|
360
374
|
this.debugEnd('SFTP realpath succeed', s);
|
|
@@ -368,9 +382,14 @@ class ServerSftp {
|
|
|
368
382
|
const s = this.debugStart(`SFTP want readlink ${path}`);
|
|
369
383
|
try {
|
|
370
384
|
const realPath = await promises_1.default.readlink(path);
|
|
385
|
+
const name = (0, path_1.basename)(realPath);
|
|
386
|
+
const stats = await promises_1.default.lstat(realPath);
|
|
387
|
+
const longname = await this.longname(realPath, name, stats);
|
|
371
388
|
this.sftp.name(reqId, [
|
|
372
389
|
{
|
|
373
390
|
filename: realPath,
|
|
391
|
+
longname,
|
|
392
|
+
attrs: this.stats2attributes(stats)
|
|
374
393
|
},
|
|
375
394
|
]);
|
|
376
395
|
this.debugEnd('SFTP readlink succeed', s);
|
|
@@ -465,7 +484,7 @@ class ServerSftp {
|
|
|
465
484
|
const s = this.debugStart(`SFTP want to lstat ${path}`);
|
|
466
485
|
try {
|
|
467
486
|
const attrs = await promises_1.default.lstat(path);
|
|
468
|
-
this.sftp.attrs(reqId, attrs);
|
|
487
|
+
this.sftp.attrs(reqId, this.stats2attributes(attrs));
|
|
469
488
|
this.debugEnd('SFTP lstat path succeed', s);
|
|
470
489
|
}
|
|
471
490
|
catch (err) {
|
|
@@ -477,19 +496,17 @@ class ServerSftp {
|
|
|
477
496
|
if (this.sftp) {
|
|
478
497
|
this.sftp.removeAllListeners();
|
|
479
498
|
this.sftp.end();
|
|
480
|
-
this.sftp = null;
|
|
481
499
|
}
|
|
482
500
|
if (this.openHandlers) {
|
|
483
|
-
this.openHandlers.forEach((fd) => {
|
|
501
|
+
this.openHandlers.forEach((fd, id) => {
|
|
484
502
|
try {
|
|
485
503
|
fd.close();
|
|
486
504
|
}
|
|
487
505
|
catch {
|
|
488
506
|
// do nothing
|
|
489
507
|
}
|
|
490
|
-
|
|
508
|
+
this.openHandlers.delete(id);
|
|
491
509
|
});
|
|
492
|
-
this.openHandlers = null;
|
|
493
510
|
}
|
|
494
511
|
this.count = 0;
|
|
495
512
|
}
|
|
@@ -14,8 +14,12 @@ const buddy_1 = __importDefault(require("../api/buddy"));
|
|
|
14
14
|
const pipeStreamToChannel = (stream, channel) => {
|
|
15
15
|
channel.once('exit', (code, signal) => {
|
|
16
16
|
logger_1.default.debug(`shell channel exit: ${code}, signal: ${signal}`);
|
|
17
|
-
if (stream.exit)
|
|
18
|
-
|
|
17
|
+
if (stream.exit) {
|
|
18
|
+
if (signal)
|
|
19
|
+
stream.exit(signal);
|
|
20
|
+
else
|
|
21
|
+
stream.exit(code);
|
|
22
|
+
}
|
|
19
23
|
});
|
|
20
24
|
channel.on('close', () => {
|
|
21
25
|
stream.end();
|
|
@@ -24,13 +28,16 @@ const pipeStreamToChannel = (stream, channel) => {
|
|
|
24
28
|
channel.stderr.pipe(stream.stderr);
|
|
25
29
|
};
|
|
26
30
|
class ServerSsh extends events_1.default {
|
|
31
|
+
agent;
|
|
32
|
+
login;
|
|
33
|
+
password;
|
|
34
|
+
server;
|
|
27
35
|
constructor(agent, login, password, hostKey) {
|
|
28
36
|
super();
|
|
29
37
|
this.agent = agent;
|
|
30
38
|
this.login = login;
|
|
31
39
|
this.password = password;
|
|
32
40
|
this.server = new ssh2_1.default.Server({
|
|
33
|
-
keepAlive: true,
|
|
34
41
|
hostKeys: [hostKey],
|
|
35
42
|
highWaterMark: 16 * 1024 * 1024,
|
|
36
43
|
ident: 'ssh2 server',
|
|
@@ -38,29 +45,35 @@ class ServerSsh extends events_1.default {
|
|
|
38
45
|
this.server.listen();
|
|
39
46
|
}
|
|
40
47
|
stop() {
|
|
41
|
-
this.server
|
|
42
|
-
|
|
48
|
+
if (this.server) {
|
|
49
|
+
this.server.close();
|
|
50
|
+
this.server.removeAllListeners();
|
|
51
|
+
}
|
|
43
52
|
this.server = null;
|
|
44
53
|
}
|
|
45
54
|
handleSshTunnel(stream) {
|
|
46
|
-
this.server
|
|
55
|
+
if (this.server)
|
|
56
|
+
this.server.injectSocket(stream);
|
|
47
57
|
}
|
|
48
58
|
checkValueSafe(input, allowed) {
|
|
49
59
|
const autoReject = input.length !== allowed.length;
|
|
50
60
|
if (autoReject)
|
|
51
61
|
allowed = input;
|
|
52
62
|
const isMatch = (0, crypto_1.timingSafeEqual)(input, allowed);
|
|
53
|
-
return
|
|
63
|
+
return !autoReject && isMatch;
|
|
54
64
|
}
|
|
55
65
|
async verifyKey(ctx, keys) {
|
|
56
66
|
try {
|
|
57
67
|
for (let i = 0; i < keys.length; i += 1) {
|
|
58
68
|
const publicKey = ssh2_1.default.utils.parseKey(keys[i]);
|
|
69
|
+
if (publicKey instanceof Error)
|
|
70
|
+
continue;
|
|
59
71
|
if (ctx.key.algo !== publicKey.type)
|
|
60
72
|
continue;
|
|
61
73
|
if (!this.checkValueSafe(ctx.key.data, publicKey.getPublicSSH()))
|
|
62
74
|
continue;
|
|
63
|
-
if (ctx.signature &&
|
|
75
|
+
if (ctx.signature &&
|
|
76
|
+
!publicKey.verify(ctx.blob || '', ctx.signature, ctx.hashAlgo))
|
|
64
77
|
continue;
|
|
65
78
|
return true;
|
|
66
79
|
}
|
|
@@ -85,7 +98,7 @@ class ServerSsh extends events_1.default {
|
|
|
85
98
|
host: '127.0.0.1',
|
|
86
99
|
port: 22,
|
|
87
100
|
username: 'root',
|
|
88
|
-
privateKey: privateKey
|
|
101
|
+
privateKey: privateKey,
|
|
89
102
|
});
|
|
90
103
|
});
|
|
91
104
|
}
|
|
@@ -146,15 +159,15 @@ class ServerSsh extends events_1.default {
|
|
|
146
159
|
}
|
|
147
160
|
localExec(stream, command, env) {
|
|
148
161
|
const s = process.hrtime();
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
const opts = {};
|
|
163
|
+
if (env)
|
|
164
|
+
opts.env = env;
|
|
165
|
+
(0, child_process_1.exec)(command, opts, (err, stdout, stderr) => {
|
|
152
166
|
if (stream) {
|
|
153
167
|
stream.stderr.write(stderr);
|
|
154
168
|
stream.write(stdout);
|
|
155
169
|
stream.exit(!err ? 0 : 1);
|
|
156
170
|
stream.end();
|
|
157
|
-
stream = null;
|
|
158
171
|
}
|
|
159
172
|
const [seconds, nano] = process.hrtime(s);
|
|
160
173
|
const ms = seconds * 1000 + nano / 1000 / 1000;
|
|
@@ -173,7 +186,6 @@ class ServerSsh extends events_1.default {
|
|
|
173
186
|
pty = null;
|
|
174
187
|
x11 = null;
|
|
175
188
|
session.removeAllListeners();
|
|
176
|
-
session = null;
|
|
177
189
|
if (sftp) {
|
|
178
190
|
sftp.destroy();
|
|
179
191
|
sftp = null;
|
|
@@ -183,7 +195,6 @@ class ServerSsh extends events_1.default {
|
|
|
183
195
|
channel = null;
|
|
184
196
|
}
|
|
185
197
|
client.removeListener('close', closeSession);
|
|
186
|
-
client = null;
|
|
187
198
|
};
|
|
188
199
|
client.on('close', closeSession);
|
|
189
200
|
session.on('close', closeSession);
|
|
@@ -215,7 +226,7 @@ class ServerSsh extends events_1.default {
|
|
|
215
226
|
pty.rows = info.rows;
|
|
216
227
|
pty.width = info.width;
|
|
217
228
|
if (channel && channel.setWindow)
|
|
218
|
-
channel.setWindow(pty.rows, pty.cols, pty.height, pty.width);
|
|
229
|
+
channel.setWindow(pty.rows || 1, pty.cols || 1, pty.height || 1, pty.width || 1);
|
|
219
230
|
if (accept)
|
|
220
231
|
accept();
|
|
221
232
|
});
|
|
@@ -227,10 +238,12 @@ class ServerSsh extends events_1.default {
|
|
|
227
238
|
return;
|
|
228
239
|
}
|
|
229
240
|
const stream = accept();
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
241
|
+
const opts = {};
|
|
242
|
+
if (env)
|
|
243
|
+
opts.env = env;
|
|
244
|
+
if (x11)
|
|
245
|
+
opts.x11 = x11;
|
|
246
|
+
proxyClient.shell(pty || {}, opts, (err, c) => {
|
|
234
247
|
if (err || !c) {
|
|
235
248
|
if (reject)
|
|
236
249
|
reject();
|
|
@@ -296,11 +309,14 @@ class ServerSsh extends events_1.default {
|
|
|
296
309
|
this.localExec(stream, info.command, env);
|
|
297
310
|
return;
|
|
298
311
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
312
|
+
const opts = {};
|
|
313
|
+
if (env)
|
|
314
|
+
opts.env = env;
|
|
315
|
+
if (pty)
|
|
316
|
+
opts.pty = pty;
|
|
317
|
+
if (x11)
|
|
318
|
+
opts.x11 = x11;
|
|
319
|
+
proxyClient.exec(info.command, opts, (err, c) => {
|
|
304
320
|
if (err || !c) {
|
|
305
321
|
if (reject)
|
|
306
322
|
reject();
|
|
@@ -309,12 +325,14 @@ class ServerSsh extends events_1.default {
|
|
|
309
325
|
pipeStreamToChannel(stream, c);
|
|
310
326
|
});
|
|
311
327
|
});
|
|
312
|
-
session.on('env', (accept,
|
|
328
|
+
session.on('env', (accept, _, info) => {
|
|
313
329
|
logger_1.default.debug('ssh env');
|
|
314
330
|
logger_1.default.debug(info);
|
|
315
|
-
|
|
316
|
-
env
|
|
317
|
-
|
|
331
|
+
if (info.key) {
|
|
332
|
+
if (!env)
|
|
333
|
+
env = {};
|
|
334
|
+
env[info.key] = info.val;
|
|
335
|
+
}
|
|
318
336
|
if (accept)
|
|
319
337
|
accept();
|
|
320
338
|
});
|
|
@@ -377,7 +395,7 @@ class ServerSsh extends events_1.default {
|
|
|
377
395
|
let accepted = false;
|
|
378
396
|
const socket = node_net_1.default.connect({
|
|
379
397
|
host: destIP,
|
|
380
|
-
port: destPort
|
|
398
|
+
port: destPort,
|
|
381
399
|
});
|
|
382
400
|
socket.on('connect', () => {
|
|
383
401
|
accepted = true;
|
|
@@ -409,7 +427,7 @@ class ServerSsh extends events_1.default {
|
|
|
409
427
|
return;
|
|
410
428
|
}
|
|
411
429
|
if (name === 'tcpip-forward') {
|
|
412
|
-
|
|
430
|
+
const { bindAddr, bindPort } = info;
|
|
413
431
|
proxyClient.forwardIn(bindAddr, bindPort, (err, port) => {
|
|
414
432
|
if (err) {
|
|
415
433
|
reject();
|
|
@@ -6,8 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const events_1 = __importDefault(require("events"));
|
|
7
7
|
const tls_1 = __importDefault(require("tls"));
|
|
8
8
|
const cert_js_1 = __importDefault(require("./cert.js"));
|
|
9
|
-
const
|
|
9
|
+
const tunnel_1 = require("../../types/tunnel");
|
|
10
10
|
class ServerTls extends events_1.default {
|
|
11
|
+
key;
|
|
12
|
+
cert;
|
|
13
|
+
ca;
|
|
14
|
+
server;
|
|
11
15
|
constructor(key, cert, ca) {
|
|
12
16
|
super();
|
|
13
17
|
this.key = key;
|
|
@@ -22,19 +26,21 @@ class ServerTls extends events_1.default {
|
|
|
22
26
|
handshakeTimeout: 60000,
|
|
23
27
|
key: this.key,
|
|
24
28
|
cert: this.cert,
|
|
25
|
-
ca: this.ca,
|
|
29
|
+
ca: this.ca || undefined,
|
|
26
30
|
rejectUnauthorized: !!this.ca,
|
|
27
31
|
requestCert: !!this.ca,
|
|
28
32
|
}, (socket) => this.processSocket(socket));
|
|
29
33
|
}
|
|
30
34
|
async processSocket(socket) {
|
|
31
|
-
this.emit(
|
|
35
|
+
this.emit(tunnel_1.TUNNEL_EVENT.TLS_SOCKET, socket);
|
|
32
36
|
}
|
|
33
37
|
handleSshTunnel(channel) {
|
|
34
|
-
this.server
|
|
38
|
+
if (this.server)
|
|
39
|
+
this.server.emit('connection', channel);
|
|
35
40
|
}
|
|
36
41
|
stop() {
|
|
37
|
-
this.server
|
|
42
|
+
if (this.server)
|
|
43
|
+
this.server.removeAllListeners();
|
|
38
44
|
this.server = null;
|
|
39
45
|
}
|
|
40
46
|
}
|