@whyour/qinglong 2.20.2-3 → 2.21.0-10

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.
Files changed (238) hide show
  1. package/.env.example +5 -0
  2. package/AGENTS.md +43 -0
  3. package/README-en.md +11 -0
  4. package/README.md +11 -0
  5. package/back/protos/api.proto +3 -0
  6. package/deploy/kubernetes/README.md +81 -0
  7. package/deploy/kubernetes/base/kustomization.yaml +5 -0
  8. package/deploy/kubernetes/base/qinglong.yaml +95 -0
  9. package/deploy/kubernetes/overlays/example/kustomization.yaml +10 -0
  10. package/docker/Dockerfile +51 -69
  11. package/docker/Dockerfile.310 +94 -0
  12. package/docker/Dockerfile.debian +120 -0
  13. package/docker/{310.Dockerfile → Dockerfile.debian310} +13 -5
  14. package/docker/docker-entrypoint.sh +95 -3
  15. package/docs/PROJECT_ARCHITECTURE.md +550 -0
  16. package/package.json +29 -28
  17. package/sample/config.sample.sh +19 -3
  18. package/sample/notify.js +145 -9
  19. package/sample/notify.py +110 -11
  20. package/shell/api.sh +51 -21
  21. package/shell/bot.sh +30 -16
  22. package/shell/check.sh +21 -19
  23. package/shell/lang/en.sh +105 -0
  24. package/shell/lang/zh.sh +105 -0
  25. package/shell/otask.sh +117 -28
  26. package/shell/preload/client.js +20 -2
  27. package/shell/preload/esm-loader.mjs +41 -0
  28. package/shell/preload/sitecustomize.js +36 -0
  29. package/shell/pub.sh +8 -8
  30. package/shell/rmlog.sh +5 -5
  31. package/shell/share.sh +50 -31
  32. package/shell/start.sh +40 -27
  33. package/shell/task.sh +10 -2
  34. package/shell/update.sh +22 -22
  35. package/static/build/api/config.js +17 -7
  36. package/static/build/api/cron.js +40 -3
  37. package/static/build/api/dashboard.js +344 -0
  38. package/static/build/api/env.js +40 -2
  39. package/static/build/api/index.js +2 -0
  40. package/static/build/api/log.js +15 -5
  41. package/static/build/api/script.js +34 -9
  42. package/static/build/api/system.js +22 -8
  43. package/static/build/api/user.js +6 -5
  44. package/static/build/app.js +22 -19
  45. package/static/build/config/const.js +8 -6
  46. package/static/build/config/container.js +12 -0
  47. package/static/build/config/grpcCerts.js +150 -0
  48. package/static/build/config/index.js +6 -4
  49. package/static/build/config/util.js +69 -18
  50. package/static/build/data/cron.js +3 -1
  51. package/static/build/data/cronStats.js +59 -0
  52. package/static/build/data/env.js +2 -0
  53. package/static/build/data/notify.js +18 -1
  54. package/static/build/data/runningInstance.js +57 -0
  55. package/static/build/data/sock.js +1 -0
  56. package/static/build/loaders/app.js +7 -7
  57. package/static/build/loaders/db.js +8 -2
  58. package/static/build/loaders/deps.js +1 -22
  59. package/static/build/loaders/express.js +19 -15
  60. package/static/build/loaders/initData.js +20 -2
  61. package/static/build/loaders/initFile.js +3 -1
  62. package/static/build/loaders/initTask.js +3 -2
  63. package/static/build/loaders/server.js +1 -1
  64. package/static/build/protos/api.js +23 -1
  65. package/static/build/schedule/addCron.js +67 -10
  66. package/static/build/schedule/api.js +1 -1
  67. package/static/build/schedule/client.js +9 -1
  68. package/static/build/schedule/delCron.js +11 -1
  69. package/static/build/schedule/health.js +1 -1
  70. package/static/build/services/config.js +19 -5
  71. package/static/build/services/cron.js +198 -38
  72. package/static/build/services/dependence.js +19 -18
  73. package/static/build/services/env.js +31 -3
  74. package/static/build/services/grpc.js +32 -6
  75. package/static/build/services/http.js +33 -18
  76. package/static/build/services/notify.js +87 -8
  77. package/static/build/services/open.js +2 -1
  78. package/static/build/services/sshKey.js +6 -3
  79. package/static/build/services/subscription.js +8 -5
  80. package/static/build/services/system.js +34 -9
  81. package/static/build/services/user.js +39 -13
  82. package/static/build/shared/auth.js +7 -1
  83. package/static/build/shared/i18n.js +160 -0
  84. package/static/build/shared/pLimit.js +15 -3
  85. package/static/build/shared/runCron.js +5 -0
  86. package/static/build/shared/store.js +7 -0
  87. package/static/build/validation/schedule.js +10 -0
  88. package/static/dist/1089.0ecc5383.async.js +1 -0
  89. package/static/dist/1147.62793604.async.js +1 -0
  90. package/static/dist/1192.4e5740f2.async.js +1 -0
  91. package/static/dist/1214.c6469b53.async.js +1 -0
  92. package/static/dist/134.54df9e38.async.js +1 -0
  93. package/static/dist/1352.96a77e1d.async.js +1 -0
  94. package/static/dist/{1765.d8e002d7.async.js → 1765.5ac01a93.async.js} +1 -1
  95. package/static/dist/1836.f0b74cf1.async.js +1 -0
  96. package/static/dist/{1885.e0d00d2d.async.js → 1885.e1ea09f6.async.js} +1 -1
  97. package/static/dist/1967.3f3945d0.async.js +1 -0
  98. package/static/dist/{2096.383c1047.async.js → 2096.6d98fd12.async.js} +1 -1
  99. package/static/dist/2208.85285476.async.js +1 -0
  100. package/static/dist/2286.f371c743.async.js +1 -0
  101. package/static/dist/2476.4e9b0992.async.js +1 -0
  102. package/static/dist/2537.2b262ee0.async.js +1 -0
  103. package/static/dist/{255.12f03ab2.async.js → 255.8a80b983.async.js} +1 -1
  104. package/static/dist/2635.d4c59d23.async.js +1 -0
  105. package/static/dist/2808.cdc0995c.async.js +1 -0
  106. package/static/dist/{2821.be3dc88e.async.js → 2821.651f31e5.async.js} +1 -1
  107. package/static/dist/2986.4c49eef7.async.js +1 -0
  108. package/static/dist/300.08ac9875.async.js +1 -0
  109. package/static/dist/3191.545ab873.async.js +1 -0
  110. package/static/dist/3714.8d6dba9e.async.js +1 -0
  111. package/static/dist/3906.a5eee612.async.js +1 -0
  112. package/static/dist/{6541.a6d499de.async.js → 3948.4fe809fd.async.js} +1 -1
  113. package/static/dist/{5171.7fc6d0a2.async.js → 4573.16f19278.async.js} +1 -1
  114. package/static/dist/{4859.93e63ea6.async.js → 4859.6592cebb.async.js} +1 -1
  115. package/static/dist/4887.8e3ae573.async.js +1 -0
  116. package/static/dist/{4902.54ecbdb5.async.js → 4902.555f92ab.async.js} +1 -1
  117. package/static/dist/{4934.1ca6b6b0.async.js → 4934.f3539d08.async.js} +1 -1
  118. package/static/dist/5077.cbd111cd.async.js +1 -0
  119. package/static/dist/{6247.b550d996.async.js → 5157.7c5af144.async.js} +1 -1
  120. package/static/dist/{540.481d4708.async.js → 540.19ddf020.async.js} +1 -1
  121. package/static/dist/{5970.10ac4f16.async.js → 5970.d3a6e7bd.async.js} +1 -1
  122. package/static/dist/{6013.2d7bb12a.async.js → 6013.4e38de36.async.js} +1 -1
  123. package/static/dist/{6016.9c379049.async.js → 6016.1e6574b6.async.js} +1 -1
  124. package/static/dist/{6035.5889ddc7.async.js → 6035.32ebfad9.async.js} +1 -1
  125. package/static/dist/6339.ab305e96.async.js +1 -0
  126. package/static/dist/6569.55177f6a.async.js +1 -0
  127. package/static/dist/6610.c111af7e.async.js +1 -0
  128. package/static/dist/{3034.6413c38e.async.js → 6638.87a163d2.async.js} +1 -1
  129. package/static/dist/{6646.5fc37228.async.js → 6646.95e92533.async.js} +1 -1
  130. package/static/dist/6665.1d099ad1.async.js +1 -0
  131. package/static/dist/{7355.b7c0562f.async.js → 7355.f9f263d8.async.js} +1 -1
  132. package/static/dist/{7384.065ccae2.async.js → 7384.1bb449d5.async.js} +1 -1
  133. package/static/dist/7441.ee1bf2bb.async.js +1 -0
  134. package/static/dist/{7508.a31662a3.async.js → 7508.7dcee91c.async.js} +1 -1
  135. package/static/dist/{7802.6b73f16a.async.js → 7802.34255805.async.js} +1 -1
  136. package/static/dist/{7984.e6bb9378.async.js → 7984.594296a5.async.js} +1 -1
  137. package/static/dist/{5653.4fce7ce8.async.js → 8033.5cb31493.async.js} +1 -1
  138. package/static/dist/8147.2fb55202.async.js +1 -0
  139. package/static/dist/8187.48c130d6.async.js +1 -0
  140. package/static/dist/8495.d53e15ca.async.js +1 -0
  141. package/static/dist/8587.315b06c0.async.js +1 -0
  142. package/static/dist/8826.db34ad8d.async.js +1 -0
  143. package/static/dist/{2742.4852aac8.async.js → 8865.ed665d31.async.js} +1 -1
  144. package/static/dist/901.7ee5c6d3.async.js +1 -0
  145. package/static/dist/9271.231db2ce.async.js +1 -0
  146. package/static/dist/9323.a33f47da.async.js +1 -0
  147. package/static/dist/{9730.30083c91.async.js → 9730.801665a3.async.js} +1 -1
  148. package/static/dist/{9761.627ca3b5.async.js → 9761.360a19d8.async.js} +1 -1
  149. package/static/dist/index.html +2 -2
  150. package/static/dist/layouts__index.a7a2bfe0.async.js +1 -0
  151. package/static/dist/layouts__index.adf0692f.chunk.css +1 -0
  152. package/static/dist/preload_helper.3048fe5b.js +1 -0
  153. package/static/dist/{src__pages__config__index.622b6ee8.async.js → src__pages__config__index.a22ff7dc.async.js} +1 -1
  154. package/static/dist/{src__pages__crontab__const.323d5124.async.js → src__pages__crontab__const.aba07deb.async.js} +1 -1
  155. package/static/dist/src__pages__crontab__detail.b98f0084.async.js +1 -0
  156. package/static/dist/src__pages__crontab__index.68e78a33.async.js +1 -0
  157. package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.831d5e4b.async.js} +1 -1
  158. package/static/dist/src__pages__crontab__modal.f7041c7c.async.js +1 -0
  159. package/static/dist/src__pages__crontab__type.d7af36e5.async.js +1 -0
  160. package/static/dist/{src__pages__crontab__viewCreateModal.ffcf7a24.async.js → src__pages__crontab__viewCreateModal.4d589f66.async.js} +1 -1
  161. package/static/dist/{src__pages__crontab__viewManageModal.c2724575.async.js → src__pages__crontab__viewManageModal.0e317746.async.js} +1 -1
  162. package/static/dist/src__pages__dashboard__index.58177357.async.js +1 -0
  163. package/static/dist/src__pages__dependence__index.b7bbc795.async.js +1 -0
  164. package/static/dist/{src__pages__dependence__logModal.f123e2ac.async.js → src__pages__dependence__logModal.0681830b.async.js} +1 -1
  165. package/static/dist/src__pages__dependence__modal.f7bb47ba.async.js +1 -0
  166. package/static/dist/src__pages__env__editNameModal.48715576.async.js +1 -0
  167. package/static/dist/src__pages__env__index.452cdc47.async.js +1 -0
  168. package/static/dist/src__pages__env__modal.e1234834.async.js +1 -0
  169. package/static/dist/src__pages__error__index.dedb2b90.async.js +1 -0
  170. package/static/dist/src__pages__initialization__index.22620a77.async.js +1 -0
  171. package/static/dist/src__pages__log__index.9c66639f.async.js +1 -0
  172. package/static/dist/{src__pages__login__index.cd6e3152.async.js → src__pages__login__index.8c813eb1.async.js} +1 -1
  173. package/static/dist/{src__pages__script__components__UnsupportedFilePreview__index.39074c68.async.js → src__pages__script__components__UnsupportedFilePreview__index.c347a13a.async.js} +1 -1
  174. package/static/dist/src__pages__script__editNameModal.532a3044.async.js +1 -0
  175. package/static/dist/src__pages__script__index.1fc20f22.async.js +1 -0
  176. package/static/dist/src__pages__script__renameModal.5cdde919.async.js +1 -0
  177. package/static/dist/src__pages__script__saveModal.5ffed35f.async.js +1 -0
  178. package/static/dist/src__pages__script__setting.1a82c6d7.async.js +1 -0
  179. package/static/dist/src__pages__setting__appModal.43b7758a.async.js +1 -0
  180. package/static/dist/src__pages__setting__checkUpdate.34d773f2.async.js +1 -0
  181. package/static/dist/src__pages__setting__dependence.9c04c79a.async.js +1 -0
  182. package/static/dist/src__pages__setting__index.7e070838.async.js +1 -0
  183. package/static/dist/src__pages__setting__notification.bac481c2.async.js +1 -0
  184. package/static/dist/src__pages__setting__other.707cfafe.async.js +1 -0
  185. package/static/dist/src__pages__setting__security.b7235753.async.js +1 -0
  186. package/static/dist/src__pages__setting__systemLog.b81a8c1d.async.js +1 -0
  187. package/static/dist/{src__pages__subscription__logModal.0caa7283.async.js → src__pages__subscription__logModal.3864b37f.async.js} +1 -1
  188. package/static/dist/src__pages__subscription__modal.562448e2.async.js +1 -0
  189. package/static/dist/{umi.ef8199a4.js → umi.a54a59f6.js} +1 -1
  190. package/version.yaml +33 -4
  191. package/sample/notify.py.save +0 -1010
  192. package/static/dist/105.85a5c47a.async.js +0 -1
  193. package/static/dist/1083.f86ce804.async.js +0 -1
  194. package/static/dist/1147.32f41a88.async.js +0 -1
  195. package/static/dist/1352.ab6da08e.async.js +0 -1
  196. package/static/dist/1690.f0290540.async.js +0 -1
  197. package/static/dist/1742.6cbe5aca.async.js +0 -1
  198. package/static/dist/2208.8e3a7325.async.js +0 -1
  199. package/static/dist/3191.70bc19db.async.js +0 -1
  200. package/static/dist/5312.74b95311.async.js +0 -1
  201. package/static/dist/5691.931f59c5.async.js +0 -1
  202. package/static/dist/6159.55cb068a.async.js +0 -1
  203. package/static/dist/7025.f4080d63.async.js +0 -1
  204. package/static/dist/739.6be5552a.async.js +0 -1
  205. package/static/dist/7571.4f6240b1.async.js +0 -1
  206. package/static/dist/786.59fc381c.async.js +0 -1
  207. package/static/dist/8317.c44c1ebd.async.js +0 -1
  208. package/static/dist/8826.0291edfd.async.js +0 -1
  209. package/static/dist/955.3c9481f7.async.js +0 -1
  210. package/static/dist/layouts__index.1fce90e0.chunk.css +0 -1
  211. package/static/dist/layouts__index.8dcf1576.async.js +0 -1
  212. package/static/dist/preload_helper.116a62f6.js +0 -1
  213. package/static/dist/src__pages__crontab__detail.b07f0c0a.async.js +0 -1
  214. package/static/dist/src__pages__crontab__index.2e2e1096.async.js +0 -1
  215. package/static/dist/src__pages__crontab__modal.4d8c2a22.async.js +0 -1
  216. package/static/dist/src__pages__crontab__type.db7c1858.async.js +0 -1
  217. package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
  218. package/static/dist/src__pages__dependence__modal.631ffb5b.async.js +0 -1
  219. package/static/dist/src__pages__env__editNameModal.ff85ef8c.async.js +0 -1
  220. package/static/dist/src__pages__env__index.a0a2fece.async.js +0 -1
  221. package/static/dist/src__pages__env__modal.d1004662.async.js +0 -1
  222. package/static/dist/src__pages__error__index.1bc3c90b.async.js +0 -1
  223. package/static/dist/src__pages__initialization__index.8b1cbaf9.async.js +0 -1
  224. package/static/dist/src__pages__log__index.cf00c9af.async.js +0 -1
  225. package/static/dist/src__pages__script__editNameModal.53424d49.async.js +0 -1
  226. package/static/dist/src__pages__script__index.e65df827.async.js +0 -1
  227. package/static/dist/src__pages__script__renameModal.4bbe7fb1.async.js +0 -1
  228. package/static/dist/src__pages__script__saveModal.cf449f3c.async.js +0 -1
  229. package/static/dist/src__pages__script__setting.b345d59a.async.js +0 -1
  230. package/static/dist/src__pages__setting__appModal.03faec89.async.js +0 -1
  231. package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
  232. package/static/dist/src__pages__setting__dependence.4495c7b6.async.js +0 -1
  233. package/static/dist/src__pages__setting__index.6919c399.async.js +0 -1
  234. package/static/dist/src__pages__setting__notification.d6a3884f.async.js +0 -1
  235. package/static/dist/src__pages__setting__other.0d931d6f.async.js +0 -1
  236. package/static/dist/src__pages__setting__security.91cb545f.async.js +0 -1
  237. package/static/dist/src__pages__setting__systemLog.1d433a48.async.js +0 -1
  238. package/static/dist/src__pages__subscription__modal.0b84f6cf.async.js +0 -1
