qq-bot-roost 0.8.10 → 0.8.11
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/README.md +1 -1
- package/package.json +1 -1
- package/src/plugin/deps.js +42 -19
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="零依赖">
|
|
11
11
|
<img src="https://img.shields.io/badge/tests-600%2B%20passed-brightgreen" alt="测试 600+ 项">
|
|
12
12
|
<img src="https://img.shields.io/badge/plugins-JS%20%7C%20Python%20%7C%20Go%20%7C%20any-blue" alt="多语言插件">
|
|
13
|
-
<img src="https://img.shields.io/badge/version-0.8.
|
|
13
|
+
<img src="https://img.shields.io/badge/version-0.8.11-blueviolet" alt="版本 0.8.11">
|
|
14
14
|
<img src="https://img.shields.io/badge/license-Non--Commercial-red" alt="禁止商用">
|
|
15
15
|
<a href="https://github.com/tdcq9594/qq-bot-roost/actions"><img src="https://img.shields.io/github/actions/workflow/status/tdcq9594/qq-bot-roost/ci.yml?branch=master" alt="CI"></a>
|
|
16
16
|
|
package/package.json
CHANGED
package/src/plugin/deps.js
CHANGED
|
@@ -239,6 +239,42 @@ function venvPython(venvDir) {
|
|
|
239
239
|
: path.join(venvDir, 'bin', 'python');
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* requirements.txt 单行的白名单。
|
|
244
|
+
*
|
|
245
|
+
* 只接受「包名 + 版本约束」(可带 extras、可带环境标记)这一种形态,其它一律拒。
|
|
246
|
+
* 不能用黑名单——pip 的选项缩写太多(`-i` = `--index-url`、`-c` = 约束文件、
|
|
247
|
+
* `-r` = 嵌套 requirement、`--no-index`、`--pre`…),黑名单列不完,
|
|
248
|
+
* 漏一个就是一条供应链后门:插件作者能把 pip 指到任意源、拉任意代码。
|
|
249
|
+
*
|
|
250
|
+
* 环境标记里也不许出现 `--`,否则 `pkg; x --index-url evil` 会绕过这条意图。
|
|
251
|
+
*/
|
|
252
|
+
const REQUIREMENT_RE =
|
|
253
|
+
/^[A-Za-z0-9][A-Za-z0-9._-]*(?:\[[A-Za-z0-9._,-]+\])?(?:\s*(?:==|>=|<=|~=|!=|===|>|<)\s*[^\s,]+(?:\s*,\s*[^\s,]+)*)?(?:\s*;\s*(?:(?!--)[^\n])+)?$/;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* pip 自己的注释规则(见 pip._internal.req.req_file.COMMENT_RE):(^|\s+)#.*$
|
|
257
|
+
* 套白名单前必须按同样规则剥掉,否则 `requests>=2.31 # 固定下限` 这种合法写法
|
|
258
|
+
* 会被误杀——这里是 throw,误杀等于整个插件装不上。
|
|
259
|
+
*/
|
|
260
|
+
const stripReqComment = (l) => l.replace(/(^|\s+)#.*$/, '').trim();
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* 校验 requirements.txt 全文。
|
|
264
|
+
* 抽成独立函数是为了能直接测:白名单一旦被改坏(拒了合法行 / 放了危险行),
|
|
265
|
+
* 靠构造假 python 走 ensurePluginDeps 很难测全。
|
|
266
|
+
*
|
|
267
|
+
* @param {string} requirements 文件全文
|
|
268
|
+
* @returns {{ok: true} | {ok: false, line: string}} line 是第一条不安全的行(已剥注释)
|
|
269
|
+
*/
|
|
270
|
+
export function checkRequirements(requirements) {
|
|
271
|
+
const bad = String(requirements ?? '')
|
|
272
|
+
.split(/\r?\n/)
|
|
273
|
+
.map((l) => stripReqComment(l.trim()))
|
|
274
|
+
.find((l) => l !== '' && !REQUIREMENT_RE.test(l));
|
|
275
|
+
return bad === undefined ? { ok: true } : { ok: false, line: bad };
|
|
276
|
+
}
|
|
277
|
+
|
|
242
278
|
/**
|
|
243
279
|
* 确保插件的依赖装好。
|
|
244
280
|
*
|
|
@@ -311,27 +347,14 @@ export async function ensurePluginDeps({ dir, manifest = {}, log = null, enabled
|
|
|
311
347
|
/**
|
|
312
348
|
* requirements.txt 里能写 `--index-url`、`-e git+...`、直接写 URL——
|
|
313
349
|
* 等于让插件作者把 pip 指到任意源、拉任意代码。
|
|
314
|
-
*
|
|
315
|
-
* 这里用**白名单**(fail-closed):只接受「包名 + 版本约束」这一种形态,
|
|
316
|
-
* 其它一律拒。不能用黑名单——pip 的选项缩写太多(`-i` = `--index-url`、
|
|
317
|
-
* `-c` = 约束文件、`-r` = 嵌套 requirement、`--no-index`、`--pre`…),
|
|
318
|
-
* 黑名单列不完,漏一个就是一条供应链后门。
|
|
319
|
-
*
|
|
320
|
-
* 合法行只匹配:包名(字母数字 + `-_.`)后面可选地跟版本约束
|
|
321
|
-
* (`==` / `>=` / `~=` / `<=` / `!=` / `>` / `<` 等,或逗号分隔的多个)。
|
|
322
|
-
* 环境标记(`; python_version < "3.8"`)一并放行,它不含网络指令。
|
|
350
|
+
* 白名单的细节和理由见上面的 checkRequirements()。
|
|
323
351
|
*/
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
.map((l) => l.trim())
|
|
327
|
-
.find((l) => {
|
|
328
|
-
if (!l || l.startsWith('#')) return false; // 空行 / 注释放行
|
|
329
|
-
return !/^[A-Za-z0-9][A-Za-z0-9._-]*(?:\[[A-Za-z0-9._,-]+\])?(?:\s*(?:==|>=|<=|~=|!=|===|>|<)\s*[^\s,]+(?:\s*,\s*[^\s,]+)*)?(?:\s*;\s*[^\n]+)?$/.test(l);
|
|
330
|
-
});
|
|
331
|
-
if (badLine) {
|
|
352
|
+
const rq = checkRequirements(requirements);
|
|
353
|
+
if (!rq.ok) {
|
|
332
354
|
throw new Error(
|
|
333
|
-
`requirements.txt 里有不安全的行,已拒绝安装:${
|
|
334
|
-
'只允许「包名 + 版本约束」(如 requests>=2.31),不接受 -e / --index-url / 直接 URL / pip 选项。'
|
|
355
|
+
`requirements.txt 里有不安全的行,已拒绝安装:${rq.line}\n` +
|
|
356
|
+
'只允许「包名 + 版本约束」(如 requests>=2.31),不接受 -e / --index-url / 直接 URL / pip 选项。' +
|
|
357
|
+
'行尾注释可以写(`# xxx`),但不支持反斜杠续行。',
|
|
335
358
|
);
|
|
336
359
|
}
|
|
337
360
|
|