@maiyunnet/kebab 2.0.6 → 2.0.8
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/index.d.ts +11 -1
- package/index.js +13 -1
- package/lib/buffer.d.ts +25 -0
- package/lib/buffer.js +30 -5
- package/lib/captcha.d.ts +15 -0
- package/lib/captcha.js +20 -0
- package/lib/consistent.d.ts +51 -0
- package/lib/consistent.js +59 -0
- package/lib/core.d.ts +134 -0
- package/lib/core.js +176 -0
- package/lib/crypto.d.ts +75 -6
- package/lib/crypto.js +206 -38
- package/lib/db.d.ts +104 -0
- package/lib/db.js +126 -0
- package/lib/dns.d.ts +51 -0
- package/lib/dns.js +54 -2
- package/lib/fs.d.ts +100 -0
- package/lib/fs.js +118 -0
- package/lib/jwt.d.ts +43 -0
- package/lib/jwt.js +45 -0
- package/lib/kv.d.ts +362 -0
- package/lib/kv.js +377 -0
- package/lib/lan.d.ts +6 -0
- package/lib/lan.js +7 -0
- package/lib/net/formdata.d.ts +38 -0
- package/lib/net/formdata.js +43 -0
- package/lib/net/request.d.ts +62 -0
- package/lib/net/request.js +57 -0
- package/lib/net/response.d.ts +21 -0
- package/lib/net/response.js +16 -0
- package/lib/net.d.ts +86 -0
- package/lib/net.js +140 -0
- package/lib/s3.d.ts +52 -0
- package/lib/s3.js +51 -0
- package/lib/scan.d.ts +52 -0
- package/lib/scan.js +84 -0
- package/lib/session.d.ts +31 -0
- package/lib/session.js +52 -1
- package/lib/sql.d.ts +176 -0
- package/lib/sql.js +287 -2
- package/lib/ssh/sftp.d.ts +106 -0
- package/lib/ssh/sftp.js +106 -0
- package/lib/ssh/shell.d.ts +37 -0
- package/lib/ssh/shell.js +31 -0
- package/lib/ssh.d.ts +32 -0
- package/lib/ssh.js +32 -0
- package/lib/text.d.ts +131 -0
- package/lib/text.js +188 -0
- package/lib/time.d.ts +53 -0
- package/lib/time.js +55 -0
- package/lib/ws.d.ts +68 -0
- package/lib/ws.js +74 -0
- package/lib/zip.d.ts +53 -0
- package/lib/zip.js +73 -0
- package/lib/zlib.d.ts +76 -0
- package/lib/zlib.js +78 -0
- package/main.d.ts +6 -1
- package/main.js +11 -1
- package/package.json +2 -2
- package/sys/child.js +104 -0
- package/sys/cmd.js +28 -0
- package/sys/ctr.d.ts +166 -0
- package/sys/ctr.js +177 -0
- package/sys/master.js +63 -0
- package/sys/mod.d.ts +266 -0
- package/sys/mod.js +335 -0
- package/sys/route.d.ts +34 -0
- package/sys/route.js +164 -0
- package/www/example/ctr/test.d.ts +3 -0
- package/www/example/ctr/test.js +63 -1
- package/www/example/mod/test.js +14 -0
- package/www/example/mod/testdata.js +9 -0
- package/www/example/ws/test.js +1 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/details.md +0 -82
- package/.VSCodeCounter/2025-02-14_14-46-44/diff-details.md +0 -15
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.csv +0 -2
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.md +0 -19
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.txt +0 -22
- package/.VSCodeCounter/2025-02-14_14-46-44/results.csv +0 -69
- package/.VSCodeCounter/2025-02-14_14-46-44/results.json +0 -1
- package/.VSCodeCounter/2025-02-14_14-46-44/results.md +0 -48
- package/.VSCodeCounter/2025-02-14_14-46-44/results.txt +0 -118
- package/.vscode/tasks.json +0 -15
package/lib/net.js
CHANGED
|
@@ -47,16 +47,27 @@ exports.filterProxyHeaders = filterProxyHeaders;
|
|
|
47
47
|
exports.mproxy = mproxy;
|
|
48
48
|
exports.mproxyData = mproxyData;
|
|
49
49
|
exports.rproxy = rproxy;
|
|
50
|
+
/**
|
|
51
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
52
|
+
* Date: 2019-5-15 22:47
|
|
53
|
+
* CA: https://curl.haxx.se/ca/cacert.pem
|
|
54
|
+
* Last: 2020-4-9 20:11:02, 2022-09-22 14:30:13, 2024-1-1 21:32:26, 2024-1-12 13:01:54, 2025-6-13 13:20:52
|
|
55
|
+
*/
|
|
50
56
|
const stream = __importStar(require("stream"));
|
|
57
|
+
// --- 第三方 ---
|
|
51
58
|
const hc = __importStar(require("@litert/http-client"));
|
|
59
|
+
// --- 库和定义 ---
|
|
52
60
|
const fs = __importStar(require("../lib/fs"));
|
|
53
61
|
const text = __importStar(require("../lib/text"));
|
|
54
62
|
const time = __importStar(require("../lib/time"));
|
|
55
63
|
const kebab = __importStar(require("../index"));
|
|
64
|
+
// --- 自己 ---
|
|
56
65
|
const fd = __importStar(require("./net/formdata"));
|
|
57
66
|
const lRequest = __importStar(require("./net/request"));
|
|
58
67
|
const response = __importStar(require("./net/response"));
|
|
68
|
+
/** --- ca 根证书内容 --- */
|
|
59
69
|
let ca = '';
|
|
70
|
+
/** --- 获取 CA 证书 --- */
|
|
60
71
|
async function getCa() {
|
|
61
72
|
if (ca) {
|
|
62
73
|
return ca;
|
|
@@ -64,26 +75,53 @@ async function getCa() {
|
|
|
64
75
|
ca = (await fs.getContent(kebab.LIB_PATH + 'net/cacert.pem', 'utf8')) ?? '';
|
|
65
76
|
return ca;
|
|
66
77
|
}
|
|
78
|
+
/** --- 复用的 hc 对象列表 --- */
|
|
67
79
|
const reuses = {
|
|
68
80
|
'default': hc.createHttpClient()
|
|
69
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* --- 创建一个请求对象 ---
|
|
84
|
+
* @param u
|
|
85
|
+
*/
|
|
70
86
|
function open(u) {
|
|
71
87
|
return new lRequest.Request(u);
|
|
72
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* --- 发起一个 get 请求 ---
|
|
91
|
+
* @param u 请求的 URL
|
|
92
|
+
* @param opt 参数
|
|
93
|
+
*/
|
|
73
94
|
async function get(u, opt = {}) {
|
|
74
95
|
return request(u, undefined, opt);
|
|
75
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* --- 发起一个 post 请求 ---
|
|
99
|
+
* @param u 请求的 URL
|
|
100
|
+
* @param data 要发送的数据
|
|
101
|
+
* @param opt 参数
|
|
102
|
+
*/
|
|
76
103
|
async function post(u, data, opt = {}) {
|
|
77
104
|
opt.method = 'POST';
|
|
78
105
|
return request(u, data, opt);
|
|
79
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* --- 发起 JSON 请求 ---
|
|
109
|
+
* @param u
|
|
110
|
+
* @param data
|
|
111
|
+
* @param opt
|
|
112
|
+
*/
|
|
80
113
|
async function postJson(u, data, opt = {}) {
|
|
81
114
|
opt.method = 'POST';
|
|
82
115
|
opt.type = 'json';
|
|
83
116
|
return request(u, data, opt);
|
|
84
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* --- 发起一个请求 ---
|
|
120
|
+
* @param opt 配置项
|
|
121
|
+
*/
|
|
85
122
|
async function request(u, data, opt = {}) {
|
|
86
123
|
const uri = text.parseUrl(u);
|
|
124
|
+
/** --- 正向代理的地址 --- */
|
|
87
125
|
const puri = opt.mproxy ? text.parseUrl(opt.mproxy.url) : null;
|
|
88
126
|
const method = opt.method ?? 'GET';
|
|
89
127
|
const type = opt.type ?? 'form';
|
|
@@ -100,6 +138,7 @@ async function request(u, data, opt = {}) {
|
|
|
100
138
|
}
|
|
101
139
|
}
|
|
102
140
|
headers['user-agent'] ??= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36';
|
|
141
|
+
// --- DATA ---
|
|
103
142
|
if (method === 'GET') {
|
|
104
143
|
if (data && !(data instanceof stream.Readable) && !Buffer.isBuffer(data)) {
|
|
105
144
|
u += (u.includes('?') ? '&' : '?') +
|
|
@@ -108,6 +147,7 @@ async function request(u, data, opt = {}) {
|
|
|
108
147
|
}
|
|
109
148
|
}
|
|
110
149
|
else {
|
|
150
|
+
// --- POST ---
|
|
111
151
|
if (data && !(data instanceof stream.Readable) && !Buffer.isBuffer(data) && typeof data !== 'string') {
|
|
112
152
|
if (type === 'form') {
|
|
113
153
|
data = text.queryStringify(data);
|
|
@@ -124,14 +164,18 @@ async function request(u, data, opt = {}) {
|
|
|
124
164
|
}
|
|
125
165
|
}
|
|
126
166
|
headers['accept-encoding'] = 'gzip, deflate';
|
|
167
|
+
// --- ssl ---
|
|
127
168
|
if (uri.protocol === 'https:') {
|
|
128
169
|
await getCa();
|
|
129
170
|
}
|
|
171
|
+
// --- cookie 托管 ---
|
|
130
172
|
if (opt.cookie) {
|
|
131
173
|
headers['cookie'] = buildCookieQuery(opt.cookie, uri);
|
|
132
174
|
}
|
|
175
|
+
// --- 发起请求 ---
|
|
133
176
|
let req;
|
|
134
177
|
try {
|
|
178
|
+
// --- 重定义 IP ---
|
|
135
179
|
const host = (puri ? puri.hostname : uri.hostname) ?? '';
|
|
136
180
|
if (!host) {
|
|
137
181
|
const res = new response.Response(null);
|
|
@@ -174,9 +218,14 @@ async function request(u, data, opt = {}) {
|
|
|
174
218
|
res.error = err;
|
|
175
219
|
return res;
|
|
176
220
|
}
|
|
221
|
+
// --- 处理返回值 ---
|
|
222
|
+
// --- 是否追踪 cookie ---
|
|
177
223
|
if (opt.cookie) {
|
|
224
|
+
// --- 提取 cookie ---
|
|
178
225
|
await buildCookieObject(opt.cookie, (req.headers['set-cookie'] ?? []), uri);
|
|
179
226
|
}
|
|
227
|
+
// --- 直接下载到文件 ---
|
|
228
|
+
/** --- 已下载文件的 size --- */
|
|
180
229
|
let total = 0;
|
|
181
230
|
if (save && (!req.headers['location'] || follow === 0)) {
|
|
182
231
|
await new Promise(function (resolve) {
|
|
@@ -192,6 +241,7 @@ async function request(u, data, opt = {}) {
|
|
|
192
241
|
}).pipe(fs.createWriteStream(save));
|
|
193
242
|
});
|
|
194
243
|
}
|
|
244
|
+
// --- 创建 Response 对象 ---
|
|
195
245
|
const res = new response.Response(req);
|
|
196
246
|
if (total) {
|
|
197
247
|
res.setContent(total.toString());
|
|
@@ -209,12 +259,14 @@ async function request(u, data, opt = {}) {
|
|
|
209
259
|
}
|
|
210
260
|
res.headers['http-code'] = req.statusCode;
|
|
211
261
|
res.headers['http-url'] = u;
|
|
262
|
+
// --- 判断 follow 追踪 ---
|
|
212
263
|
if (follow === 0) {
|
|
213
264
|
return res;
|
|
214
265
|
}
|
|
215
266
|
if (!res.headers['location']) {
|
|
216
267
|
return res;
|
|
217
268
|
}
|
|
269
|
+
// --- 哦,要追踪 ---
|
|
218
270
|
headers['referer'] = u;
|
|
219
271
|
return request(text.urlResolve(u, req.headers['location']), data, {
|
|
220
272
|
'method': method,
|
|
@@ -229,6 +281,14 @@ async function request(u, data, opt = {}) {
|
|
|
229
281
|
'reuse': reuse
|
|
230
282
|
});
|
|
231
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* --- 对 cookie 对象进行操作 ---
|
|
286
|
+
* @param cookie 要操作的对象
|
|
287
|
+
* @param name 名
|
|
288
|
+
* @param value 值
|
|
289
|
+
* @param domain 应用网址,如 .xxx.com
|
|
290
|
+
* @param opt 选项 ttl, path, ssl, httponly
|
|
291
|
+
*/
|
|
232
292
|
function setCookie(cookie, name, value, domain, opt = {}) {
|
|
233
293
|
const tim = time.stamp();
|
|
234
294
|
const ttl = opt.ttl ?? 0;
|
|
@@ -248,25 +308,35 @@ function setCookie(cookie, name, value, domain, opt = {}) {
|
|
|
248
308
|
'httponly': opt['httponly'] ? true : false
|
|
249
309
|
};
|
|
250
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* --- 根据 Set-Cookie 头部转换到 cookie 对象 ---
|
|
313
|
+
* @param cookie cookie 对象
|
|
314
|
+
* @param setCookies 头部的 set-cookie 数组
|
|
315
|
+
* @param uri 请求的 URI 对象
|
|
316
|
+
*/
|
|
251
317
|
async function buildCookieObject(cookie, setCookies, uri) {
|
|
252
318
|
const tim = time.stamp();
|
|
253
319
|
uri.path ??= '/';
|
|
254
320
|
for (const setCookie of setCookies) {
|
|
255
321
|
const cookieTmp = {};
|
|
256
322
|
const list = setCookie.split(';');
|
|
323
|
+
// --- 提取 set-cookie 中的定义信息 ---
|
|
257
324
|
for (let index = 0; index < list.length; ++index) {
|
|
258
325
|
const item = list[index];
|
|
259
326
|
const arr = item.split('=');
|
|
260
327
|
const key = arr[0].trim();
|
|
261
328
|
const val = arr[1] ?? '';
|
|
262
329
|
if (index === 0) {
|
|
330
|
+
// --- 用户定义的信息 ---
|
|
263
331
|
cookieTmp['name'] = key;
|
|
264
332
|
cookieTmp['value'] = decodeURIComponent(val);
|
|
265
333
|
}
|
|
266
334
|
else {
|
|
335
|
+
// --- cookie 配置信息,可转小写方便读取 ---
|
|
267
336
|
cookieTmp[key.toLowerCase()] = val;
|
|
268
337
|
}
|
|
269
338
|
}
|
|
339
|
+
// --- 获取定义的 domain ---
|
|
270
340
|
let domain = '', domainN = '';
|
|
271
341
|
if (cookieTmp['domain']) {
|
|
272
342
|
cookieTmp['domain'] = cookieTmp['domain'].split(':')[0];
|
|
@@ -283,15 +353,28 @@ async function buildCookieObject(cookie, setCookies, uri) {
|
|
|
283
353
|
domain = '.' + (uri.hostname ?? '');
|
|
284
354
|
domainN = uri.hostname ?? '';
|
|
285
355
|
}
|
|
356
|
+
// --- 判断有没有设置 domain 的权限 ---
|
|
357
|
+
// --- uri.hostname vs domain(domainN) ---
|
|
358
|
+
// --- ok.xxx.com vs .ok.xxx.com: true ---
|
|
359
|
+
// --- ok.xxx.com vs .xxx.com: true ---
|
|
360
|
+
// --- z.ok.xxx.com vs .xxx.com: true ---
|
|
361
|
+
// --- ok.xxx.com vs .zz.ok.xxx.com: false ---
|
|
286
362
|
if (uri.hostname !== domainN) {
|
|
363
|
+
// --- 设置的域名和当前 host 不相等,如果是 IP、无 . 域名,则直接失败 ---
|
|
287
364
|
if (!text.isDomain(uri.hostname ?? '')) {
|
|
288
365
|
continue;
|
|
289
366
|
}
|
|
290
367
|
const parseDomain = await text.parseDomain(domainN);
|
|
291
368
|
if (parseDomain.tld === domainN.toLowerCase()) {
|
|
369
|
+
// --- 不能给 tld 设置 cookie ---
|
|
292
370
|
continue;
|
|
293
371
|
}
|
|
372
|
+
// --- 判断访问路径 (uri['host']) 是不是设置域名 (domain) 的孩子,domain 必须是 uriHost 的同级或者父辈 ---
|
|
294
373
|
if (!((uri.hostname ?? '').endsWith(domain))) {
|
|
374
|
+
// --- false 代表进入了,代表失败 ---
|
|
375
|
+
// --- ok.xxx.com, .xxx.com: true ---
|
|
376
|
+
// --- ok.xxx.com, .ppp.com: false ---
|
|
377
|
+
// --- ok.xxx.com, .p.ok.xxx.com: false ---
|
|
295
378
|
continue;
|
|
296
379
|
}
|
|
297
380
|
}
|
|
@@ -306,6 +389,7 @@ async function buildCookieObject(cookie, setCookies, uri) {
|
|
|
306
389
|
if (cookieTmp['max-age']) {
|
|
307
390
|
exp = tim + Number(cookieTmp['max-age']);
|
|
308
391
|
}
|
|
392
|
+
// --- path ---
|
|
309
393
|
let path = cookieTmp['path'] ?? '';
|
|
310
394
|
if (path === '') {
|
|
311
395
|
const srp = (uri.pathname ?? '').lastIndexOf('/');
|
|
@@ -325,6 +409,11 @@ async function buildCookieObject(cookie, setCookies, uri) {
|
|
|
325
409
|
};
|
|
326
410
|
}
|
|
327
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* --- 对象转换为 Cookie 拼接字符串(会自动筛掉不能发送的 cookie) ---
|
|
414
|
+
* @param cookie cookie 对象
|
|
415
|
+
* @param uri 请求的 URI 对象
|
|
416
|
+
*/
|
|
328
417
|
function buildCookieQuery(cookie, uri) {
|
|
329
418
|
const tim = time.stamp();
|
|
330
419
|
let cookieStr = '';
|
|
@@ -338,12 +427,26 @@ function buildCookieQuery(cookie, uri) {
|
|
|
338
427
|
if (item.secure && (uri.protocol === 'https')) {
|
|
339
428
|
continue;
|
|
340
429
|
}
|
|
430
|
+
// --- 判断 path 是否匹配 ---
|
|
341
431
|
if (!uri.path.startsWith(item.path)) {
|
|
342
432
|
continue;
|
|
343
433
|
}
|
|
344
434
|
const domain = '.' + item.domain;
|
|
435
|
+
// --- 判断 $uri['host'] 必须是 $domain 的同级或子级 ---
|
|
436
|
+
// --- $uri['host'] vs $domain ---
|
|
437
|
+
// --- ok.xxx.com vs .ok.xxx.com: true ---
|
|
438
|
+
// --- ok.xxx.com vs .xxx.com: true ---
|
|
439
|
+
// --- z.ok.xxx.com vs .xxx.com: true ---
|
|
440
|
+
// --- ok.xxx.com vs .zz.ok.xxx.com: false ---
|
|
345
441
|
if ('.' + (uri.hostname ?? '') !== domain) {
|
|
442
|
+
// --- 域名不相等,那么判断当前域名 host 是不是 domain 的孩子 ---
|
|
346
443
|
if (!(uri.hostname.endsWith(domain))) {
|
|
444
|
+
// --- false 代表进入,被排除了,因为 cookie 的 domain 和当前 host 后半部分,代表不是 domain 的孩子 ---
|
|
445
|
+
// --- ok.xxx.com, .zz.ok.xxx.com: false ---
|
|
446
|
+
// --- pp.ok.xxx.com, .zz.ok.xxx.com: false ---
|
|
447
|
+
// --- q.b.ok.xx.com, .zz.ok.xxx.com: false ---
|
|
448
|
+
// --- z.ok.xxx.com, .xxx.com: true ---
|
|
449
|
+
// --- xx.xxx.com, .ok.xxx.com: false ---
|
|
347
450
|
continue;
|
|
348
451
|
}
|
|
349
452
|
}
|
|
@@ -356,6 +459,10 @@ function buildCookieQuery(cookie, uri) {
|
|
|
356
459
|
return '';
|
|
357
460
|
}
|
|
358
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* --- 模拟重启浏览器后的状态 ---
|
|
464
|
+
* @param cookie cookie 对象
|
|
465
|
+
*/
|
|
359
466
|
function resetCookieSession(cookie) {
|
|
360
467
|
for (const key in cookie) {
|
|
361
468
|
const item = cookie[key];
|
|
@@ -364,10 +471,19 @@ function resetCookieSession(cookie) {
|
|
|
364
471
|
}
|
|
365
472
|
}
|
|
366
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* --- 创建 FormData 对象, Mutton: false, Kebab: true ---
|
|
476
|
+
*/
|
|
367
477
|
function getFormData() {
|
|
368
478
|
return new fd.FormData();
|
|
369
479
|
}
|
|
480
|
+
/** --- proxy 要剔除的基础头部 --- */
|
|
370
481
|
const proxyContinueHeaders = ['host', 'connection', 'http-version', 'http-code', 'http-url'];
|
|
482
|
+
/**
|
|
483
|
+
* --- 剔除不代理的 header ---
|
|
484
|
+
* @param headers 剔除前的 header
|
|
485
|
+
* @param res 直接设置头部而不返回,可置空
|
|
486
|
+
*/
|
|
371
487
|
function filterProxyHeaders(headers, res) {
|
|
372
488
|
const heads = {};
|
|
373
489
|
for (const h in headers) {
|
|
@@ -389,10 +505,18 @@ function filterProxyHeaders(headers, res) {
|
|
|
389
505
|
}
|
|
390
506
|
return heads;
|
|
391
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* --- 正向 mproxy 代理,读取 get 的 url 为实际请求地址 ---
|
|
510
|
+
* --- get: url, auth ---
|
|
511
|
+
* @param ctr 当前控制器
|
|
512
|
+
* @param auth 校验字符串,读取 get 的 auth 和本参数做比对
|
|
513
|
+
* @param opt 参数
|
|
514
|
+
*/
|
|
392
515
|
async function mproxy(ctr, auth, opt = {}) {
|
|
393
516
|
const req = ctr.getPrototype('_req');
|
|
394
517
|
const res = ctr.getPrototype('_res');
|
|
395
518
|
const input = ctr.getPrototype('_input');
|
|
519
|
+
/** --- 客户端请求中的 get 的数据 --- */
|
|
396
520
|
const get = ctr.getPrototype('_get');
|
|
397
521
|
if (get['auth'] !== auth) {
|
|
398
522
|
return 0;
|
|
@@ -403,6 +527,7 @@ async function mproxy(ctr, auth, opt = {}) {
|
|
|
403
527
|
opt.method = req.method ?? 'GET';
|
|
404
528
|
opt.headers ??= {};
|
|
405
529
|
Object.assign(opt.headers, filterProxyHeaders(req.headers));
|
|
530
|
+
// --- 发起请求 ---
|
|
406
531
|
const rres = await request(get['url'], req.headers['content-type']?.includes('form-data') ? req : input, opt);
|
|
407
532
|
if (rres.error) {
|
|
408
533
|
return -2;
|
|
@@ -418,6 +543,10 @@ async function mproxy(ctr, auth, opt = {}) {
|
|
|
418
543
|
});
|
|
419
544
|
return 1;
|
|
420
545
|
}
|
|
546
|
+
/**
|
|
547
|
+
* --- 获取 mproxy 的附加数据 ---
|
|
548
|
+
* @param ctr 当前控制器
|
|
549
|
+
*/
|
|
421
550
|
function mproxyData(ctr) {
|
|
422
551
|
const get = ctr.getPrototype('_get');
|
|
423
552
|
if (!get['data']) {
|
|
@@ -429,6 +558,12 @@ function mproxyData(ctr) {
|
|
|
429
558
|
}
|
|
430
559
|
return data;
|
|
431
560
|
}
|
|
561
|
+
/**
|
|
562
|
+
* --- 反向代理,将本服务器的某个路由反代到其他网址 ---
|
|
563
|
+
* @param ctr 当前控制器
|
|
564
|
+
* @param route 要反代的路由
|
|
565
|
+
* @param opt 参数
|
|
566
|
+
*/
|
|
432
567
|
async function rproxy(ctr, route, opt = {}) {
|
|
433
568
|
const req = ctr.getPrototype('_req');
|
|
434
569
|
const res = ctr.getPrototype('_res');
|
|
@@ -439,10 +574,15 @@ async function rproxy(ctr, route, opt = {}) {
|
|
|
439
574
|
if (!path.startsWith(key)) {
|
|
440
575
|
continue;
|
|
441
576
|
}
|
|
577
|
+
// --- 找到了,做转发 ---
|
|
578
|
+
// --- key 类似:test/net-rproxy/ ---
|
|
579
|
+
// --- 值类似:https://cdn.jsdelivr.net/npm/deskrt@2.0.10/ ---
|
|
580
|
+
/** --- 要拼接的地址 --- */
|
|
442
581
|
const lpath = path.slice(key.length);
|
|
443
582
|
opt.method = req.method ?? 'GET';
|
|
444
583
|
opt.headers ??= {};
|
|
445
584
|
Object.assign(opt.headers, filterProxyHeaders(req.headers));
|
|
585
|
+
// --- 发起请求 ---
|
|
446
586
|
const rres = await request(route[key] + lpath, req.headers['content-type']?.includes('form-data') ? req : input, opt);
|
|
447
587
|
if (rres.error) {
|
|
448
588
|
return false;
|
package/lib/s3.d.ts
CHANGED
|
@@ -1,35 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: Tang Rukun, JianSuoQiYue
|
|
3
|
+
* Date: 2024-2-18 18:32:45
|
|
4
|
+
* Last: 2024-2-18 18:32:47, 2024-3-16 16:42:27, 2024-5-31 21:36:26, 2024-7-8 00:28:42, 2024-7-19 11:32:43, 2025-6-10 21:45:34
|
|
5
|
+
*/
|
|
1
6
|
import * as s3 from '@aws-sdk/client-s3';
|
|
2
7
|
import * as stream from 'stream';
|
|
3
8
|
import * as sCtr from '../sys/ctr';
|
|
9
|
+
/**
|
|
10
|
+
* s3 文档:https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/
|
|
11
|
+
*/
|
|
12
|
+
/** --- 服务商定义 --- */
|
|
4
13
|
export declare enum ESERVICE {
|
|
5
14
|
'AMAZON' = 0,
|
|
6
15
|
'TENCENT' = 1,
|
|
7
16
|
'ALIBABA' = 2,
|
|
8
17
|
'CF' = 3
|
|
9
18
|
}
|
|
19
|
+
/** --- 选项 --- */
|
|
10
20
|
export interface IOptions {
|
|
21
|
+
/** --- 服务商 ---- */
|
|
11
22
|
'service': ESERVICE;
|
|
23
|
+
/** --- cf r2 使用 --- */
|
|
12
24
|
'account'?: string;
|
|
25
|
+
/** --- 密钥键 --- */
|
|
13
26
|
'secretId'?: string;
|
|
27
|
+
/** --- 密钥值 --- */
|
|
14
28
|
'secretKey'?: string;
|
|
29
|
+
/** --- 区域 --- */
|
|
15
30
|
'region'?: string;
|
|
31
|
+
/** --- 预定义 bucket --- */
|
|
16
32
|
'bucket'?: string;
|
|
17
33
|
}
|
|
18
34
|
export declare class S3 {
|
|
19
35
|
private readonly _link;
|
|
36
|
+
/** --- bucket 名 --- */
|
|
20
37
|
private _bucket;
|
|
21
38
|
private readonly _ctr;
|
|
22
39
|
constructor(ctr: sCtr.Ctr, opt: IOptions);
|
|
40
|
+
/**
|
|
41
|
+
* --- 修改预定义 bucket ---
|
|
42
|
+
* @param bucket bucket 名
|
|
43
|
+
*/
|
|
23
44
|
setBucket(bucket: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* --- 上传对象(可传流且也可无需设置 length) --
|
|
47
|
+
* @param key 对象路径
|
|
48
|
+
* @param content 内容
|
|
49
|
+
* @param length 设置 contentLength,如果是流模式则需要设置此项,也可以设置为对象参数
|
|
50
|
+
* @param bucket bucket 名
|
|
51
|
+
*/
|
|
24
52
|
putObject(key: string, content: string | Buffer | stream.Readable, length?: number | {
|
|
25
53
|
'length'?: number;
|
|
26
54
|
'type'?: string;
|
|
27
55
|
'disposition'?: string;
|
|
28
56
|
'bucket'?: string;
|
|
29
57
|
}, bucket?: string): Promise<s3.CompleteMultipartUploadCommandOutput | false>;
|
|
58
|
+
/**
|
|
59
|
+
* --- 获取对象流,可通过流获取 buffer 或 text ---
|
|
60
|
+
* @param key 对象路径
|
|
61
|
+
* @param bucket bucket 名
|
|
62
|
+
*/
|
|
30
63
|
getObject(key: string, bucket?: string): Promise<false | (stream.Readable & import("@smithy/types").SdkStreamMixin) | (Blob & import("@smithy/types").SdkStreamMixin) | (ReadableStream<any> & import("@smithy/types").SdkStreamMixin) | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* --- 删除对象 ---
|
|
66
|
+
* @param key 对象路径
|
|
67
|
+
* @param bucket bucket 名
|
|
68
|
+
*/
|
|
31
69
|
deleteObject(key: string, bucket?: string): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* --- 批量删除对象 ---
|
|
72
|
+
* @param keys 批量对象路径
|
|
73
|
+
* @param bucket bucket 名
|
|
74
|
+
*/
|
|
32
75
|
deleteObjects(keys: string[], bucket?: string): Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* --- 检测对象是否存在 ---
|
|
78
|
+
* @param key 对象路径
|
|
79
|
+
* @param bucket bucket 名
|
|
80
|
+
*/
|
|
33
81
|
headObject(key: string, bucket?: string): Promise<s3.HeadObjectCommandOutput | false>;
|
|
34
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* --- 创建一个对象存储对象 ---
|
|
85
|
+
* @param opt 选项
|
|
86
|
+
*/
|
|
35
87
|
export declare function get(ctr: sCtr.Ctr, opt: IOptions): S3;
|
package/lib/s3.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Project: Kebab, User: Tang Rukun, JianSuoQiYue
|
|
4
|
+
* Date: 2024-2-18 18:32:45
|
|
5
|
+
* Last: 2024-2-18 18:32:47, 2024-3-16 16:42:27, 2024-5-31 21:36:26, 2024-7-8 00:28:42, 2024-7-19 11:32:43, 2025-6-10 21:45:34
|
|
6
|
+
*/
|
|
2
7
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
8
|
if (k2 === undefined) k2 = k;
|
|
4
9
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -35,10 +40,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
41
|
exports.S3 = exports.ESERVICE = void 0;
|
|
37
42
|
exports.get = get;
|
|
43
|
+
// --- 库和定义 ---
|
|
38
44
|
const s3 = __importStar(require("@aws-sdk/client-s3"));
|
|
39
45
|
const ls = __importStar(require("@aws-sdk/lib-storage"));
|
|
40
46
|
const lCore = __importStar(require("../lib/core"));
|
|
41
47
|
const lText = __importStar(require("../lib/text"));
|
|
48
|
+
/**
|
|
49
|
+
* s3 文档:https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/
|
|
50
|
+
*/
|
|
51
|
+
/** --- 服务商定义 --- */
|
|
42
52
|
var ESERVICE;
|
|
43
53
|
(function (ESERVICE) {
|
|
44
54
|
ESERVICE[ESERVICE["AMAZON"] = 0] = "AMAZON";
|
|
@@ -48,6 +58,7 @@ var ESERVICE;
|
|
|
48
58
|
})(ESERVICE || (exports.ESERVICE = ESERVICE = {}));
|
|
49
59
|
class S3 {
|
|
50
60
|
constructor(ctr, opt) {
|
|
61
|
+
/** --- bucket 名 --- */
|
|
51
62
|
this._bucket = '';
|
|
52
63
|
this._ctr = ctr;
|
|
53
64
|
const config = ctr.getPrototype('_config');
|
|
@@ -84,12 +95,25 @@ class S3 {
|
|
|
84
95
|
'endpoint': endpoint
|
|
85
96
|
});
|
|
86
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* --- 修改预定义 bucket ---
|
|
100
|
+
* @param bucket bucket 名
|
|
101
|
+
*/
|
|
87
102
|
setBucket(bucket) {
|
|
88
103
|
this._bucket = bucket;
|
|
89
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* --- 上传对象(可传流且也可无需设置 length) --
|
|
107
|
+
* @param key 对象路径
|
|
108
|
+
* @param content 内容
|
|
109
|
+
* @param length 设置 contentLength,如果是流模式则需要设置此项,也可以设置为对象参数
|
|
110
|
+
* @param bucket bucket 名
|
|
111
|
+
*/
|
|
90
112
|
async putObject(key, content, length, bucket) {
|
|
91
113
|
try {
|
|
114
|
+
/** --- content type --- */
|
|
92
115
|
let type = undefined;
|
|
116
|
+
/** --- content disposition --- */
|
|
93
117
|
let disposition = undefined;
|
|
94
118
|
if (typeof length !== 'number') {
|
|
95
119
|
type = length?.type;
|
|
@@ -116,6 +140,12 @@ class S3 {
|
|
|
116
140
|
return false;
|
|
117
141
|
}
|
|
118
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* --- 获取对象流,可通过流获取 buffer 或 text ---
|
|
145
|
+
* @param key 对象路径
|
|
146
|
+
* @param bucket bucket 名
|
|
147
|
+
*/
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
119
149
|
async getObject(key, bucket) {
|
|
120
150
|
try {
|
|
121
151
|
const go = new s3.GetObjectCommand({
|
|
@@ -126,9 +156,15 @@ class S3 {
|
|
|
126
156
|
return r.Body;
|
|
127
157
|
}
|
|
128
158
|
catch {
|
|
159
|
+
// await lCore.log(this._ctr, '[getObject, s3] ' + lText.stringifyJson(e.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
|
|
129
160
|
return false;
|
|
130
161
|
}
|
|
131
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* --- 删除对象 ---
|
|
165
|
+
* @param key 对象路径
|
|
166
|
+
* @param bucket bucket 名
|
|
167
|
+
*/
|
|
132
168
|
async deleteObject(key, bucket) {
|
|
133
169
|
try {
|
|
134
170
|
const doc = new s3.DeleteObjectCommand({
|
|
@@ -139,9 +175,15 @@ class S3 {
|
|
|
139
175
|
return true;
|
|
140
176
|
}
|
|
141
177
|
catch {
|
|
178
|
+
// await lCore.log(this._ctr, '[deleteObject, s3] ' + lText.stringifyJson(e.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
|
|
142
179
|
return false;
|
|
143
180
|
}
|
|
144
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* --- 批量删除对象 ---
|
|
184
|
+
* @param keys 批量对象路径
|
|
185
|
+
* @param bucket bucket 名
|
|
186
|
+
*/
|
|
145
187
|
async deleteObjects(keys, bucket) {
|
|
146
188
|
try {
|
|
147
189
|
const doc = new s3.DeleteObjectsCommand({
|
|
@@ -158,6 +200,11 @@ class S3 {
|
|
|
158
200
|
return false;
|
|
159
201
|
}
|
|
160
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* --- 检测对象是否存在 ---
|
|
205
|
+
* @param key 对象路径
|
|
206
|
+
* @param bucket bucket 名
|
|
207
|
+
*/
|
|
161
208
|
async headObject(key, bucket) {
|
|
162
209
|
try {
|
|
163
210
|
const ho = new s3.HeadObjectCommand({
|
|
@@ -175,6 +222,10 @@ class S3 {
|
|
|
175
222
|
}
|
|
176
223
|
}
|
|
177
224
|
exports.S3 = S3;
|
|
225
|
+
/**
|
|
226
|
+
* --- 创建一个对象存储对象 ---
|
|
227
|
+
* @param opt 选项
|
|
228
|
+
*/
|
|
178
229
|
function get(ctr, opt) {
|
|
179
230
|
return new S3(ctr, opt);
|
|
180
231
|
}
|
package/lib/scan.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* Date: 2022-09-24 15:23:25
|
|
4
|
+
* Last: 2022-09-24 15:23:25, 2022-9-26 12:37:01, 2022-12-29 00:11:16
|
|
5
|
+
*/
|
|
1
6
|
import * as lDb from '../lib/db';
|
|
2
7
|
import * as lKv from '../lib/kv';
|
|
3
8
|
import * as sCtr from '../sys/ctr';
|
|
9
|
+
/** --- Scan 设置的选项 --- */
|
|
4
10
|
export interface IOptions {
|
|
5
11
|
'ttl'?: number;
|
|
6
12
|
'sqlPre'?: sCtr.Ctr | string;
|
|
7
13
|
'name'?: string;
|
|
8
14
|
}
|
|
15
|
+
/** --- scanned 函数的选项 --- */
|
|
9
16
|
export interface IStaticOptions {
|
|
10
17
|
'sqlPre'?: sCtr.Ctr | string;
|
|
11
18
|
'name'?: string;
|
|
@@ -13,19 +20,64 @@ export interface IStaticOptions {
|
|
|
13
20
|
export declare class Scan {
|
|
14
21
|
private readonly _link;
|
|
15
22
|
private readonly _sql;
|
|
23
|
+
/** --- 表名或者 kv 里 key 的前缀 --- */
|
|
16
24
|
private readonly _name;
|
|
17
25
|
private _token;
|
|
26
|
+
/** --- 有效期,默认 5 分钟 --- */
|
|
18
27
|
private _ttl;
|
|
19
28
|
constructor(link: lDb.Pool | lKv.Pool, token?: string, opt?: IOptions);
|
|
29
|
+
/** --- 二维码剩余有效时间 --- */
|
|
20
30
|
private _timeLeft;
|
|
31
|
+
/**
|
|
32
|
+
* --- 生成二维码处的轮询,检查是否被扫码、被录入数据 ---
|
|
33
|
+
* @returns -3 系统错误 -2 token 不存在或已过期 -1 无操作, 0 已扫码, 其他返回为存的数据并结束轮询
|
|
34
|
+
*/
|
|
21
35
|
poll(): Promise<any>;
|
|
36
|
+
/**
|
|
37
|
+
* --- 创建 token,直接应用到本类 ---
|
|
38
|
+
*/
|
|
22
39
|
createToken(): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* --- 获取当前 token ---
|
|
42
|
+
*/
|
|
23
43
|
getToken(): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* --- 设置有效期,设置后的新 token 被创建有效 ---
|
|
46
|
+
* @param ttl
|
|
47
|
+
*/
|
|
24
48
|
setTTL(ttl: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* --- 获取设置的有效期 ---
|
|
51
|
+
*/
|
|
25
52
|
getTTL(): number;
|
|
53
|
+
/**
|
|
54
|
+
* --- 获取当前 token 可扫剩余有效期 ---
|
|
55
|
+
*/
|
|
26
56
|
getTimeLeft(): number | null;
|
|
57
|
+
/**
|
|
58
|
+
* --- 根据情况清空 Db 状态下的 scan 表垃圾数据 ---
|
|
59
|
+
*/
|
|
27
60
|
private _gc;
|
|
28
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* -- 创建 Scan 对象 ---
|
|
64
|
+
* @param link
|
|
65
|
+
* @param token Token
|
|
66
|
+
* @param opt
|
|
67
|
+
*/
|
|
29
68
|
export declare function get(link: lDb.Pool | lKv.Pool, token?: string, opt?: IOptions): Promise<Scan>;
|
|
69
|
+
/**
|
|
70
|
+
* --- 对 token 执行访问操作,通常用户扫码后展示的网页所调用,代表已扫码 ---
|
|
71
|
+
* @param link
|
|
72
|
+
* @patam token 必填
|
|
73
|
+
* @param opt
|
|
74
|
+
*/
|
|
30
75
|
export declare function scanned(link: lDb.Pool | lKv.Pool, token: string, opt?: IStaticOptions): Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* --- 将数据写入 token,通常在客户的逻辑下去写,服务器会 poll 到 ---
|
|
78
|
+
* @param link
|
|
79
|
+
* @param token
|
|
80
|
+
* @param data
|
|
81
|
+
* @param opt
|
|
82
|
+
*/
|
|
31
83
|
export declare function setData(link: lDb.Pool | lKv.Pool, token: string, data: Record<string, any> | string | number, opt?: IStaticOptions): Promise<boolean>;
|