@@ -10,6 +10,7 @@ const multer_1 = __importDefault(require("multer"));
10
10
  const typedi_1 = require("typedi");
11
11
  const config_1 = __importDefault(require("../config"));
12
12
  const util_1 = require("../config/util");
13
+ const i18n_1 = require("../shared/i18n");
13
14
  const env_1 = __importDefault(require("../services/env"));
14
15
  const route = (0, express_1.Router)();
15
16
  const storage = multer_1.default.diskStorage({
@@ -21,6 +22,10 @@ const storage = multer_1.default.diskStorage({
21
22
  },
22
23
  });
23
24
  const upload = (0, multer_1.default)({ storage: storage });
25
+ const labelSchema = celebrate_1.Joi.array()
26
+ .items(celebrate_1.Joi.string().trim().required())
27
+ .min(1)
28
+ .required();
24
29
  exports.default = (app) => {
25
30
  app.use('/envs', route);
26
31
  route.get('/', async (req, res, next) => {
@@ -42,6 +47,7 @@ exports.default = (app) => {
42
47
  .required()
43
48
  .pattern(/^[a-zA-Z_][0-9a-zA-Z_]*$/),
44
49
  remarks: celebrate_1.Joi.string().optional().allow(''),
50
+ labels: celebrate_1.Joi.array().items(celebrate_1.Joi.string().trim()).optional().allow(null),
45
51
  })),
46
52
  }), async (req, res, next) => {
47
53
  var _a;
@@ -49,7 +55,7 @@ exports.default = (app) => {
49
55
  try {
50
56
  const envService = typedi_1.Container.get(env_1.default);
51
57
  if (!((_a = req.body) === null || _a === void 0 ? void 0 : _a.length)) {
52
- return res.send({ code: 400, message: '参数不正确' });
58
+ return res.send({ code: 400, message: (0, i18n_1.t)('参数不正确') });
53
59
  }
54
60
  const data = await envService.create(req.body);
55
61
  return res.send({ code: 200, data });
@@ -64,6 +70,7 @@ exports.default = (app) => {
64
70
  name: celebrate_1.Joi.string().required(),
65
71
  remarks: celebrate_1.Joi.string().optional().allow('').allow(null),
66
72
  id: celebrate_1.Joi.number().required(),
73
+ labels: celebrate_1.Joi.array().items(celebrate_1.Joi.string().trim()).optional().allow(null),
67
74
  }),
68
75
  }), async (req, res, next) => {
69
76
  const logger = typedi_1.Container.get('logger');
@@ -190,6 +197,36 @@ exports.default = (app) => {
190
197
  return next(e);
191
198
  }
192
199
  });
