@whyour/qinglong 2.18.2-5 → 2.18.3-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.
@@ -1,4 +1,4 @@
1
- FROM node:20-slim AS nodebuilder
1
+ FROM node:22-slim AS nodebuilder
2
2
 
3
3
  FROM python:3.10-slim-bookworm AS builder
4
4
  COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
package/docker/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20-slim AS nodebuilder
1
+ FROM node:22-slim AS nodebuilder
2
2
 
3
3
  FROM python:3.11-slim-bookworm AS builder
4
4
  COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whyour/qinglong",
3
- "version": "2.18.2-5",
3
+ "version": "2.18.3-0",
4
4
  "description": "Timed task management platform supporting Python3, JavaScript, Shell, Typescript",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,9 +14,6 @@ class GrpcClient {
14
14
  },
15
15
  grpcOptions: {
16
16
  'grpc.enable_http_proxy': 0,
17
- 'grpc.keepalive_time_ms': 120000,
18
- 'grpc.keepalive_timeout_ms': 20000,
19
- 'grpc.max_receive_message_length': 100 * 1024 * 1024,
20
17
  },
21
18
  defaultTimeout: 30000,
22
19
  };
@@ -59,23 +56,12 @@ class GrpcClient {
59
56
  grpc.credentials.createInsecure(),
60
57
  grpcOptions,
61
58
  );
62
-
63
- this.#checkConnection();
64
59
  } catch (error) {
65
60
  console.error('Failed to initialize gRPC client:', error);
66
61
  process.exit(1);
67
62
  }
68
63
  }
69
64
 
70
- #checkConnection() {
71
- this.#client.waitForReady(Date.now() + 5000, (error) => {
72
- if (error) {
73
- console.error('gRPC client connection failed:', error);
74
- process.exit(1);
75
- }
76
- });
77
- }
78
-
79
65
  #promisifyMethod(methodName) {
80
66
  const capitalizedMethod =
81
67
  methodName.charAt(0).toUpperCase() + methodName.slice(1);
@@ -3,12 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const celebrate_1 = require("celebrate");
6
7
  const express_1 = require("express");
7
8
  const typedi_1 = require("typedi");
8
9
  const config_1 = __importDefault(require("../config"));
9
10
  const util_1 = require("../config/util");
10
- const path_1 = require("path");
11
- const celebrate_1 = require("celebrate");
11
+ const log_1 = __importDefault(require("../services/log"));
12
12
  const route = (0, express_1.Router)();
13
13
  const blacklist = ['.tmp'];
14
14
  exports.default = (app) => {
@@ -29,10 +29,13 @@ exports.default = (app) => {
29
29
  });
30
30
  route.get('/detail', async (req, res, next) => {
31
31
  try {
32
- const finalPath = (0, path_1.resolve)(config_1.default.logPath, req.query.path || '', req.query.file || '');
33
- if (blacklist.includes(req.query.path) ||
34
- !finalPath.startsWith(config_1.default.logPath)) {
35
- return res.send({ code: 403, message: '暂无权限' });
32
+ const logService = typedi_1.Container.get(log_1.default);
33
+ const finalPath = logService.checkFilePath(req.query.path || '', req.query.file || '');
34
+ if (!finalPath || blacklist.includes(req.query.path)) {
35
+ return res.send({
36
+ code: 403,
37
+ message: '暂无权限',
38
+ });
36
39
  }
37
40
  const content = await (0, util_1.getFileContentByName)(finalPath);
38
41
  res.send({ code: 200, data: (0, util_1.removeAnsi)(content) });
@@ -43,10 +46,13 @@ exports.default = (app) => {
43
46
  });
44
47
  route.get('/:file', async (req, res, next) => {
45
48
  try {
46
- const finalPath = (0, path_1.resolve)(config_1.default.logPath, req.query.path || '', req.params.file || '');
47
- if (blacklist.includes(req.path) ||
48
- !finalPath.startsWith(config_1.default.logPath)) {
49
- return res.send({ code: 403, message: '暂无权限' });
49
+ const logService = typedi_1.Container.get(log_1.default);
50
+ const finalPath = logService.checkFilePath(req.query.path || '', req.query.file || '');
51
+ if (!finalPath || blacklist.includes(req.query.path)) {
52
+ return res.send({
53
+ code: 403,
54
+ message: '暂无权限',
55
+ });
50
56
  }
51
57
  const content = await (0, util_1.getFileContentByName)(finalPath);
52
58
  res.send({ code: 200, data: content });
@@ -63,14 +69,47 @@ exports.default = (app) => {
63
69
  }),
64
70
  }), async (req, res, next) => {
65
71
  try {
66
- let { filename, path, type } = req.body;
67
- const filePath = (0, path_1.join)(config_1.default.logPath, path, filename);
68
- await (0, util_1.rmPath)(filePath);
72
+ let { filename, path } = req.body;
73
+ const logService = typedi_1.Container.get(log_1.default);
74
+ const finalPath = logService.checkFilePath(filename, path);
75
+ if (!finalPath || blacklist.includes(path)) {
76
+ return res.send({
77
+ code: 403,
78
+ message: '暂无权限',
79
+ });
80
+ }
81
+ await (0, util_1.rmPath)(finalPath);
69
82
  res.send({ code: 200 });
70
83
  }
71
84
  catch (e) {
72
85
  return next(e);
73
86
  }
74
87
  });
88
+ route.post('/download', (0, celebrate_1.celebrate)({
89
+ body: celebrate_1.Joi.object({
90
+ filename: celebrate_1.Joi.string().required(),
91
+ path: celebrate_1.Joi.string().allow(''),
92
+ }),
93
+ }), async (req, res, next) => {
94
+ try {
95
+ let { filename, path } = req.body;
96
+ const logService = typedi_1.Container.get(log_1.default);
97
+ const filePath = logService.checkFilePath(path, filename);
98
+ if (!filePath) {
99
+ return res.send({
100
+ code: 403,
101
+ message: '暂无权限',
102
+ });
103
+ }
104
+ return res.download(filePath, filename, (err) => {
105
+ if (err) {
106
+ return next(err);
107
+ }
108
+ });
109
+ }
110
+ catch (e) {
111
+ return next(e);
112
+ }
113
+ });
75
114
  };
76
115
  //# sourceMappingURL=log.js.map
@@ -105,7 +105,6 @@ exports.default = (app) => {
105
105
  }
106
106
  });
