@maiyunnet/kebab 2.0.0
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/.VSCodeCounter/2025-02-14_14-46-44/details.md +82 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff-details.md +15 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.csv +2 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.md +19 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.txt +22 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.csv +69 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.json +1 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.md +48 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/results.txt +118 -0
- package/.vscode/tasks.json +15 -0
- package/LICENSE +201 -0
- package/README.md +201 -0
- package/bin/kebab.js +2 -0
- package/eslint.config.js +22 -0
- package/index.js +19 -0
- package/index.ts +33 -0
- package/lib/buffer.js +108 -0
- package/lib/buffer.ts +152 -0
- package/lib/captcha/zcool-addict-italic.ttf +0 -0
- package/lib/captcha.js +71 -0
- package/lib/captcha.ts +63 -0
- package/lib/consistent.js +171 -0
- package/lib/consistent.ts +219 -0
- package/lib/core.js +663 -0
- package/lib/core.ts +880 -0
- package/lib/crypto.js +256 -0
- package/lib/crypto.ts +384 -0
- package/lib/db.js +521 -0
- package/lib/db.ts +719 -0
- package/lib/dns.js +321 -0
- package/lib/dns.ts +405 -0
- package/lib/fs.js +405 -0
- package/lib/fs.ts +527 -0
- package/lib/jwt.js +223 -0
- package/lib/jwt.ts +276 -0
- package/lib/kv.js +1004 -0
- package/lib/kv.ts +1489 -0
- package/lib/lan.js +99 -0
- package/lib/lan.ts +87 -0
- package/lib/net/cacert.pem +3480 -0
- package/lib/net/formdata.js +137 -0
- package/lib/net/formdata.ts +166 -0
- package/lib/net/request.js +102 -0
- package/lib/net/request.ts +150 -0
- package/lib/net/response.js +28 -0
- package/lib/net/response.ts +59 -0
- package/lib/net.js +462 -0
- package/lib/net.ts +662 -0
- package/lib/s3.js +180 -0
- package/lib/s3.ts +235 -0
- package/lib/scan.js +276 -0
- package/lib/scan.ts +364 -0
- package/lib/session.js +177 -0
- package/lib/session.ts +230 -0
- package/lib/sql.js +818 -0
- package/lib/sql.ts +1151 -0
- package/lib/ssh/sftp.js +373 -0
- package/lib/ssh/sftp.ts +508 -0
- package/lib/ssh/shell.js +109 -0
- package/lib/ssh/shell.ts +123 -0
- package/lib/ssh.js +171 -0
- package/lib/ssh.ts +191 -0
- package/lib/text/tld.json +1 -0
- package/lib/text.js +452 -0
- package/lib/text.ts +607 -0
- package/lib/time.js +216 -0
- package/lib/time.ts +254 -0
- package/lib/ws.js +373 -0
- package/lib/ws.ts +523 -0
- package/lib/zip.js +381 -0
- package/lib/zip.ts +447 -0
- package/lib/zlib.js +289 -0
- package/lib/zlib.ts +350 -0
- package/main.js +51 -0
- package/main.ts +27 -0
- package/package.json +37 -0
- package/sys/child.js +585 -0
- package/sys/child.ts +678 -0
- package/sys/cmd.js +226 -0
- package/sys/cmd.ts +225 -0
- package/sys/ctr.js +608 -0
- package/sys/ctr.ts +904 -0
- package/sys/master.js +314 -0
- package/sys/master.ts +355 -0
- package/sys/mod.js +1273 -0
- package/sys/mod.ts +1871 -0
- package/sys/route.js +922 -0
- package/sys/route.ts +1113 -0
- package/types/index.d.ts +283 -0
- package/www/example/ctr/main.js +42 -0
- package/www/example/ctr/main.ts +9 -0
- package/www/example/ctr/middle.js +57 -0
- package/www/example/ctr/middle.ts +26 -0
- package/www/example/ctr/test.js +2818 -0
- package/www/example/ctr/test.ts +3218 -0
- package/www/example/data/locale/en.test.json +8 -0
- package/www/example/data/locale/index.html +1 -0
- package/www/example/data/locale/ja.test.json +8 -0
- package/www/example/data/locale/sc.test.json +8 -0
- package/www/example/data/locale/tc.test.json +8 -0
- package/www/example/data/test.zip +0 -0
- package/www/example/kebab.json +24 -0
- package/www/example/mod/test.js +49 -0
- package/www/example/mod/test.ts +47 -0
- package/www/example/mod/testdata.js +11 -0
- package/www/example/mod/testdata.ts +30 -0
- package/www/example/route.json +6 -0
- package/www/example/view/test.ejs +11 -0
- package/www/example/ws/mproxy.js +49 -0
- package/www/example/ws/mproxy.ts +16 -0
- package/www/example/ws/rproxy.js +47 -0
- package/www/example/ws/rproxy.ts +14 -0
- package/www/example/ws/test.js +68 -0
- package/www/example/ws/test.ts +36 -0
package/lib/ssh/shell.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* Date: 2019-6-8 22:13
|
|
4
|
+
* Last: 2020-4-10 16:08:32, 2022-12-30 00:03:40, 2023-4-22 21:06:57
|
|
5
|
+
*/
|
|
6
|
+
import * as ssh2 from 'ssh2';
|
|
7
|
+
import * as lCore from '~/lib/core';
|
|
8
|
+
|
|
9
|
+
export class Connection {
|
|
10
|
+
|
|
11
|
+
/** --- 连接对象 --- */
|
|
12
|
+
private readonly _client: ssh2.ClientChannel;
|
|
13
|
+
|
|
14
|
+
public constructor(stream: ssh2.ClientChannel) {
|
|
15
|
+
this._client = stream;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* --- 发送指令 ---
|
|
20
|
+
* @param cmd 指令
|
|
21
|
+
* @param encoding 编码
|
|
22
|
+
*/
|
|
23
|
+
public send(cmd: string | Buffer, encoding?: BufferEncoding): Promise<boolean> {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const cb = (e: any): void => {
|
|
26
|
+
if (e) {
|
|
27
|
+
resolve(false);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
resolve(true);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (encoding) {
|
|
34
|
+
this._client.write(cmd, encoding, cb);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this._client.write(cmd, cb);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* --- 发送带换行的内容(发送并执行) ---
|
|
44
|
+
* @param cmd 指令
|
|
45
|
+
* @param encoding 编码
|
|
46
|
+
*/
|
|
47
|
+
public async sendLine(cmd: string, encoding?: BufferEncoding): Promise<boolean> {
|
|
48
|
+
return this.send(cmd + '\n', encoding);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* --- 发送 Enter 键 ---
|
|
53
|
+
*/
|
|
54
|
+
public async sendEnter(): Promise<boolean> {
|
|
55
|
+
return this.send('\n');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* --- 发送 Tab 键 ---
|
|
60
|
+
*/
|
|
61
|
+
public async sendTab(): Promise<boolean> {
|
|
62
|
+
return this.send('\t');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* --- 发送中断 ---
|
|
67
|
+
*/
|
|
68
|
+
public async sendCtrlC(): Promise<boolean> {
|
|
69
|
+
return this.send('\x03');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* --- 关闭 shell ---
|
|
74
|
+
* @param cmd 命令
|
|
75
|
+
* @param encoding 编码
|
|
76
|
+
*/
|
|
77
|
+
public close(cmd?: string | Buffer, encoding?: BufferEncoding): Promise<void> {
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
if (encoding) {
|
|
80
|
+
this._client.end(cmd, encoding, () => {
|
|
81
|
+
resolve();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
this._client.end(cmd, () => {
|
|
86
|
+
resolve();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* --- 获取返回值 ---
|
|
94
|
+
* @param tryCount 如果无知重试次数,1 次为 10 毫秒 ---
|
|
95
|
+
*/
|
|
96
|
+
public async getContent(tryCount: number = 10): Promise<Buffer> {
|
|
97
|
+
let nowCount: number = 0;
|
|
98
|
+
let data: Buffer = Buffer.from('');
|
|
99
|
+
while (true) {
|
|
100
|
+
const r: Buffer | null = this._client.read();
|
|
101
|
+
if (r !== null) {
|
|
102
|
+
data = Buffer.concat([data, r], data.byteLength + r.byteLength);
|
|
103
|
+
nowCount = 0;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
++nowCount;
|
|
107
|
+
if (nowCount === tryCount) {
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
await lCore.sleep(10);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* --- 获取响应读取流对象 ---
|
|
118
|
+
*/
|
|
119
|
+
public getStream(): ssh2.ClientChannel {
|
|
120
|
+
return this._client;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
}
|
package/lib/ssh.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Connection = void 0;
|
|
37
|
+
exports.get = get;
|
|
38
|
+
const ssh2 = __importStar(require("ssh2"));
|
|
39
|
+
const shell = __importStar(require("./ssh/shell"));
|
|
40
|
+
const sftp = __importStar(require("./ssh/sftp"));
|
|
41
|
+
class Connection {
|
|
42
|
+
constructor() {
|
|
43
|
+
this._client = new ssh2.Client();
|
|
44
|
+
}
|
|
45
|
+
connect(opt) {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
if (!opt.mproxy) {
|
|
48
|
+
this._client.on('error', function () {
|
|
49
|
+
resolve(false);
|
|
50
|
+
}).on('ready', () => {
|
|
51
|
+
resolve(true);
|
|
52
|
+
}).connect(opt);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this._mclient = new ssh2.Client();
|
|
56
|
+
const old = {
|
|
57
|
+
'host': opt.host,
|
|
58
|
+
'port': opt.port,
|
|
59
|
+
'username': opt.username,
|
|
60
|
+
'password': opt.password,
|
|
61
|
+
'privateKey': opt.privateKey
|
|
62
|
+
};
|
|
63
|
+
opt.host = opt.mproxy.host;
|
|
64
|
+
opt.port = opt.mproxy.port;
|
|
65
|
+
opt.username = opt.mproxy.username;
|
|
66
|
+
opt.password = opt.mproxy.password;
|
|
67
|
+
if (opt.privateKey) {
|
|
68
|
+
delete opt.privateKey;
|
|
69
|
+
}
|
|
70
|
+
this._mclient.on('error', function () {
|
|
71
|
+
resolve(false);
|
|
72
|
+
}).on('ready', () => {
|
|
73
|
+
if (!old.host || !old.port || !this._mclient) {
|
|
74
|
+
resolve(false);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this._mclient.forwardOut('0.0.0.0', 12345, old.host, old.port, (err, stream) => {
|
|
78
|
+
if (err) {
|
|
79
|
+
this._mclient?.end();
|
|
80
|
+
resolve(false);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this._client.on('error', () => {
|
|
84
|
+
this._mclient?.end();
|
|
85
|
+
resolve(false);
|
|
86
|
+
}).on('ready', () => {
|
|
87
|
+
resolve(true);
|
|
88
|
+
}).on('close', () => {
|
|
89
|
+
this._mclient?.end();
|
|
90
|
+
}).connect({
|
|
91
|
+
'sock': stream,
|
|
92
|
+
'username': old.username,
|
|
93
|
+
'password': old.password,
|
|
94
|
+
'privateKey': old.privateKey
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}).connect(opt);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
disconnect() {
|
|
101
|
+
this._client.end();
|
|
102
|
+
}
|
|
103
|
+
exec(command) {
|
|
104
|
+
return new Promise((resolve) => {
|
|
105
|
+
this._client.exec(command, function (err, channel) {
|
|
106
|
+
if (err ?? !channel) {
|
|
107
|
+
resolve(false);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
let data = Buffer.from('');
|
|
111
|
+
channel.on('close', () => {
|
|
112
|
+
resolve(data);
|
|
113
|
+
}).on('data', function (chunk) {
|
|
114
|
+
data = Buffer.concat([data, chunk], data.length + chunk.length);
|
|
115
|
+
}).stderr.on('data', function (chunk) {
|
|
116
|
+
data = Buffer.concat([data, chunk], data.length + chunk.length);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
getShell() {
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
this._client.shell(function (err, channel) {
|
|
124
|
+
if (err ?? !channel) {
|
|
125
|
+
resolve(null);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
resolve(new shell.Connection(channel));
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
getSftp() {
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
this._client.sftp((err, ssftp) => {
|
|
135
|
+
if (err ?? !ssftp) {
|
|
136
|
+
resolve(null);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
(async () => {
|
|
140
|
+
const pwdb = await this.exec('pwd');
|
|
141
|
+
let pwd = '/';
|
|
142
|
+
if (pwdb) {
|
|
143
|
+
pwd = pwdb.toString().trim();
|
|
144
|
+
if (!pwd.endsWith('/')) {
|
|
145
|
+
pwd = pwd + '/';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
resolve(new sftp.Connection(ssftp, pwd));
|
|
149
|
+
})().catch(function () {
|
|
150
|
+
resolve(null);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
getStream() {
|
|
156
|
+
return new Promise((resolve) => {
|
|
157
|
+
this._client.shell(function (err, stream) {
|
|
158
|
+
if (err) {
|
|
159
|
+
resolve(null);
|
|
160
|
+
}
|
|
161
|
+
resolve(stream);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.Connection = Connection;
|
|
167
|
+
async function get(opt) {
|
|
168
|
+
const conn = new Connection();
|
|
169
|
+
const rtn = await conn.connect(opt);
|
|
170
|
+
return rtn ? conn : null;
|
|
171
|
+
}
|
package/lib/ssh.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* Date: 2019-6-8 21:34:35
|
|
4
|
+
* Last: 2020-04-06 21:22:46, 2022-09-12 00:19:05, 2024-3-4 14:46:11
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// --- 第三方 ---
|
|
8
|
+
import * as ssh2 from 'ssh2';
|
|
9
|
+
// --- 自己 ---
|
|
10
|
+
import * as shell from './ssh/shell';
|
|
11
|
+
import * as sftp from './ssh/sftp';
|
|
12
|
+
|
|
13
|
+
interface IExtOptions {
|
|
14
|
+
'mproxy'?: {
|
|
15
|
+
'host': string;
|
|
16
|
+
'port': number;
|
|
17
|
+
'username': string;
|
|
18
|
+
'password': string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 主连接对象 */
|
|
23
|
+
export class Connection {
|
|
24
|
+
|
|
25
|
+
/** --- SSH 对象 --- */
|
|
26
|
+
private readonly _client: ssh2.Client;
|
|
27
|
+
|
|
28
|
+
/** --- 中转服务器 --- */
|
|
29
|
+
private _mclient?: ssh2.Client;
|
|
30
|
+
|
|
31
|
+
public constructor() {
|
|
32
|
+
this._client = new ssh2.Client();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* --- 发起连接 ---
|
|
37
|
+
* @param opt 选项
|
|
38
|
+
*/
|
|
39
|
+
public connect(opt: ssh2.ConnectConfig & IExtOptions): Promise<boolean> {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
if (!opt.mproxy) {
|
|
42
|
+
this._client.on('error', function() {
|
|
43
|
+
resolve(false);
|
|
44
|
+
}).on('ready', () => {
|
|
45
|
+
resolve(true);
|
|
46
|
+
}).connect(opt);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this._mclient = new ssh2.Client();
|
|
50
|
+
const old = {
|
|
51
|
+
'host': opt.host,
|
|
52
|
+
'port': opt.port,
|
|
53
|
+
'username': opt.username,
|
|
54
|
+
'password': opt.password,
|
|
55
|
+
'privateKey': opt.privateKey
|
|
56
|
+
};
|
|
57
|
+
opt.host = opt.mproxy.host;
|
|
58
|
+
opt.port = opt.mproxy.port;
|
|
59
|
+
opt.username = opt.mproxy.username;
|
|
60
|
+
opt.password = opt.mproxy.password;
|
|
61
|
+
if (opt.privateKey) {
|
|
62
|
+
delete opt.privateKey;
|
|
63
|
+
}
|
|
64
|
+
this._mclient.on('error', function() {
|
|
65
|
+
resolve(false);
|
|
66
|
+
}).on('ready', () => {
|
|
67
|
+
if (!old.host || !old.port || !this._mclient) {
|
|
68
|
+
resolve(false);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this._mclient.forwardOut('0.0.0.0', 12345, old.host, old.port, (err, stream) => {
|
|
72
|
+
if (err) {
|
|
73
|
+
this._mclient?.end();
|
|
74
|
+
resolve(false);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this._client.on('error', () => {
|
|
78
|
+
this._mclient?.end();
|
|
79
|
+
resolve(false);
|
|
80
|
+
}).on('ready', () => {
|
|
81
|
+
resolve(true);
|
|
82
|
+
}).on('close', () => {
|
|
83
|
+
this._mclient?.end();
|
|
84
|
+
}).connect({
|
|
85
|
+
'sock': stream,
|
|
86
|
+
'username': old.username,
|
|
87
|
+
'password': old.password,
|
|
88
|
+
'privateKey': old.privateKey
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}).connect(opt);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* --- 断开此连接 socket ---
|
|
97
|
+
*/
|
|
98
|
+
public disconnect(): void {
|
|
99
|
+
this._client.end();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* --- 执行一个命令并获取返回值,请不要在此执行无尽命令,否则获取不到返回值 ---
|
|
104
|
+
* @param command 命令内容
|
|
105
|
+
*/
|
|
106
|
+
public exec(command: string): Promise<Buffer | false> {
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
this._client.exec(command, function(err?: Error, channel?: ssh2.ClientChannel): void {
|
|
109
|
+
if (err ?? !channel) {
|
|
110
|
+
resolve(false);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
let data = Buffer.from('');
|
|
114
|
+
channel.on('close', () => {
|
|
115
|
+
resolve(data);
|
|
116
|
+
}).on('data', function(chunk: Buffer) {
|
|
117
|
+
data = Buffer.concat([data, chunk], data.length + chunk.length);
|
|
118
|
+
}).stderr.on('data', function(chunk: Buffer) {
|
|
119
|
+
data = Buffer.concat([data, chunk], data.length + chunk.length);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* --- 获取 Shell 执行对象 ---
|
|
127
|
+
*/
|
|
128
|
+
public getShell(): Promise<shell.Connection | null> {
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
this._client.shell(function(err, channel) {
|
|
131
|
+
if (err ?? !channel) {
|
|
132
|
+
resolve(null);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
resolve(new shell.Connection(channel));
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* --- 获取 Sftp 执行对象 ---
|
|
142
|
+
*/
|
|
143
|
+
public getSftp(): Promise<sftp.Connection | null> {
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
this._client.sftp((err, ssftp) => {
|
|
146
|
+
if (err ?? !ssftp) {
|
|
147
|
+
resolve(null);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
(async () => {
|
|
151
|
+
const pwdb = await this.exec('pwd');
|
|
152
|
+
let pwd = '/';
|
|
153
|
+
if (pwdb) {
|
|
154
|
+
pwd = pwdb.toString().trim();
|
|
155
|
+
if (!pwd.endsWith('/')) {
|
|
156
|
+
pwd = pwd + '/';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
resolve(new sftp.Connection(ssftp, pwd));
|
|
160
|
+
})().catch(function() {
|
|
161
|
+
resolve(null);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* --- 直接获取原生 shell stream 对象 ---
|
|
169
|
+
*/
|
|
170
|
+
public getStream(): Promise<ssh2.ClientChannel | null> {
|
|
171
|
+
return new Promise((resolve) => {
|
|
172
|
+
this._client.shell(function(err, stream) {
|
|
173
|
+
if (err) {
|
|
174
|
+
resolve(null);
|
|
175
|
+
}
|
|
176
|
+
resolve(stream);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* --- 创建一个 SSH 连接 ---
|
|
185
|
+
* @param opt 选项
|
|
186
|
+
*/
|
|
187
|
+
export async function get(opt: ssh2.ConnectConfig & IExtOptions): Promise<Connection | null> {
|
|
188
|
+
const conn = new Connection();
|
|
189
|
+
const rtn = await conn.connect(opt);
|
|
190
|
+
return rtn ? conn : null;
|
|
191
|
+
}
|