200
+ route.post('/labels', (0, celebrate_1.celebrate)({
201
+ body: celebrate_1.Joi.object({
202
+ ids: celebrate_1.Joi.array().items(celebrate_1.Joi.number().required()).min(1).required(),
203
+ labels: labelSchema,
204
+ }),
205
+ }), async (req, res, next) => {
206
+ try {
207
+ const envService = typedi_1.Container.get(env_1.default);
208
+ const data = await envService.addLabels(req.body.ids, req.body.labels);
209
+ return res.send({ code: 200, data });
210
+ }
211
+ catch (e) {
212
+ return next(e);
213
+ }
214
+ });
215
+ route.delete('/labels', (0, celebrate_1.celebrate)({
216
+ body: celebrate_1.Joi.object({
217
+ ids: celebrate_1.Joi.array().items(celebrate_1.Joi.number().required()).min(1).required(),
218
+ labels: labelSchema,
219
+ }),
220
+ }), async (req, res, next) => {
221
+ try {
222
+ const envService = typedi_1.Container.get(env_1.default);
223
+ const data = await envService.removeLabels(req.body.ids, req.body.labels);
224
+ return res.send({ code: 200, data });
225
+ }
226
+ catch (e) {
227
+ return next(e);
228
+ }
229
+ });
193
230
  route.post('/upload', upload.single('env'), async (req, res, next) => {
194
231
  const logger = typedi_1.Container.get('logger');
195
232
  try {
@@ -204,13 +241,14 @@ exports.default = (app) => {
204
241
  name: x.name,
205
242
  value: x.value,
206
243
  remarks: x.remarks,
244
+ labels: x.labels,
207
245
  })));
