@whyour/qinglong 2.20.2-2 → 2.21.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/.env.example +5 -0
- package/AGENTS.md +43 -0
- package/CLAUDE.md +43 -0
- package/README-en.md +11 -0
- package/README.md +11 -0
- package/docker/Dockerfile +51 -69
- package/docker/Dockerfile.310 +94 -0
- package/docker/Dockerfile.debian +120 -0
- package/docker/{310.Dockerfile → Dockerfile.debian310} +13 -5
- package/docker/docker-entrypoint.sh +95 -3
- package/docs/PROJECT_ARCHITECTURE.md +550 -0
- package/package.json +28 -25
- package/sample/config.sample.sh +12 -1
- package/sample/notify.js +81 -9
- package/sample/notify.py +54 -11
- package/shell/api.sh +44 -20
- package/shell/bot.sh +30 -16
- package/shell/check.sh +21 -19
- package/shell/lang/en.sh +105 -0
- package/shell/lang/zh.sh +105 -0
- package/shell/otask.sh +114 -28
- package/shell/preload/client.js +20 -2
- package/shell/preload/esm-loader.mjs +41 -0
- package/shell/preload/sitecustomize.js +36 -0
- package/shell/pub.sh +8 -8
- package/shell/rmlog.sh +5 -5
- package/shell/share.sh +49 -30
- package/shell/start.sh +40 -27
- package/shell/task.sh +10 -2
- package/shell/update.sh +22 -22
- package/static/build/api/config.js +17 -7
- package/static/build/api/cron.js +38 -1
- package/static/build/api/dashboard.js +337 -0
- package/static/build/api/env.js +40 -2
- package/static/build/api/index.js +2 -0
- package/static/build/api/log.js +5 -4
- package/static/build/api/script.js +34 -9
- package/static/build/api/system.js +16 -1
- package/static/build/api/user.js +6 -5
- package/static/build/app.js +3 -0
- package/static/build/config/const.js +7 -6
- package/static/build/config/container.js +12 -0
- package/static/build/config/grpcCerts.js +150 -0
- package/static/build/config/index.js +6 -0
- package/static/build/config/util.js +66 -15
- package/static/build/data/cron.js +3 -1
- package/static/build/data/cronStats.js +59 -0
- package/static/build/data/env.js +2 -0
- package/static/build/data/notify.js +11 -1
- package/static/build/data/runningInstance.js +57 -0
- package/static/build/loaders/app.js +1 -1
- package/static/build/loaders/db.js +6 -0
- package/static/build/loaders/express.js +2 -1
- package/static/build/loaders/initData.js +19 -2
- package/static/build/loaders/initFile.js +2 -0
- package/static/build/schedule/api.js +1 -1
- package/static/build/schedule/client.js +9 -1
- package/static/build/schedule/health.js +1 -1
- package/static/build/services/config.js +19 -5
- package/static/build/services/cron.js +118 -8
- package/static/build/services/env.js +31 -3
- package/static/build/services/grpc.js +32 -6
- package/static/build/services/http.js +33 -18
- package/static/build/services/notify.js +40 -3
- package/static/build/services/open.js +2 -1
- package/static/build/services/sshKey.js +6 -3
- package/static/build/services/subscription.js +2 -1
- package/static/build/services/system.js +22 -7
- package/static/build/services/user.js +8 -7
- package/static/build/shared/i18n.js +105 -0
- package/static/build/shared/pLimit.js +12 -1
- package/static/build/shared/runCron.js +5 -0
- package/static/build/validation/schedule.js +1 -0
- package/static/dist/1089.0ecc5383.async.js +1 -0
- package/static/dist/1147.c420132e.async.js +1 -0
- package/static/dist/1192.4e5740f2.async.js +1 -0
- package/static/dist/1214.c6469b53.async.js +1 -0
- package/static/dist/134.54df9e38.async.js +1 -0
- package/static/dist/1352.96a77e1d.async.js +1 -0
- package/static/dist/{1765.d8e002d7.async.js → 1765.5ac01a93.async.js} +1 -1
- package/static/dist/1836.f0b74cf1.async.js +1 -0
- package/static/dist/{1885.e0d00d2d.async.js → 1885.e1ea09f6.async.js} +1 -1
- package/static/dist/1967.3f3945d0.async.js +1 -0
- package/static/dist/{2096.383c1047.async.js → 2096.6d98fd12.async.js} +1 -1
- package/static/dist/2208.f7ba3dfa.async.js +1 -0
- package/static/dist/2286.164bb089.async.js +1 -0
- package/static/dist/2476.4e9b0992.async.js +1 -0
- package/static/dist/2537.2b262ee0.async.js +1 -0
- package/static/dist/{255.12f03ab2.async.js → 255.8a80b983.async.js} +1 -1
- package/static/dist/2635.d4c59d23.async.js +1 -0
- package/static/dist/2808.cdc0995c.async.js +1 -0
- package/static/dist/{2821.be3dc88e.async.js → 2821.651f31e5.async.js} +1 -1
- package/static/dist/2986.4c49eef7.async.js +1 -0
- package/static/dist/300.08ac9875.async.js +1 -0
- package/static/dist/{3191.70bc19db.async.js → 3191.63263871.async.js} +1 -1
- package/static/dist/3714.8d6dba9e.async.js +1 -0
- package/static/dist/3906.a5eee612.async.js +1 -0
- package/static/dist/{6541.a6d499de.async.js → 3948.4fe809fd.async.js} +1 -1
- package/static/dist/{5171.7fc6d0a2.async.js → 4573.16f19278.async.js} +1 -1
- package/static/dist/{4859.93e63ea6.async.js → 4859.6592cebb.async.js} +1 -1
- package/static/dist/4887.8e3ae573.async.js +1 -0
- package/static/dist/{4902.54ecbdb5.async.js → 4902.555f92ab.async.js} +1 -1
- package/static/dist/{4934.1ca6b6b0.async.js → 4934.f3539d08.async.js} +1 -1
- package/static/dist/5077.cbd111cd.async.js +1 -0
- package/static/dist/{6247.b550d996.async.js → 5157.7c5af144.async.js} +1 -1
- package/static/dist/{540.481d4708.async.js → 540.19ddf020.async.js} +1 -1
- package/static/dist/{5970.10ac4f16.async.js → 5970.d3a6e7bd.async.js} +1 -1
- package/static/dist/{6013.2d7bb12a.async.js → 6013.4e38de36.async.js} +1 -1
- package/static/dist/{6016.9c379049.async.js → 6016.1e6574b6.async.js} +1 -1
- package/static/dist/{6035.5889ddc7.async.js → 6035.32ebfad9.async.js} +1 -1
- package/static/dist/6339.ab305e96.async.js +1 -0
- package/static/dist/6569.55177f6a.async.js +1 -0
- package/static/dist/6610.c111af7e.async.js +1 -0
- package/static/dist/{3034.6413c38e.async.js → 6638.87a163d2.async.js} +1 -1
- package/static/dist/{6646.5fc37228.async.js → 6646.95e92533.async.js} +1 -1
- package/static/dist/6665.1d099ad1.async.js +1 -0
- package/static/dist/{7355.b7c0562f.async.js → 7355.f9f263d8.async.js} +1 -1
- package/static/dist/{7384.065ccae2.async.js → 7384.1bb449d5.async.js} +1 -1
- package/static/dist/7441.ee1bf2bb.async.js +1 -0
- package/static/dist/{7508.a31662a3.async.js → 7508.7dcee91c.async.js} +1 -1
- package/static/dist/{7802.6b73f16a.async.js → 7802.34255805.async.js} +1 -1
- package/static/dist/{7984.e6bb9378.async.js → 7984.594296a5.async.js} +1 -1
- package/static/dist/{5653.4fce7ce8.async.js → 8033.5cb31493.async.js} +1 -1
- package/static/dist/8147.2fb55202.async.js +1 -0
- package/static/dist/8187.48c130d6.async.js +1 -0
- package/static/dist/8495.d53e15ca.async.js +1 -0
- package/static/dist/8587.315b06c0.async.js +1 -0
- package/static/dist/8826.2447a104.async.js +1 -0
- package/static/dist/{2742.4852aac8.async.js → 8865.ed665d31.async.js} +1 -1
- package/static/dist/901.7ee5c6d3.async.js +1 -0
- package/static/dist/9271.231db2ce.async.js +1 -0
- package/static/dist/9323.a33f47da.async.js +1 -0
- package/static/dist/{9730.30083c91.async.js → 9730.801665a3.async.js} +1 -1
- package/static/dist/{9761.627ca3b5.async.js → 9761.360a19d8.async.js} +1 -1
- package/static/dist/index.html +2 -2
- package/static/dist/layouts__index.a7a2bfe0.async.js +1 -0
- package/static/dist/layouts__index.adf0692f.chunk.css +1 -0
- package/static/dist/preload_helper.0431c0f3.js +1 -0
- package/static/dist/{src__pages__config__index.622b6ee8.async.js → src__pages__config__index.a22ff7dc.async.js} +1 -1
- package/static/dist/{src__pages__crontab__const.323d5124.async.js → src__pages__crontab__const.aba07deb.async.js} +1 -1
- package/static/dist/src__pages__crontab__detail.b9c36808.async.js +1 -0
- package/static/dist/src__pages__crontab__index.fed99fd0.async.js +1 -0
- package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.0b8cce8c.async.js} +1 -1
- package/static/dist/src__pages__crontab__modal.f7041c7c.async.js +1 -0
- package/static/dist/src__pages__crontab__type.d7af36e5.async.js +1 -0
- package/static/dist/{src__pages__crontab__viewCreateModal.ffcf7a24.async.js → src__pages__crontab__viewCreateModal.4d589f66.async.js} +1 -1
- package/static/dist/{src__pages__crontab__viewManageModal.c2724575.async.js → src__pages__crontab__viewManageModal.0e317746.async.js} +1 -1
- package/static/dist/src__pages__dashboard__index.b30f2f47.async.js +1 -0
- package/static/dist/{src__pages__dependence__logModal.f123e2ac.async.js → src__pages__dependence__logModal.0681830b.async.js} +1 -1
- package/static/dist/src__pages__dependence__modal.11124896.async.js +1 -0
- package/static/dist/src__pages__env__editNameModal.5d264b25.async.js +1 -0
- package/static/dist/src__pages__env__index.baa27d4e.async.js +1 -0
- package/static/dist/src__pages__env__modal.7f2ef1bc.async.js +1 -0
- package/static/dist/src__pages__error__index.f156b45e.async.js +1 -0
- package/static/dist/src__pages__initialization__index.e96d4ba8.async.js +1 -0
- package/static/dist/{src__pages__log__index.cf00c9af.async.js → src__pages__log__index.e0978bae.async.js} +1 -1
- package/static/dist/{src__pages__login__index.cd6e3152.async.js → src__pages__login__index.8c813eb1.async.js} +1 -1
- package/static/dist/{src__pages__script__components__UnsupportedFilePreview__index.39074c68.async.js → src__pages__script__components__UnsupportedFilePreview__index.c347a13a.async.js} +1 -1
- package/static/dist/src__pages__script__editNameModal.3e7e100d.async.js +1 -0
- package/static/dist/src__pages__script__index.2765d1b8.async.js +1 -0
- package/static/dist/src__pages__script__renameModal.5e987ef5.async.js +1 -0
- package/static/dist/src__pages__script__saveModal.3f9d23d6.async.js +1 -0
- package/static/dist/src__pages__script__setting.a535793a.async.js +1 -0
- package/static/dist/src__pages__setting__appModal.251cd14f.async.js +1 -0
- package/static/dist/src__pages__setting__dependence.8a7a9529.async.js +1 -0
- package/static/dist/src__pages__setting__index.cc85fdfb.async.js +1 -0
- package/static/dist/src__pages__setting__notification.390fc905.async.js +1 -0
- package/static/dist/src__pages__setting__other.b22d2165.async.js +1 -0
- package/static/dist/src__pages__setting__security.598720a8.async.js +1 -0
- package/static/dist/src__pages__setting__systemLog.67406721.async.js +1 -0
- package/static/dist/{src__pages__subscription__logModal.0caa7283.async.js → src__pages__subscription__logModal.3864b37f.async.js} +1 -1
- package/static/dist/src__pages__subscription__modal.3562c670.async.js +1 -0
- package/static/dist/{umi.ef8199a4.js → umi.ca04a019.js} +1 -1
- package/version.yaml +33 -4
- package/sample/notify.py.save +0 -1010
- package/static/dist/105.85a5c47a.async.js +0 -1
- package/static/dist/1083.f86ce804.async.js +0 -1
- package/static/dist/1147.32f41a88.async.js +0 -1
- package/static/dist/1352.ab6da08e.async.js +0 -1
- package/static/dist/1690.f0290540.async.js +0 -1
- package/static/dist/1742.6cbe5aca.async.js +0 -1
- package/static/dist/2208.8e3a7325.async.js +0 -1
- package/static/dist/5312.74b95311.async.js +0 -1
- package/static/dist/5691.931f59c5.async.js +0 -1
- package/static/dist/6159.55cb068a.async.js +0 -1
- package/static/dist/7025.f4080d63.async.js +0 -1
- package/static/dist/739.6be5552a.async.js +0 -1
- package/static/dist/7571.4f6240b1.async.js +0 -1
- package/static/dist/786.59fc381c.async.js +0 -1
- package/static/dist/8317.c44c1ebd.async.js +0 -1
- package/static/dist/8826.0291edfd.async.js +0 -1
- package/static/dist/955.3c9481f7.async.js +0 -1
- package/static/dist/layouts__index.1fce90e0.chunk.css +0 -1
- package/static/dist/layouts__index.8dcf1576.async.js +0 -1
- package/static/dist/preload_helper.116a62f6.js +0 -1
- package/static/dist/src__pages__crontab__detail.b07f0c0a.async.js +0 -1
- package/static/dist/src__pages__crontab__index.2e2e1096.async.js +0 -1
- package/static/dist/src__pages__crontab__modal.4d8c2a22.async.js +0 -1
- package/static/dist/src__pages__crontab__type.db7c1858.async.js +0 -1
- package/static/dist/src__pages__dependence__modal.631ffb5b.async.js +0 -1
- package/static/dist/src__pages__env__editNameModal.ff85ef8c.async.js +0 -1
- package/static/dist/src__pages__env__index.a0a2fece.async.js +0 -1
- package/static/dist/src__pages__env__modal.d1004662.async.js +0 -1
- package/static/dist/src__pages__error__index.1bc3c90b.async.js +0 -1
- package/static/dist/src__pages__initialization__index.8b1cbaf9.async.js +0 -1
- package/static/dist/src__pages__script__editNameModal.53424d49.async.js +0 -1
- package/static/dist/src__pages__script__index.e65df827.async.js +0 -1
- package/static/dist/src__pages__script__renameModal.4bbe7fb1.async.js +0 -1
- package/static/dist/src__pages__script__saveModal.cf449f3c.async.js +0 -1
- package/static/dist/src__pages__script__setting.b345d59a.async.js +0 -1
- package/static/dist/src__pages__setting__appModal.03faec89.async.js +0 -1
- package/static/dist/src__pages__setting__dependence.4495c7b6.async.js +0 -1
- package/static/dist/src__pages__setting__index.6919c399.async.js +0 -1
- package/static/dist/src__pages__setting__notification.d6a3884f.async.js +0 -1
- package/static/dist/src__pages__setting__other.0d931d6f.async.js +0 -1
- package/static/dist/src__pages__setting__security.91cb545f.async.js +0 -1
- package/static/dist/src__pages__setting__systemLog.1d433a48.async.js +0 -1
- package/static/dist/src__pages__subscription__modal.0b84f6cf.async.js +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const builtinModules = [
|
|
5
|
+
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
|
|
6
|
+
'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'process', 'querystring',
|
|
7
|
+
'readline', 'stream', 'string_decoder', 'timers', 'tls', 'tty', 'url', 'util',
|
|
8
|
+
'v8', 'zlib',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
function isBareSpecifier(specifier) {
|
|
12
|
+
return !specifier.startsWith('.') &&
|
|
13
|
+
!specifier.startsWith('/') &&
|
|
14
|
+
!specifier.startsWith('file:') &&
|
|
15
|
+
!specifier.startsWith('node:') &&
|
|
16
|
+
!builtinModules.includes(specifier) &&
|
|
17
|
+
!builtinModules.includes(specifier.split('/')[0]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function resolve(specifier, context, nextResolve) {
|
|
21
|
+
if (!isBareSpecifier(specifier)) {
|
|
22
|
+
return nextResolve(specifier, context);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 解析优先级:全局 pnpm > 系统全局
|
|
26
|
+
const bases = [
|
|
27
|
+
process.env.QL_NODE_GLOBAL_PATH,
|
|
28
|
+
'/usr/local/lib/node_modules',
|
|
29
|
+
].filter(Boolean);
|
|
30
|
+
|
|
31
|
+
for (const base of bases) {
|
|
32
|
+
if (existsSync(join(base, specifier))) {
|
|
33
|
+
return nextResolve(specifier, {
|
|
34
|
+
...context,
|
|
35
|
+
parentURL: new URL(`${join(base, specifier)}/`, 'file://').href,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return nextResolve(specifier, context);
|
|
41
|
+
}
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
|
+
const Module = require('module');
|
|
3
|
+
const path = require('path');
|
|
2
4
|
const client = require('./client.js');
|
|
3
5
|
require(`./env.js`);
|
|
4
6
|
|
|
7
|
+
// 注册 ESM loader,使全局安装的包也可通过 import 导入
|
|
8
|
+
try {
|
|
9
|
+
Module.register(new URL('esm-loader.mjs', `file://${__dirname}/`).href);
|
|
10
|
+
} catch (_) {}
|
|
11
|
+
|
|
12
|
+
function preferGlobalNodeModules() {
|
|
13
|
+
const { QL_NODE_GLOBAL_PATH } = process.env;
|
|
14
|
+
if (!QL_NODE_GLOBAL_PATH || Module._qlGlobalPathPatched) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const originalResolveFilename = Module._resolveFilename;
|
|
19
|
+
Module._resolveFilename = function (request, parent, isMain, options) {
|
|
20
|
+
if (
|
|
21
|
+
!Module.builtinModules.includes(request) &&
|
|
22
|
+
!request.startsWith('node:') &&
|
|
23
|
+
!request.startsWith('.') &&
|
|
24
|
+
!path.isAbsolute(request)
|
|
25
|
+
) {
|
|
26
|
+
try {
|
|
27
|
+
return originalResolveFilename.call(this, request, parent, isMain, {
|
|
28
|
+
...options,
|
|
29
|
+
paths: [QL_NODE_GLOBAL_PATH],
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
35
|
+
};
|
|
36
|
+
Module._qlGlobalPathPatched = true;
|
|
37
|
+
}
|
|
38
|
+
|
|
5
39
|
function expandRange(rangeStr, max) {
|
|
6
40
|
const tempRangeStr = rangeStr
|
|
7
41
|
.trim()
|
|
@@ -113,6 +147,8 @@ try {
|
|
|
113
147
|
return;
|
|
114
148
|
}
|
|
115
149
|
|
|
150
|
+
preferGlobalNodeModules();
|
|
151
|
+
|
|
116
152
|
process.on('SIGTERM', (code) => {
|
|
117
153
|
process.exit(15);
|
|
118
154
|
});
|
package/shell/pub.sh
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
echo -e "开始发布"
|
|
3
3
|
|
|
4
|
-
echo -e "切换
|
|
5
|
-
git branch -D
|
|
6
|
-
git checkout -b
|
|
7
|
-
git push --set-upstream origin
|
|
4
|
+
echo -e "切换master分支"
|
|
5
|
+
git branch -D master
|
|
6
|
+
git checkout -b master
|
|
7
|
+
git push --set-upstream origin master -f
|
|
8
8
|
|
|
9
9
|
echo -e "更新cdn文件"
|
|
10
10
|
ts-node-transpile-only sample/tool.ts
|
|
11
11
|
|
|
12
12
|
string=$(cat version.yaml | grep "version" | egrep "[^ ]*" -o | egrep "\d\.*")
|
|
13
13
|
version="v$string"
|
|
14
|
-
echo -e "当前版本$version
|
|
14
|
+
echo -e "当前版本$version"
|
|
15
15
|
|
|
16
16
|
echo -e "删除已经存在的本地tag"
|
|
17
|
-
git tag -d "$version
|
|
17
|
+
git tag -d "$version" &>/dev/null
|
|
18
18
|
|
|
19
19
|
echo -e "删除已经存在的远程tag"
|
|
20
|
-
git push origin :refs/tags/$version
|
|
20
|
+
git push origin :refs/tags/$version &>/dev/null
|
|
21
21
|
|
|
22
22
|
echo -e "创建新tag"
|
|
23
|
-
git tag -a "$version
|
|
23
|
+
git tag -a "$version" -m "release $version"
|
|
24
24
|
|
|
25
25
|
echo -e "提交tag"
|
|
26
26
|
git push --tags
|
package/shell/rmlog.sh
CHANGED
|
@@ -22,12 +22,12 @@ remove_js_log() {
|
|
|
22
22
|
if [[ $diff_time -gt $((${days} * 86400)) ]]; then
|
|
23
23
|
local log_path=$(echo "$log" | sed "s,${dir_log}/,,g")
|
|
24
24
|
local result=$(find_cron_api "log_path=$log_path")
|
|
25
|
-
|
|
25
|
+
t '查询文件 %s' "$log_path"
|
|
26
26
|
if [[ -z $result ]]; then
|
|
27
|
-
|
|
27
|
+
t '删除中~'
|
|
28
28
|
rm -vf $log
|
|
29
29
|
else
|
|
30
|
-
|
|
30
|
+
t '正在被 %s 使用,跳过~' "$result"
|
|
31
31
|
fi
|
|
32
32
|
fi
|
|
33
33
|
done
|
|
@@ -43,8 +43,8 @@ remove_empty_dir() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
if [[ ${days} ]]; then
|
|
46
|
-
|
|
46
|
+
t '查找旧日志文件中...\n'
|
|
47
47
|
remove_js_log
|
|
48
48
|
remove_empty_dir
|
|
49
|
-
|
|
49
|
+
t '删除旧日志执行完毕\n'
|
|
50
50
|
fi
|
package/shell/share.sh
CHANGED
|
@@ -65,17 +65,7 @@ link_name=(
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
init_env() {
|
|
68
|
-
|
|
69
|
-
export NODE_PATH="/usr/local/bin:/usr/local/lib/node_modules${pnpm_global_path:+:${pnpm_global_path}}"
|
|
70
|
-
|
|
71
|
-
# 如果存在 pnpm 全局路径,创建软链接
|
|
72
|
-
if [[ -n "$pnpm_global_path" ]]; then
|
|
73
|
-
# 确保目标目录存在
|
|
74
|
-
mkdir -p "${dir_root}/node_modules"
|
|
75
|
-
# 链接全局模块到项目的 node_modules
|
|
76
|
-
ln -sf "${pnpm_global_path}/"* "${dir_root}/node_modules/" 2>/dev/null || true
|
|
77
|
-
fi
|
|
78
|
-
|
|
68
|
+
export NODE_PATH="/usr/local/bin:/usr/local/lib/node_modules"
|
|
79
69
|
export PYTHONUNBUFFERED=1
|
|
80
70
|
}
|
|
81
71
|
|
|
@@ -88,6 +78,16 @@ load_ql_envs() {
|
|
|
88
78
|
|
|
89
79
|
import_config() {
|
|
90
80
|
[[ -f $file_config_user ]] && . $file_config_user
|
|
81
|
+
[[ -f $dir_preload/lang_env.sh ]] && . $dir_preload/lang_env.sh
|
|
82
|
+
|
|
83
|
+
# 加载语言包(bash 4+ 支持 declare -A,不兼容时回退输出中文 key)
|
|
84
|
+
local lang=${QL_LANG:-zh}
|
|
85
|
+
local lang_file="$dir_shell/lang/${lang}.sh"
|
|
86
|
+
if [[ ${BASH_VERSINFO[0]} -ge 4 ]] && [[ -f $lang_file ]]; then
|
|
87
|
+
. $lang_file
|
|
88
|
+
elif [[ ${BASH_VERSINFO[0]} -ge 4 ]]; then
|
|
89
|
+
. "$dir_shell/lang/zh.sh"
|
|
90
|
+
fi
|
|
91
91
|
|
|
92
92
|
load_ql_envs
|
|
93
93
|
command_timeout_time=${CommandTimeoutTime:-""}
|
|
@@ -101,6 +101,18 @@ import_config() {
|
|
|
101
101
|
fi
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
t() {
|
|
105
|
+
local key="$1"
|
|
106
|
+
shift
|
|
107
|
+
local msg
|
|
108
|
+
if declare -p LANG_MESSAGES &>/dev/null; then
|
|
109
|
+
msg="${LANG_MESSAGES["$key"]}"
|
|
110
|
+
fi
|
|
111
|
+
[[ -z $msg ]] && msg="$key"
|
|
112
|
+
# shellcheck disable=SC2059
|
|
113
|
+
printf "$msg\n" "$@"
|
|
114
|
+
}
|
|
115
|
+
|
|
104
116
|
set_proxy() {
|
|
105
117
|
local proxy="$1"
|
|
106
118
|
if [[ $proxy ]]; then
|
|
@@ -235,7 +247,7 @@ npm_install_2() {
|
|
|
235
247
|
local dir_work=$1
|
|
236
248
|
|
|
237
249
|
cd $dir_work
|
|
238
|
-
|
|
250
|
+
t '安装 %s 依赖包...\n' "$dir_work"
|
|
239
251
|
npm_install_sub
|
|
240
252
|
cd $dir_current
|
|
241
253
|
}
|
|
@@ -254,7 +266,7 @@ git_clone_scripts() {
|
|
|
254
266
|
local branch="$3"
|
|
255
267
|
local proxy="$4"
|
|
256
268
|
[[ $branch ]] && local part_cmd="-b $branch "
|
|
257
|
-
|
|
269
|
+
t '开始拉取仓库 %s 到 %s\n' "${uniq_path}" "$dir"
|
|
258
270
|
|
|
259
271
|
set_proxy "$proxy"
|
|
260
272
|
|
|
@@ -287,18 +299,18 @@ reload_pm2() {
|
|
|
287
299
|
return 0
|
|
288
300
|
else
|
|
289
301
|
local exit_code=$?
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
302
|
+
t '警告: PM2 启动失败 (退出码: %s),可能是由于硬件不兼容' "$exit_code"
|
|
303
|
+
t '正在尝试直接使用 Node.js 启动服务...'
|
|
304
|
+
|
|
293
305
|
# Kill any existing node processes for qinglong
|
|
294
306
|
pkill -f "node.*static/build/app.js" 2>/dev/null || true
|
|
295
|
-
|
|
307
|
+
|
|
296
308
|
# Start node directly in the background
|
|
297
309
|
nohup node static/build/app.js > $dir_log/qinglong.log 2>&1 &
|
|
298
310
|
local node_pid=$!
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
311
|
+
|
|
312
|
+
t '已使用 Node.js 直接启动服务 (PID: %s)' "$node_pid"
|
|
313
|
+
t '注意: 使用此模式时,部分 PM2 管理功能将不可用'
|
|
302
314
|
return 0
|
|
303
315
|
fi
|
|
304
316
|
}
|
|
@@ -370,16 +382,16 @@ handle_task_start() {
|
|
|
370
382
|
error_message=", 任务状态更新失败(${error})"
|
|
371
383
|
fi
|
|
372
384
|
fi
|
|
373
|
-
|
|
385
|
+
t '## 开始执行... %s\n' "${begin_time}${error_message}"
|
|
374
386
|
}
|
|
375
387
|
|
|
376
388
|
run_task_before() {
|
|
377
389
|
. $file_task_before "$@"
|
|
378
390
|
|
|
379
391
|
if [[ ${task_before:=} ]]; then
|
|
380
|
-
|
|
392
|
+
t '执行前置命令\n'
|
|
381
393
|
eval "${task_before%;}"
|
|
382
|
-
|
|
394
|
+
t '\n执行前置命令结束\n'
|
|
383
395
|
fi
|
|
384
396
|
}
|
|
385
397
|
|
|
@@ -387,9 +399,9 @@ run_task_after() {
|
|
|
387
399
|
. $file_task_after "$@"
|
|
388
400
|
|
|
389
401
|
if [[ ${task_after:=} ]]; then
|
|
390
|
-
|
|
402
|
+
t '\n执行后置命令\n'
|
|
391
403
|
eval "${task_after%;}"
|
|
392
|
-
|
|
404
|
+
t '\n执行后置命令结束'
|
|
393
405
|
fi
|
|
394
406
|
}
|
|
395
407
|
|
|
@@ -398,18 +410,25 @@ handle_task_end() {
|
|
|
398
410
|
local end_time=$(format_time "$time_format" "$etime")
|
|
399
411
|
local end_timestamp=$(format_timestamp "$time_format" "$etime")
|
|
400
412
|
local diff_time=$(($end_timestamp - $begin_timestamp))
|
|
401
|
-
local
|
|
402
|
-
[[ "${MANUAL:=}" == "true" ]] && suffix="(手动停止)"
|
|
403
|
-
|
|
413
|
+
local exit_code="${_task_exit_code:-0}"
|
|
404
414
|
[[ "$diff_time" == 0 ]] && diff_time=1
|
|
405
415
|
|
|
406
416
|
if [[ $ID ]]; then
|
|
407
417
|
local error=$(update_cron "\"$ID\"" "1" "$$" "$log_path" "$begin_timestamp" "$diff_time")
|
|
408
418
|
if [[ $error ]]; then
|
|
409
|
-
error_message=",
|
|
419
|
+
error_message=", 状态更新失败(${error})"
|
|
410
420
|
fi
|
|
411
421
|
fi
|
|
412
|
-
|
|
422
|
+
|
|
423
|
+
record_cron_stat "$ID" "${exit_code:-0}" "$diff_time"
|
|
424
|
+
|
|
425
|
+
if [[ "${MANUAL:=}" == "true" ]]; then
|
|
426
|
+
t '\n## 已停止 🛑... %s 耗时 %s 秒%s' "$end_time" "$diff_time" "${error_message:=} "
|
|
427
|
+
elif [[ $exit_code -eq 0 ]]; then
|
|
428
|
+
t '\n## 完成 ✅... %s 耗时 %s 秒%s' "$end_time" "$diff_time" "${error_message:=} "
|
|
429
|
+
else
|
|
430
|
+
t '\n## 失败 ❌(退出码 %s)... %s 耗时 %s 秒%s' "$exit_code" "$end_time" "$diff_time" "${error_message:=} "
|
|
431
|
+
fi
|
|
413
432
|
}
|
|
414
433
|
|
|
415
434
|
init_env
|
package/shell/start.sh
CHANGED
|
@@ -12,23 +12,23 @@ if [[ ! $QL_DIR ]]; then
|
|
|
12
12
|
elif [[ -d "$pnpm_dir/@whyour/qinglong" ]]; then
|
|
13
13
|
QL_DIR="$pnpm_dir/@whyour/qinglong"
|
|
14
14
|
else
|
|
15
|
-
|
|
15
|
+
t '未找到 qinglong 模块,请先执行 npm i -g @whyour/qinglong 安装'
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
18
|
if [[ $QL_DIR ]]; then
|
|
19
|
-
|
|
19
|
+
t '请先手动设置 export QL_DIR=%s,环境变量,并手动添加到系统环境变量,然后再次执行命令 qinglong 启动服务' "$QL_DIR"
|
|
20
20
|
fi
|
|
21
21
|
|
|
22
22
|
exit 1
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
25
|
if [[ ! $QL_DATA_DIR ]]; then
|
|
26
|
-
|
|
26
|
+
t '请先手动设置数据存储目录 export QL_DATA_DIR 环境变量,目录必须以斜杠开头的绝对路径,并且以 /data 结尾,例如 /ql/data 并手动添加到系统环境变量'
|
|
27
27
|
exit 1
|
|
28
28
|
fi
|
|
29
29
|
|
|
30
30
|
if [[ $QL_DATA_DIR != */data ]]; then
|
|
31
|
-
|
|
31
|
+
t 'QL_DATA_DIR 必须以 /data 结尾,例如 /ql/data,如果有历史数据,请新建 data 目录,把历史数据放到 data 目录中'
|
|
32
32
|
exit 1
|
|
33
33
|
fi
|
|
34
34
|
|
|
@@ -36,31 +36,44 @@ command="$1"
|
|
|
36
36
|
|
|
37
37
|
if [[ $command != "reload" ]]; then
|
|
38
38
|
# 安装依赖
|
|
39
|
-
os_name
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
tzdata \
|
|
49
|
-
perl \
|
|
50
|
-
openssl \
|
|
51
|
-
jq \
|
|
52
|
-
nginx \
|
|
53
|
-
openssh \
|
|
54
|
-
procps \
|
|
55
|
-
netcat-openbsd
|
|
56
|
-
elif [[ $os_name == 'debian' ]] || [[ $os_name == 'ubuntu' ]]; then
|
|
57
|
-
apt-get update
|
|
58
|
-
apt-get install -y git curl wget tzdata perl openssl jq nginx procps netcat-openbsd openssh-client
|
|
59
|
-
else
|
|
60
|
-
echo -e "暂不支持此系统部署 $os_name"
|
|
61
|
-
exit 1
|
|
39
|
+
os_name="${QL_OS_TYPE:-}"
|
|
40
|
+
if [ -z "$os_name" ]; then
|
|
41
|
+
os_name=$(source /etc/os-release && echo "$ID")
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# 非 root 用户使用 sudo
|
|
45
|
+
SUDO=""
|
|
46
|
+
if [ "$(id -u)" -ne 0 ]; then
|
|
47
|
+
SUDO="sudo"
|
|
62
48
|
fi
|
|
63
49
|
|
|
50
|
+
case "$os_name" in
|
|
51
|
+
alpine)
|
|
52
|
+
$SUDO apk update
|
|
53
|
+
$SUDO apk add -f bash \
|
|
54
|
+
coreutils \
|
|
55
|
+
git \
|
|
56
|
+
curl \
|
|
57
|
+
wget \
|
|
58
|
+
tzdata \
|
|
59
|
+
perl \
|
|
60
|
+
openssl \
|
|
61
|
+
jq \
|
|
62
|
+
nginx \
|
|
63
|
+
openssh \
|
|
64
|
+
procps \
|
|
65
|
+
netcat-openbsd
|
|
66
|
+
;;
|
|
67
|
+
debian|ubuntu)
|
|
68
|
+
$SUDO apt-get update
|
|
69
|
+
$SUDO apt-get install -y git curl wget tzdata perl openssl jq nginx procps netcat-openbsd openssh-client
|
|
70
|
+
;;
|
|
71
|
+
*)
|
|
72
|
+
t '暂不支持此系统部署 %s' "$os_name"
|
|
73
|
+
exit 1
|
|
74
|
+
;;
|
|
75
|
+
esac
|
|
76
|
+
|
|
64
77
|
npm install -g pnpm@8.3.1 pm2 ts-node
|
|
65
78
|
fi
|
|
66
79
|
|
package/shell/task.sh
CHANGED
|
@@ -4,9 +4,17 @@ dir_shell=$QL_DIR/shell
|
|
|
4
4
|
. $dir_shell/share.sh
|
|
5
5
|
. $dir_shell/api.sh
|
|
6
6
|
|
|
7
|
-
trap
|
|
7
|
+
trap 'single_hanle SIGINT' INT
|
|
8
|
+
trap 'single_hanle SIGTERM' TERM
|
|
9
|
+
trap 'single_hanle SIGHUP' HUP
|
|
10
|
+
trap 'single_hanle SIGALRM' ALRM
|
|
11
|
+
trap 'single_hanle SIGTSTP' TSTP
|
|
12
|
+
trap 'single_hanle SIGQUIT' QUIT
|
|
13
|
+
|
|
8
14
|
single_hanle() {
|
|
9
|
-
|
|
15
|
+
_task_exit_code="${_task_exit_code:-$?}"
|
|
16
|
+
[[ "$_task_exit_code" == "0" ]] && _task_exit_code="1"
|
|
17
|
+
eval MANUAL=true handle_task_end "$@"
|
|
10
18
|
exit 1
|
|
11
19
|
}
|
|
12
20
|
|
package/shell/update.sh
CHANGED
|
@@ -33,7 +33,7 @@ output_list_add_drop() {
|
|
|
33
33
|
local list=$1
|
|
34
34
|
local type=$2
|
|
35
35
|
if [[ -s $list ]]; then
|
|
36
|
-
|
|
36
|
+
t '检测到有%s的定时任务:' "$type"
|
|
37
37
|
cat $list
|
|
38
38
|
fi
|
|
39
39
|
}
|
|
@@ -45,7 +45,7 @@ del_cron() {
|
|
|
45
45
|
local path=$2
|
|
46
46
|
local detail=""
|
|
47
47
|
local ids=""
|
|
48
|
-
|
|
48
|
+
t '\n开始尝试自动删除失效的定时任务...'
|
|
49
49
|
for cron in $(cat $list_drop); do
|
|
50
50
|
local id=$(cat $list_crontab_user | grep -E "$cmd_task.* $cron" | perl -pe "s|.*ID=(.*) $cmd_task.* $cron\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
|
51
51
|
if [[ $ids ]]; then
|
|
@@ -76,7 +76,7 @@ del_cron() {
|
|
|
76
76
|
add_cron() {
|
|
77
77
|
local list_add=$1
|
|
78
78
|
local path=$2
|
|
79
|
-
|
|
79
|
+
t '\n开始尝试自动添加定时任务...'
|
|
80
80
|
local detail=""
|
|
81
81
|
cd $dir_scripts
|
|
82
82
|
for file in $(cat $list_add); do
|
|
@@ -136,10 +136,10 @@ update_repo() {
|
|
|
136
136
|
git_clone_scripts "${formatUrl}" ${repo_path} "${branch}" "${proxy}"
|
|
137
137
|
|
|
138
138
|
if [[ $exit_status -eq 0 ]]; then
|
|
139
|
-
|
|
139
|
+
t '拉取 %s 成功...\n' "${uniq_path}"
|
|
140
140
|
diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions" "$autoAddCron" "$autoDelCron"
|
|
141
141
|
else
|
|
142
|
-
|
|
142
|
+
t '拉取 %s 失败,请检查日志...\n' "${uniq_path}"
|
|
143
143
|
fi
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -160,7 +160,7 @@ update_raw() {
|
|
|
160
160
|
local raw_url="$url"
|
|
161
161
|
local suffix="${raw_url##*.}"
|
|
162
162
|
local raw_file_name="${uniq_path}.${suffix}"
|
|
163
|
-
|
|
163
|
+
t '开始下载:%s 保存路径:%s\n' "${raw_url}" "$dir_raw/${raw_file_name}"
|
|
164
164
|
|
|
165
165
|
set_proxy "$proxy"
|
|
166
166
|
wget -q --no-check-certificate -O "$dir_raw/${raw_file_name}.new" ${raw_url}
|
|
@@ -169,7 +169,7 @@ update_raw() {
|
|
|
169
169
|
|
|
170
170
|
if [[ $? -eq 0 ]]; then
|
|
171
171
|
mv "$dir_raw/${raw_file_name}.new" "$dir_raw/${raw_file_name}"
|
|
172
|
-
|
|
172
|
+
t '下载 %s 成功...\n' "${raw_file_name}"
|
|
173
173
|
cd $dir_raw
|
|
174
174
|
local filename="raw_${raw_file_name}"
|
|
175
175
|
local cron_id=$(cat $list_crontab_user | grep -E "$cmd_task.* $filename" | perl -pe "s|.*ID=(.*) $cmd_task.* $filename\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
|
@@ -196,7 +196,7 @@ update_raw() {
|
|
|
196
196
|
# update_cron_api "$cron_line:$cmd_task $filename:$cron_name:$cron_id"
|
|
197
197
|
fi
|
|
198
198
|
else
|
|
199
|
-
|
|
199
|
+
t '下载 %s 失败,保留之前正常下载的版本...\n' "${raw_file_name}"
|
|
200
200
|
[[ -f "$dir_raw/${raw_file_name}.new" ]] && rm -f "$dir_raw/${raw_file_name}.new"
|
|
201
201
|
fi
|
|
202
202
|
|
|
@@ -207,13 +207,13 @@ run_extra_shell() {
|
|
|
207
207
|
if [[ -f $file_extra_shell ]]; then
|
|
208
208
|
. $file_extra_shell
|
|
209
209
|
else
|
|
210
|
-
|
|
210
|
+
t '%s文件不存在,跳过执行...\n' "$file_extra_shell"
|
|
211
211
|
fi
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
## 脚本用法
|
|
215
215
|
usage() {
|
|
216
|
-
|
|
216
|
+
t "$cmd_update 命令使用方法:"
|
|
217
217
|
echo -e "1. $cmd_update update # 更新并重启青龙"
|
|
218
218
|
echo -e "2. $cmd_update extra # 运行自定义脚本"
|
|
219
219
|
echo -e "3. $cmd_update raw <fileurl> # 更新单个脚本文件"
|
|
@@ -268,7 +268,7 @@ update_qinglong() {
|
|
|
268
268
|
downloadQLUrl="https://github.com/whyour/qinglong/archive/refs/heads"
|
|
269
269
|
downloadStaticUrl="https://github.com/whyour/qinglong-static/archive/refs/heads"
|
|
270
270
|
fi
|
|
271
|
-
|
|
271
|
+
t '使用 %s 源更新...\n' "${mirror}"
|
|
272
272
|
|
|
273
273
|
local primary_branch="master"
|
|
274
274
|
if [[ "${QL_BRANCH}" == "develop" ]] || [[ "${QL_BRANCH}" == "debian" ]] || [[ "${QL_BRANCH}" == "debian-dev" ]]; then
|
|
@@ -279,13 +279,13 @@ update_qinglong() {
|
|
|
279
279
|
exit_status=$?
|
|
280
280
|
|
|
281
281
|
if [[ $exit_status -eq 0 ]]; then
|
|
282
|
-
|
|
282
|
+
t '更新青龙源文件成功...\n'
|
|
283
283
|
|
|
284
284
|
unzip -oq ${dir_tmp}/ql.zip -d ${dir_tmp}
|
|
285
285
|
|
|
286
286
|
update_qinglong_static
|
|
287
287
|
else
|
|
288
|
-
|
|
288
|
+
t '更新青龙源文件失败,请检查网络...\n'
|
|
289
289
|
fi
|
|
290
290
|
}
|
|
291
291
|
|
|
@@ -294,30 +294,30 @@ update_qinglong_static() {
|
|
|
294
294
|
exit_status=$?
|
|
295
295
|
|
|
296
296
|
if [[ $exit_status -eq 0 ]]; then
|
|
297
|
-
|
|
297
|
+
t '更新青龙静态资源成功...\n'
|
|
298
298
|
unzip -oq ${dir_tmp}/static.zip -d ${dir_tmp}
|
|
299
299
|
|
|
300
300
|
check_update_dep
|
|
301
301
|
else
|
|
302
|
-
|
|
302
|
+
t '更新青龙静态资源失败,请检查网络...\n'
|
|
303
303
|
fi
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
check_update_dep() {
|
|
307
|
-
|
|
307
|
+
t '\n开始检测依赖...\n'
|
|
308
308
|
if [[ $(diff $dir_root/package.json ${dir_tmp}/qinglong-${primary_branch}/package.json) ]]; then
|
|
309
309
|
npm_install_2 "${dir_tmp}/qinglong-${primary_branch}"
|
|
310
310
|
fi
|
|
311
311
|
|
|
312
312
|
if [[ $exit_status -eq 0 ]]; then
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
t '\n依赖检测安装成功...\n'
|
|
314
|
+
t '更新包下载成功...\n'
|
|
315
315
|
|
|
316
316
|
if [[ "$needRestart" == 'true' ]]; then
|
|
317
317
|
reload_qinglong "system"
|
|
318
318
|
fi
|
|
319
319
|
else
|
|
320
|
-
|
|
320
|
+
t '\n依赖检测安装失败,请检查网络...\n'
|
|
321
321
|
fi
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -514,7 +514,7 @@ main() {
|
|
|
514
514
|
if [[ -n $p2 ]]; then
|
|
515
515
|
update_repo "$p2" "$p3" "$p4" "$p5" "$p6" "$p7" "$p8" "$p9" "$p10"
|
|
516
516
|
else
|
|
517
|
-
|
|
517
|
+
t '命令输入错误...\n'
|
|
518
518
|
eval usage $cmd
|
|
519
519
|
fi
|
|
520
520
|
;;
|
|
@@ -523,7 +523,7 @@ main() {
|
|
|
523
523
|
if [[ -n $p2 ]]; then
|
|
524
524
|
update_raw "$p2" "$p3" "$p4" "$p5"
|
|
525
525
|
else
|
|
526
|
-
|
|
526
|
+
t '命令输入错误...\n'
|
|
527
527
|
eval usage $cmd
|
|
528
528
|
fi
|
|
529
529
|
;;
|
|
@@ -549,7 +549,7 @@ main() {
|
|
|
549
549
|
eval update_auth_config "\\\"username\\\":\\\"$p2\\\"" "重置用户名" $cmd
|
|
550
550
|
;;
|
|
551
551
|
*)
|
|
552
|
-
|
|
552
|
+
t '命令输入错误...\n'
|
|
553
553
|
eval usage $cmd
|
|
554
554
|
;;
|
|
555
555
|
esac
|
|
@@ -33,6 +33,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
33
33
|
const celebrate_1 = require("celebrate");
|
|
34
34
|
const path_1 = require("path");
|
|
35
35
|
const const_1 = require("../config/const");
|
|
36
|
+
const i18n_1 = require("../shared/i18n");
|
|
36
37
|
const config_2 = __importDefault(require("../services/config"));
|
|
37
38
|
const utils_1 = require("../shared/utils");
|
|
38
39
|
const route = (0, express_1.Router)();
|
|
@@ -84,15 +85,24 @@ exports.default = (app) => {
|
|
|
84
85
|
const logger = typedi_1.Container.get('logger');
|
|
85
86
|
try {
|
|
86
87
|
const { name, content } = req.body;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
let path = (0, path_1.join)(config_1.default.configPath, name);
|
|
88
|
+
// Resolve path first to prevent traversal attacks
|
|
89
|
+
let basePath = config_1.default.configPath;
|
|
91
90
|
if (name.startsWith('data/scripts/')) {
|
|
92
|
-
|
|
91
|
+
basePath = (0, path_1.join)(config_1.default.rootPath, 'data/scripts');
|
|
92
|
+
}
|
|
93
|
+
const cleanName = name.replace(/^data\/scripts\//, '');
|
|
94
|
+
const resolvedPath = (0, path_1.join)(basePath, cleanName);
|
|
95
|
+
const normalized = (0, path_1.join)(resolvedPath);
|
|
96
|
+
// Verify the resolved path stays within allowed directory
|
|
97
|
+
if (!normalized.startsWith(basePath)) {
|
|
98
|
+
return res.send({ code: 403, message: (0, i18n_1.t)('文件路径无效') });
|
|
99
|
+
}
|
|
100
|
+
// Check blacklist on actual filename (not user input)
|
|
101
|
+
if (config_1.default.blackFileList.includes((0, path_1.basename)(normalized))) {
|
|
102
|
+
return res.send({ code: 403, message: (0, i18n_1.t)('文件无法访问') });
|
|
93
103
|
}
|
|
94
|
-
await (0, utils_1.writeFileWithLock)(
|
|
95
|
-
res.send({ code: 200, message: '保存成功' });
|
|
104
|
+
await (0, utils_1.writeFileWithLock)(normalized, content);
|
|
105
|
+
res.send({ code: 200, message: (0, i18n_1.t)('保存成功') });
|
|
96
106
|
}
|
|
97
107
|
catch (e) {
|
|
98
108
|
return next(e);
|