107
107
  route.post('/', upload.single('file'), async (req, res, next) => {
108
- const logger = typedi_1.Container.get('logger');
109
108
  try {
110
109
  let { filename, path, content, originFilename, directory } = req.body;
111
110
  if (!path) {
@@ -119,8 +118,8 @@ exports.default = (app) => {
119
118
  }
120
119
  if (config_1.default.writePathList.every((x) => !path.startsWith(x))) {
121
120
  return res.send({
122
- code: 430,
123
- message: '文件路径禁止访问',
121
+ code: 403,
122
+ message: '暂无权限',
124
123
  });
125
124
  }
126
125
  if (req.file) {
@@ -157,10 +156,16 @@ exports.default = (app) => {
157
156
  content: celebrate_1.Joi.string().required().allow(''),
158
157
  }),
159
158
  }), async (req, res, next) => {
160
- const logger = typedi_1.Container.get('logger');
161
159
  try {
162
160
  let { filename, content, path } = req.body;
163
- const filePath = (0, path_1.join)(config_1.default.scriptPath, path, filename);
161
+ const scriptService = typedi_1.Container.get(script_1.default);
162
+ const filePath = scriptService.checkFilePath(path, filename);
163
+ if (!filePath) {
164
+ return res.send({
165
+ code: 403,
166
+ message: '暂无权限',
167
+ });
168
+ }
164
169
  await (0, utils_1.writeFileWithLock)(filePath, content);
165
170
  return res.send({ code: 200 });
166
171
  }
@@ -172,13 +177,18 @@ exports.default = (app) => {
172
177
  body: celebrate_1.Joi.object({
173
178
  filename: celebrate_1.Joi.string().required(),
174
179
  path: celebrate_1.Joi.string().allow(''),
175
- type: celebrate_1.Joi.string().optional(),
176
180
  }),
177
181
  }), async (req, res, next) => {
178
- const logger = typedi_1.Container.get('logger');
179
182
  try {
180
- let { filename, path, type } = req.body;
181
- const filePath = (0, path_1.join)(config_1.default.scriptPath, path, filename);
183
+ let { filename, path } = req.body;
184
+ const scriptService = typedi_1.Container.get(script_1.default);
185
+ const filePath = scriptService.checkFilePath(path, filename);
186
+ if (!filePath) {
187
+ return res.send({
188
+ code: 403,
189
+ message: '暂无权限',
190
+ });
191
+ }
182
192
  await (0, util_1.rmPath)(filePath);
183
193
  res.send({ code: 200 });
184
194
  }
@@ -189,21 +199,23 @@ exports.default = (app) => {
189
199
  route.post('/download', (0, celebrate_1.celebrate)({
190
200
  body: celebrate_1.Joi.object({
191
201
  filename: celebrate_1.Joi.string().required(),
202
+ path: celebrate_1.Joi.string().allow(''),
192
203
  }),
193
204
  }), async (req, res, next) => {
194
- const logger = typedi_1.Container.get('logger');
195
205
  try {
196
- let { filename } = req.body;
197
- const filePath = (0, path_1.join)(config_1.default.scriptPath, filename);
198
- // const stats = fs.statSync(filePath);
199
- // res.set({
200
- // 'Content-Type': 'application/octet-stream', //告诉浏览器这是一个二进制文件
201
- // 'Content-Disposition': 'attachment; filename=' + filename, //告诉浏览器这是一个需要下载的文件
202
- // 'Content-Length': stats.size //文件大小
203
- // });
204
- // fs.createReadStream(filePath).pipe(res);
206
+ let { filename, path } = req.body;
207
+ const scriptService = typedi_1.Container.get(script_1.default);
208
+ const filePath = scriptService.checkFilePath(path, filename);
209
+ if (!filePath) {
210
+ return res.send({
211
+ code: 403,
212
+ message: '暂无权限',
213
+ });
214
+ }
205
215
  return res.download(filePath, filename, (err) => {
206
- return next(err);
216
+ if (err) {
217
+ return next(err);
218
+ }
207
219
  });
208
220
  }
209
221
  catch (e) {
@@ -32,17 +32,20 @@ exports.default = async () => {
32
32
  }, true);
33
33
  // 运行删除日志任务
34
34
  const data = await systemService.getSystemConfig();
35
- if (data && data.info && data.info.logRemoveFrequency) {
36
- const rmlogCron = {
37
- id: data.id,
38
- name: '删除日志',
39
- command: `ql rmlog ${data.info.logRemoveFrequency}`,
40
- runOrigin: 'system',
41
- };
42
- await scheduleService.cancelIntervalTask(rmlogCron);
43
- scheduleService.createIntervalTask(rmlogCron, {
44
- days: data.info.logRemoveFrequency,
45
- }, true);
35
+ if (data && data.info) {
36
+ if (data.info.logRemoveFrequency) {
37
+ const rmlogCron = {
38
+ id: data.id,
39
+ name: '删除日志',
40
+ command: `ql rmlog ${data.info.logRemoveFrequency}`,
41
+ runOrigin: 'system',
42
+ };
43
+ await scheduleService.cancelIntervalTask(rmlogCron);
44
+ scheduleService.createIntervalTask(rmlogCron, {
45
+ days: data.info.logRemoveFrequency,
46
+ }, true);
47
+ }
48
+ systemService.updateTimezone(data.info);
46
49
  }
47
50
  await subscriptionService.setSshConfig();
48
51
  const subs = await subscriptionService.list();
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const path_1 = __importDefault(require("path"));
19
+ const typedi_1 = require("typedi");
20
+ const winston_1 = __importDefault(require("winston"));
21
+ const config_1 = __importDefault(require("../config"));
22
+ let LogService = class LogService {
23
+ constructor(logger) {
24
+ this.logger = logger;
25
+ }
26
+ checkFilePath(filePath, fileName) {
27
+ const finalPath = path_1.default.resolve(config_1.default.logPath, filePath, fileName);
28
+ return finalPath.startsWith(config_1.default.logPath) ? finalPath : '';
29
+ }
30
+ };
31
+ LogService = __decorate([
32
+ (0, typedi_1.Service)(),
33
+ __param(0, (0, typedi_1.Inject)('logger')),
34
+ __metadata("design:paramtypes", [winston_1.default.Logger])
35
+ ], LogService);
36
+ exports.default = LogService;
37
+ //# sourceMappingURL=log.js.map
@@ -69,9 +69,13 @@ let ScriptService = class ScriptService {
69
69
  catch (error) { }
70
70
  return { code: 200 };
71
71
  }
72
- async getFile(filePath, fileName) {
72
+ checkFilePath(filePath, fileName) {
73
73
  const finalPath = path_1.default.resolve(config_1.default.scriptPath, filePath, fileName);
74
- if (!finalPath.startsWith(config_1.default.scriptPath)) {
74
+ return finalPath.startsWith(config_1.default.scriptPath) ? finalPath : '';
75
+ }
76
+ async getFile(filePath, fileName) {
77
+ const finalPath = this.checkFilePath(filePath, fileName);
78
+ if (!finalPath) {
75
79
  return '';
76
80
  }
77
81
  const content = await (0, util_1.getFileContentByName)(finalPath);