208
246
  return res.send({ code: 200, data: result });
209
247
  }
210
248
  else {
211
249
  return res.send({
212
250
  code: 400,
213
- message: '每条数据 name 或者 value 字段不能为空,参考导出文件格式',
251
+ message: (0, i18n_1.t)('每条数据 name 或者 value 字段不能为空,参考导出文件格式'),
214
252
  });
215
253
  }
216
254
  }
@@ -15,6 +15,7 @@ const dependence_1 = __importDefault(require("./dependence"));
15
15
  const system_1 = __importDefault(require("./system"));
16
16
  const subscription_1 = __importDefault(require("./subscription"));
17
17
  const update_1 = __importDefault(require("./update"));
18
+ const dashboard_1 = __importDefault(require("./dashboard"));
18
19
  const health_1 = __importDefault(require("./health"));
19
20
  exports.default = () => {
20
21
  const app = (0, express_1.Router)();
@@ -29,6 +30,7 @@ exports.default = () => {
29
30
  (0, system_1.default)(app);
30
31
  (0, subscription_1.default)(app);
31
32
  (0, update_1.default)(app);
33
+ (0, dashboard_1.default)(app);
32
34
  (0, health_1.default)(app);
33
35
  return app;
34
36
  };
@@ -7,8 +7,10 @@ const celebrate_1 = require("celebrate");
7
7
  const express_1 = require("express");
8
8
  const typedi_1 = require("typedi");
9
9
  const config_1 = __importDefault(require("../config"));
10
+ const i18n_1 = require("../shared/i18n");
10
11
  const util_1 = require("../config/util");
11
12
  const log_1 = __importDefault(require("../services/log"));
13
+ const runningInstance_1 = require("../data/runningInstance");
12
14
  const route = (0, express_1.Router)();
13
15
  const blacklist = ['.tmp'];
14
16
  exports.default = (app) => {
@@ -34,11 +36,19 @@ exports.default = (app) => {
34
36
  if (!finalPath || blacklist.includes(req.query.path)) {
35
37
  return res.send({
36
38
  code: 403,
37
- message: '暂无权限',
39
+ message: (0, i18n_1.t)('暂无权限'),
38
40
  });
39
41
  }
42
+ const logPath = `${req.query.path}/${req.query.file}`;
43
+ const runningInstance = await runningInstance_1.RunningInstanceModel.findOne({
44
+ where: { log_path: logPath, status: runningInstance_1.InstanceStatus.running },
45
+ });
40
46
  const content = await (0, util_1.getFileContentByName)(finalPath);
41
- res.send({ code: 200, data: (0, util_1.removeAnsi)(content) });
47
+ res.send({
48
+ code: 200,
49
+ data: (0, util_1.removeAnsi)(content),
50
+ logStatus: runningInstance ? 'running' : undefined,
51
+ });
42
52
  }
43
53
  catch (e) {
44
54
  return next(e);
@@ -51,7 +61,7 @@ exports.default = (app) => {
51
61
  if (!finalPath || blacklist.includes(req.query.path)) {
52
62
  return res.send({
53
63
  code: 403,
54
- message: '暂无权限',
64
+ message: (0, i18n_1.t)('暂无权限'),
55
65
  });
56
66
  }
57
67
  const content = await (0, util_1.getFileContentByName)(finalPath);
@@ -75,7 +85,7 @@ exports.default = (app) => {
75
85
  if (!finalPath || blacklist.includes(path)) {
76
86
  return res.send({
77
87
  code: 403,
78
- message: '暂无权限',
88
+ message: (0, i18n_1.t)('暂无权限'),
79
89
  });
80
90
  }
81
91
  await (0, util_1.rmPath)(finalPath);
@@ -98,7 +108,7 @@ exports.default = (app) => {
98
108
  if (!filePath) {
99
109
  return res.send({
100
110
  code: 403,
101
- message: '暂无权限',
111
+ message: (0, i18n_1.t)('暂无权限'),
102
112
  });
103
113
  }
104
114
  return res.download(filePath, filename, (err) => {
@@ -32,11 +32,16 @@ const typedi_1 = require("typedi");
32
32
  const config_1 = __importDefault(require("../config"));
33
33
  const fs = __importStar(require("fs/promises"));
34
34
  const celebrate_1 = require("celebrate");
35
- const path_1 = require("path");
35
+ const path_1 = __importStar(require("path"));
36
36
  const script_1 = __importDefault(require("../services/script"));
37
+ const i18n_1 = require("../shared/i18n");
37
38
  const multer_1 = __importDefault(require("multer"));
38
39
  const utils_1 = require("../shared/utils");
39
40
  const route = (0, express_1.Router)();
41
+ function isPathAllowed(targetPath) {
42
+ const resolved = path_1.default.resolve(targetPath);
43
+ return config_1.default.writePathList.some((x) => resolved.startsWith(x));
44
+ }
40
45
  const storage = multer_1.default.diskStorage({
41
46
  destination: function (req, file, cb) {
42
47
  cb(null, config_1.default.scriptPath);
@@ -145,23 +150,34 @@ exports.default = (app) => {
145
150
  if (config_1.default.writePathList.every((x) => !path.startsWith(x))) {
146
151
  return res.send({
147
152
  code: 403,
148
- message: '暂无权限',
153
+ message: (0, i18n_1.t)('暂无权限'),
149
154
  });
150
155
  }
151
156
  if (req.file) {
152
- await fs.rename(req.file.path, (0, path_1.join)(path, filename));
157
+ const uploadPath = (0, path_1.join)(path, filename);
158
+ if (!isPathAllowed(uploadPath)) {
159
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
160
+ }
161
+ await fs.rename(req.file.path, uploadPath);
153
162
  return res.send({ code: 200 });
154
163
  }
155
164
  if (directory) {
156
- await fs.mkdir((0, path_1.join)(path, directory), { recursive: true });
165
+ const dirPath = (0, path_1.join)(path, directory);
166
+ if (!isPathAllowed(dirPath)) {
167
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
168
+ }
169
+ await fs.mkdir(dirPath, { recursive: true });
157
170
  return res.send({ code: 200 });
158
171
  }
159
172
  if (!originFilename) {
160
173
  originFilename = filename;
161
174
  }
162
- const originFilePath = (0, path_1.join)(path, `${originFilename.replace(/\//g, '')}`);
175
+ const originFilePath = (0, path_1.join)(path, originFilename);
176
+ const filePath = (0, path_1.join)(path, filename);
177
+ if (!isPathAllowed(filePath) || !isPathAllowed(originFilePath)) {
178
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
179
+ }
163
180
  await fs.mkdir(path, { recursive: true });
164
- const filePath = (0, path_1.join)(path, `${filename.replace(/\//g, '')}`);
165
181
  const fileExists = await (0, util_1.fileExist)(filePath);
166
182
  if (fileExists) {
167
183
  await fs.copyFile(originFilePath, (0, path_1.join)(config_1.default.bakPath, originFilename.replace(/\//g, '')));
@@ -190,7 +206,7 @@ exports.default = (app) => {
190
206
  if (!filePath) {
191
207
  return res.send({
192
208
  code: 403,
193
- message: '暂无权限',
209
+ message: (0, i18n_1.t)('暂无权限'),
194
210
  });
195
211
  }
196
212
  await (0, utils_1.writeFileWithLock)(filePath, content);
@@ -217,7 +233,7 @@ exports.default = (app) => {
217
233
  if (!filePath) {
218
234
  return res.send({
219
235
  code: 403,
220
- message: '暂无权限',
236
+ message: (0, i18n_1.t)('暂无权限'),
221
237
  });
222
238
  }
223
239
  await (0, util_1.rmPath)(filePath);
@@ -243,7 +259,7 @@ exports.default = (app) => {
243
259
  if (!filePath) {
244
260
  return res.send({
245
261
  code: 403,
246
- message: '暂无权限',
262
+ message: (0, i18n_1.t)('暂无权限'),
247
263
  });
248
264
  }
249
265
  return res.download(filePath, filename, (err) => {
@@ -271,6 +287,9 @@ exports.default = (app) => {
271
287
  }
272
288
  const { name, ext } = (0, path_1.parse)(filename);
273
289
  const filePath = (0, path_1.join)(config_1.default.scriptPath, path, `${name}.swap${ext}`);
290
+ if (!isPathAllowed(filePath)) {
291
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
292
+ }
274
293
  await (0, utils_1.writeFileWithLock)(filePath, content || '');
275
294
  const scriptService = typedi_1.Container.get(script_1.default);
276
295
  const result = await scriptService.runScript(filePath);
@@ -294,6 +313,9 @@ exports.default = (app) => {
294
313
  }
295
314
  const { name, ext } = (0, path_1.parse)(filename);
296
315
  const filePath = (0, path_1.join)(config_1.default.scriptPath, path, `${name}.swap${ext}`);
316
+ if (!isPathAllowed(filePath)) {
317
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
318
+ }
297
319
  const logPath = (0, path_1.join)(config_1.default.logPath, path, `${name}.swap`);
298
320
  const scriptService = typedi_1.Container.get(script_1.default);
299
321
  const result = await scriptService.stopScript(filePath, pid);
@@ -320,6 +342,9 @@ exports.default = (app) => {
320
342
  }
321
343
  const filePath = (0, path_1.join)(config_1.default.scriptPath, path, filename);
322
344
  const newPath = (0, path_1.join)(config_1.default.scriptPath, path, newFilename);
345
+ if (!isPathAllowed(filePath) || !isPathAllowed(newPath)) {
346
+ return res.send({ code: 403, message: (0, i18n_1.t)('暂无权限') });
347
+ }
323
348
  await fs.rename(filePath, newPath);
324
349
  res.send({ code: 200 });
325
350
  }
@@ -9,6 +9,8 @@ const config_1 = __importDefault(require("../config"));
9
9
  const system_1 = __importDefault(require("../services/system"));
10
10
  const celebrate_1 = require("celebrate");
11
11
  const user_1 = __importDefault(require("../services/user"));
12
+ const i18n_1 = require("../shared/i18n");
13
+ const auth_1 = require("../shared/auth");
12
14
  const util_1 = require("../config/util");
13
15
  const dayjs_1 = __importDefault(require("dayjs"));
14
16
  const multer_1 = __importDefault(require("multer"));
@@ -31,12 +33,7 @@ exports.default = (app) => {
31
33
  const userService = typedi_1.Container.get(user_1.default);
32
34
  const authInfo = await userService.getAuthInfo();
33
35
  const { version, changeLog, changeLogLink, publishTime } = await (0, util_1.parseVersion)(config_1.default.versionFile);
34
- let isInitialized = true;
35
- if (Object.keys(authInfo).length === 2 &&
36
- authInfo.username === 'admin' &&
37
- authInfo.password === 'admin') {
38
- isInitialized = false;
39
- }
36
+ const isInitialized = !(0, auth_1.isDefaultAuthInfo)(authInfo);
40
37
  res.send({
41
38
  code: 200,
42
39
  data: {
@@ -315,8 +312,11 @@ exports.default = (app) => {
315
312
  }), async (req, res, next) => {
316
313
  try {
317
314
  const userService = typedi_1.Container.get(user_1.default);
318
- await userService.resetAuthInfo(req.body);
319
- res.send({ code: 200, message: '更新成功' });
315
+ const result = await userService.resetAuthInfo(req.body);
316
+ if (result) {
317
+ return res.send(result);
318
+ }
319
+ res.send({ code: 200, message: (0, i18n_1.t)('更新成功') });
320
320
  }
321
321
  catch (e) {
322
322
  return next(e);
@@ -336,6 +336,20 @@ exports.default = (app) => {
336
336
  return next(e);
337
337
  }
338
338
  });
339
+ route.put('/config/lang', (0, celebrate_1.celebrate)({
340
+ body: celebrate_1.Joi.object({
341
+ lang: celebrate_1.Joi.string().allow('').allow(null),
342
+ }),
343
+ }), async (req, res, next) => {
344
+ try {
345
+ const systemService = typedi_1.Container.get(system_1.default);
346
+ const result = await systemService.updateLanguage(req.body);
347
+ res.send(result);
348
+ }
349
+ catch (e) {
350
+ return next(e);
351
+ }
352
+ });
339
353
  route.put('/config/global-ssh-key', (0, celebrate_1.celebrate)({
340
354
  body: celebrate_1.Joi.object({
341
355
  globalSshKey: celebrate_1.Joi.string().allow('').allow(null),
@@ -12,6 +12,7 @@ const path_1 = __importDefault(require("path"));
12
12
  const uuid_1 = require("uuid");
13
13
  const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
14
14
  const config_1 = __importDefault(require("../config"));
15
+ const i18n_1 = require("../shared/i18n");
15
16
  const util_1 = require("../config/util");
16
17
  const route = (0, express_1.Router)();
17
18
  const storage = multer_1.default.diskStorage({
@@ -66,11 +67,11 @@ exports.default = (app) => {
66
67
  }), async (req, res, next) => {
67
68
  try {
68
69
  if ((0, util_1.isDemoEnv)()) {
69
- return res.send({ code: 450, message: '未知错误' });
70
+ return res.send({ code: 450, message: (0, i18n_1.t)('未知错误') });
70
71
  }
71
72
  const userService = typedi_1.Container.get(user_1.default);
72
73
  await userService.updateUsernameAndPassword(req.body);
73
- res.send({ code: 200, message: '更新成功' });
74
+ res.send({ code: 200, message: (0, i18n_1.t)('更新成功') });
74
75
  }
75
76
  catch (e) {
76
77
  return next(e);
@@ -121,11 +122,11 @@ exports.default = (app) => {
121
122
  return next(e);
122
123
  }
123
124
  });
124
- route.put('/two-factor/deactive', async (req, res, next) => {
125
+ route.put('/two-factor/deactivate', async (req, res, next) => {
125
126
  const logger = typedi_1.Container.get('logger');
126
127
  try {
127
128
  const userService = typedi_1.Container.get(user_1.default);
128
- const data = await userService.deactiveTwoFactor();
129
+ const data = await userService.deactivateTwoFactor();
129
130
  res.send({ code: 200, data });
130
131
  }
131
132
  catch (e) {
@@ -192,7 +193,7 @@ exports.default = (app) => {
192
193
  try {
193
194
  const userService = typedi_1.Container.get(user_1.default);
194
195
  await userService.updateUsernameAndPassword(req.body);
195
- res.send({ code: 200, message: '更新成功' });
196
+ res.send({ code: 200, message: (0, i18n_1.t)('更新成功') });
196
197
  }
197
198
  catch (e) {
198
199
  return next(e);
@@ -72,37 +72,37 @@ class Application {
72
72
  // Wait for gRPC worker to signal it's ready before starting HTTP worker
73
73
  this.waitForWorkerReady(grpcWorker, 30000)
74
74
  .then(() => {
75
- logger_1.default.info('✌️ gRPC worker is ready, starting HTTP worker');
75
+ logger_1.default.info('[boot] gRPC worker is ready, starting HTTP worker');
76
76
  this.httpWorker = this.forkWorker('http');
77
77
  })
78
78
  .catch((error) => {
79
- logger_1.default.error('✌️ Failed to wait for gRPC worker:', error);
79
+ logger_1.default.error('[boot] Failed to wait for gRPC worker:', error);
80
80
  process.exit(1);
81
81
  });
82
82
  cluster_1.default.on('exit', (worker, code, signal) => {
83
83
  const metadata = this.workerMetadataMap.get(worker.id);
84
84
  if (metadata) {
85
85
  if (!this.isShuttingDown) {
86
- logger_1.default.error(`✌️ ${metadata.serviceType} worker ${worker.process.pid} died (${signal || code}). Restarting...`);
86
+ logger_1.default.error(`${metadata.serviceType} worker ${worker.process.pid} died (${signal || code}). Restarting...`);
87
87
  // If gRPC worker died, restart it and wait for it to be ready
88
88
  if (metadata.serviceType === 'grpc') {
89
89
  const newGrpcWorker = this.forkWorker('grpc');
90
90
  this.waitForWorkerReady(newGrpcWorker, 30000)
91
91
  .then(() => {
92
- logger_1.default.info('✌️ gRPC worker restarted and ready');
92
+ logger_1.default.info('gRPC worker restarted and ready');
93
93
  // Re-register cron jobs by notifying the HTTP worker
94
94
  if (this.httpWorker) {
95
95
  try {
96
96
  this.httpWorker.send('reregister-crons');
97
- logger_1.default.info('✌️ Sent reregister-crons message to HTTP worker');
97
+ logger_1.default.info('Sent reregister-crons message to HTTP worker');
98
98
  }
99
99
  catch (error) {
100
- logger_1.default.error('✌️ Failed to send reregister-crons message:', error);
100
+ logger_1.default.error('Failed to send reregister-crons message:', error);
101
101
  }
102
102
  }
103
103
  })
104
104
  .catch((error) => {
105
- logger_1.default.error('✌️ Failed to restart gRPC worker:', error);
105
+ logger_1.default.error('Failed to restart gRPC worker:', error);
106
106
  process.exit(1);
107
107
  });
108
108
  }
@@ -110,7 +110,7 @@ class Application {
110
110
  // For HTTP worker, just restart it
111
111
  const newWorker = this.forkWorker(metadata.serviceType);
112
112
  this.httpWorker = newWorker;
113
- logger_1.default.info(`✌️ Restarted ${metadata.serviceType} worker (PID: ${newWorker.process.pid})`);
113
+ logger_1.default.info(`Restarted ${metadata.serviceType} worker (PID: ${newWorker.process.pid})`);
114
114
  }
115
115
  }
116
116
  this.workerMetadataMap.delete(worker.id);
@@ -168,14 +168,14 @@ class Application {
168
168
  if (worker) {
169
169
  const exitPromise = new Promise((resolve) => {
170
170
  worker.once('exit', () => {
171
- logger_1.default.info(`✌️ Worker ${worker.process.pid} exited`);
171
+ logger_1.default.info(`Worker ${worker.process.pid} exited`);
172
172
  resolve();
173
173
  });
174
174
  try {
175
175
  worker.send('shutdown');
176
176
  }
177
177
  catch (error) {
178
- logger_1.default.warn(`✌️ Failed to send shutdown to worker ${worker.process.pid}:`, error);
178
+ logger_1.default.warn(`Failed to send shutdown to worker ${worker.process.pid}:`, error);
179
179
  }
180
180
  });
181
181
  workerPromises.push(exitPromise);
@@ -186,7 +186,7 @@ class Application {
186
186
  Promise.all(workerPromises),
187
187
  new Promise((resolve) => {
188
188
  setTimeout(() => {
189
- logger_1.default.warn('✌️ Worker shutdown timeout reached');
189
+ logger_1.default.warn('Worker shutdown timeout reached');
190
190
  resolve();
191
191
  }, 10000);
192
192
  }),
@@ -194,7 +194,7 @@ class Application {
194
194
  process.exit(0);
195
195
  }
196
196
  catch (error) {
197
- logger_1.default.error('✌️ Error during worker shutdown:', error);
197
+ logger_1.default.error('Error during worker shutdown:', error);
198
198
  process.exit(1);
199
199
  }
200
200
  };
@@ -205,10 +205,10 @@ class Application {
205
205
  var _a;
206
206
  const serviceType = process.env.SERVICE_TYPE;
207
207
  if (!serviceType || !['http', 'grpc'].includes(serviceType)) {
208
- logger_1.default.error('✌️ Invalid SERVICE_TYPE:', serviceType);
208
+ logger_1.default.error('[boot] Invalid SERVICE_TYPE:', serviceType);
209
209
  process.exit(1);
210
210
  }
211
- logger_1.default.info(`✌️ ${serviceType} worker started (PID: ${process.pid})`);
211
+ logger_1.default.info(`[boot] ${serviceType} worker started (PID: ${process.pid})`);
212
212
  try {
213
213
  if (serviceType === 'http') {
214
214
  await this.startHttpService();
@@ -219,11 +219,14 @@ class Application {
219
219
  (_a = process.send) === null || _a === void 0 ? void 0 : _a.call(process, 'ready');
220
220
  }
221
221
  catch (error) {
222
- logger_1.default.error(`✌️ ${serviceType} worker failed:`, error);
222
+ logger_1.default.error(`[boot] ${serviceType} worker failed:`, error);
223
223
  process.exit(1);
224
224
  }
225
225
  }
226
226
  async startHttpService() {
227
+ // 在导入任何 gRPC 客户端模块之前初始化 mTLS 证书
228
+ const { initGrpcCerts } = await Promise.resolve().then(() => __importStar(require('./config/grpcCerts')));
229
+ await initGrpcCerts();
227
230
  this.setupMiddlewares();
228
231
  const { HttpServerService } = await Promise.resolve().then(() => __importStar(require('./services/http')));
229
232
  this.httpServerService = typedi_1.Container.get(HttpServerService);
@@ -248,14 +251,14 @@ class Application {
248
251
  else if (msg === 'reregister-crons' && serviceType === 'http') {
249
252
  // Re-register cron jobs when gRPC worker restarts
250
253
  try {
251
- logger_1.default.info('✌️ Received reregister-crons message, re-registering cron jobs...');
254
+ logger_1.default.info('[boot] Received reregister-crons message, re-registering cron jobs...');
252
255
  const CronService = (await Promise.resolve().then(() => __importStar(require('./services/cron')))).default;
253
256
  const cronService = typedi_1.Container.get(CronService);
254
257
  await cronService.autosave_crontab();
255
- logger_1.default.info('✌️ Cron jobs re-registered successfully');
258
+ logger_1.default.info('[boot] Cron jobs re-registered successfully');
256
259
  }
257
260
  catch (error) {
258
- logger_1.default.error('✌️ Failed to re-register cron jobs:', error);
261
+ logger_1.default.error('[boot] Failed to re-register cron jobs:', error);
259
262
  }
260
263
  }
261
264
  });
@@ -278,7 +281,7 @@ class Application {
278
281
  process.exit(0);
279
282
  }
280
283
  catch (error) {
281
- logger_1.default.error(`✌️ [${serviceType}] Error during shutdown:`, error);
284
+ logger_1.default.error(`[${serviceType}] Error during shutdown:`, error);
282
285
  process.exit(1);
283
286
  }
284
287
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LINUX_DEPENDENCE_COMMAND = exports.NotificationModeStringMap = exports.PYTHON_INSTALL_DIR = exports.SAMPLE_FILES = exports.QL_PREFIX = exports.TASK_PREFIX = exports.QL_COMMAND = exports.TASK_COMMAND = exports.LOG_END_SYMBOL = void 0;
4
+ const container_1 = require("./container");
4
5
  exports.LOG_END_SYMBOL = '     ';
5
6
  exports.TASK_COMMAND = 'task';
6
7
  exports.QL_COMMAND = 'ql';
@@ -46,20 +47,21 @@ exports.NotificationModeStringMap = {
46
47
  18: 'chronocat',
47
48
  19: 'ntfy',
48
49
  20: 'wxPusherBot',
50
+ 21: 'wxPusherSpt',
49
51
  };
50
52
  exports.LINUX_DEPENDENCE_COMMAND = {
51
53
  Debian: {
52
- install: 'apt-get install -y',
53
- uninstall: 'apt-get remove -y',
54
- info: 'dpkg-query -s',
54
+ install: (0, container_1.maybeSudo)('apt-get install -y'),
55
+ uninstall: (0, container_1.maybeSudo)('apt-get remove -y'),
56
+ info: (0, container_1.maybeSudo)('dpkg-query -s'),
55
57
  check(info) {
56
58
  return info.includes('install ok installed');
57
59
  },
58
60
  },
59
61
  Ubuntu: {
60
- install: 'apt-get install -y',
61
- uninstall: 'apt-get remove -y',
62
- info: 'dpkg-query -s',
62
+ install: (0, container_1.maybeSudo)('apt-get install -y'),
63
+ uninstall: (0, container_1.maybeSudo)('apt-get remove -y'),
64
+ info: (0, container_1.maybeSudo)('dpkg-query -s'),
63
65
  check(info) {
64
66
  return info.includes('install ok installed');
65
67
  },
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maybeSudo = exports.isInContainer = void 0;
4
+ function isInContainer() {
5
+ return process.env.QL_CONTAINER === 'true';
6
+ }
7
+ exports.isInContainer = isInContainer;
8
+ function maybeSudo(cmd) {
9
+ return isInContainer() ? `sudo ${cmd}` : cmd;
10
+ }
11
+ exports.maybeSudo = maybeSudo;
12
+ //# sourceMappingURL=container.js.map