@whyour/qinglong 2.19.2-2 → 2.20.0-2

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 (112) hide show
  1. package/.env.example +1 -2
  2. package/README-en.md +4 -2
  3. package/README.md +4 -2
  4. package/back/protos/api.proto +17 -0
  5. package/docker/310.Dockerfile +23 -6
  6. package/docker/Dockerfile +22 -6
  7. package/docker/docker-entrypoint.sh +27 -14
  8. package/package.json +8 -9
  9. package/sample/notify.js +18 -2
  10. package/sample/notify.py +15 -0
  11. package/sample/ql_sample.js +28 -0
  12. package/shell/api.sh +8 -48
  13. package/shell/check.sh +5 -22
  14. package/shell/preload/client.js +6 -1
  15. package/shell/pub.sh +4 -4
  16. package/shell/share.sh +32 -55
  17. package/shell/start.sh +2 -3
  18. package/shell/task.sh +19 -10
  19. package/shell/update.sh +1 -0
  20. package/static/build/api/dependence.js +7 -1
  21. package/static/build/api/env.js +30 -4
  22. package/static/build/api/script.js +48 -8
  23. package/static/build/api/subscription.js +3 -3
  24. package/static/build/api/system.js +19 -26
  25. package/static/build/api/user.js +2 -1
  26. package/static/build/app.js +96 -18
  27. package/static/build/config/index.js +2 -2
  28. package/static/build/config/util.js +24 -1
  29. package/static/build/data/cron.js +4 -0
  30. package/static/build/data/env.js +3 -1
  31. package/static/build/data/notify.js +1 -0
  32. package/static/build/loaders/db.js +29 -35
  33. package/static/build/loaders/deps.js +22 -5
  34. package/static/build/loaders/express.js +19 -10
  35. package/static/build/loaders/initData.js +25 -1
  36. package/static/build/loaders/initTask.js +6 -0
  37. package/static/build/loaders/sock.js +10 -12
  38. package/static/build/protos/api.js +336 -1
  39. package/static/build/schedule/addCron.js +2 -2
  40. package/static/build/schedule/api.js +100 -1
  41. package/static/build/schedule/delCron.js +1 -1
  42. package/static/build/schedule/health.js +2 -3
  43. package/static/build/services/cron.js +54 -20
  44. package/static/build/services/dependence.js +6 -5
  45. package/static/build/services/env.js +9 -2
  46. package/static/build/services/notify.js +17 -5
  47. package/static/build/services/schedule.js +4 -4
  48. package/static/build/services/sshKey.js +24 -4
  49. package/static/build/services/subscription.js +11 -8
  50. package/static/build/services/system.js +15 -0
  51. package/static/build/services/user.js +83 -4
  52. package/static/build/shared/auth.js +40 -0
  53. package/static/build/shared/logStreamManager.js +104 -0
  54. package/static/build/shared/runCron.js +23 -0
  55. package/static/build/validation/schedule.js +39 -2
  56. package/static/dist/1147.856bb861.async.js +1 -0
  57. package/static/dist/1379.f91563a1.async.js +1 -0
  58. package/static/dist/{2208.3bc521b1.async.js → 2208.7bf7e296.async.js} +1 -1
  59. package/static/dist/3191.da7f3e07.async.js +1 -0
  60. package/static/dist/5691.931f59c5.async.js +1 -0
  61. package/static/dist/7571.4f6240b1.async.js +1 -0
  62. package/static/dist/{8826.3ab4ad84.async.js → 8826.5f289c4d.async.js} +1 -1
  63. package/static/dist/index.html +2 -2
  64. package/static/dist/preload_helper.0fb920eb.js +1 -0
  65. package/static/dist/{src__pages__crontab__detail.ee431270.async.js → src__pages__crontab__detail.b07f0c0a.async.js} +1 -1
  66. package/static/dist/src__pages__crontab__index.6b90d8c5.async.js +1 -0
  67. package/static/dist/{src__pages__crontab__logModal.57501983.async.js → src__pages__crontab__logModal.5e6a4bf2.async.js} +1 -1
  68. package/static/dist/src__pages__crontab__modal.2d3d4953.async.js +1 -0
  69. package/static/dist/src__pages__dependence__modal.86604072.async.js +1 -0
  70. package/static/dist/{src__pages__env__editNameModal.665393cd.async.js → src__pages__env__editNameModal.79b7cf83.async.js} +1 -1
  71. package/static/dist/src__pages__env__index.a0a2fece.async.js +1 -0
  72. package/static/dist/{src__pages__env__modal.168498f9.async.js → src__pages__env__modal.b84c1173.async.js} +1 -1
  73. package/static/dist/{src__pages__error__index.d9beeda3.async.js → src__pages__error__index.01fac00e.async.js} +1 -1
  74. package/static/dist/{src__pages__initialization__index.2403c031.async.js → src__pages__initialization__index.2e49cf43.async.js} +1 -1
  75. package/static/dist/src__pages__script__editModal.cbf4ec0e.async.js +1 -0
  76. package/static/dist/{src__pages__script__editNameModal.e36cd111.async.js → src__pages__script__editNameModal.05441c89.async.js} +1 -1
  77. package/static/dist/src__pages__script__index.d6e9cb23.async.js +1 -0
  78. package/static/dist/{src__pages__script__renameModal.f9756f26.async.js → src__pages__script__renameModal.3bb00014.async.js} +1 -1
  79. package/static/dist/src__pages__script__saveModal.8417503a.async.js +1 -0
  80. package/static/dist/{src__pages__script__setting.8c2727b4.async.js → src__pages__script__setting.5a2a2a2c.async.js} +1 -1
  81. package/static/dist/{src__pages__setting__appModal.5a39121e.async.js → src__pages__setting__appModal.7f763fa7.async.js} +1 -1
  82. package/static/dist/src__pages__setting__dependence.e64c4554.async.js +1 -0
  83. package/static/dist/src__pages__setting__index.3a220288.async.js +1 -0
  84. package/static/dist/src__pages__setting__notification.49003b2f.async.js +1 -0
  85. package/static/dist/src__pages__setting__other.0d931d6f.async.js +1 -0
  86. package/static/dist/src__pages__setting__security.a916e056.async.js +1 -0
  87. package/static/dist/{src__pages__setting__systemLog.fc5bdc78.async.js → src__pages__setting__systemLog.cbb0a3bb.async.js} +1 -1
  88. package/static/dist/src__pages__subscription__modal.ade477c1.async.js +1 -0
  89. package/static/dist/umi.e7cba995.js +1 -0
  90. package/version.yaml +46 -9
  91. package/docker/front.conf +0 -61
  92. package/docker/nginx.conf +0 -45
  93. package/static/dist/2995.2eb218b3.async.js +0 -1
  94. package/static/dist/3191.cc1e31cd.async.js +0 -1
  95. package/static/dist/4046.7fbcfa02.async.js +0 -1
  96. package/static/dist/5713.8519f547.async.js +0 -1
  97. package/static/dist/8851.503b1e64.async.js +0 -1
  98. package/static/dist/preload_helper.9c086410.js +0 -1
  99. package/static/dist/src__pages__crontab__index.af4cb04a.async.js +0 -1
  100. package/static/dist/src__pages__crontab__modal.21258e08.async.js +0 -1
  101. package/static/dist/src__pages__dependence__modal.6639424a.async.js +0 -1
  102. package/static/dist/src__pages__env__index.70340ba7.async.js +0 -1
  103. package/static/dist/src__pages__script__editModal.f1741417.async.js +0 -1
  104. package/static/dist/src__pages__script__index.82b42e11.async.js +0 -1
  105. package/static/dist/src__pages__script__saveModal.e885e133.async.js +0 -1
  106. package/static/dist/src__pages__setting__dependence.a46e873d.async.js +0 -1
  107. package/static/dist/src__pages__setting__index.9be4775c.async.js +0 -1
  108. package/static/dist/src__pages__setting__notification.299f6b96.async.js +0 -1
  109. package/static/dist/src__pages__setting__other.60924a56.async.js +0 -1
  110. package/static/dist/src__pages__setting__security.e7371daa.async.js +0 -1
  111. package/static/dist/src__pages__subscription__modal.a7fd6a3c.async.js +0 -1
  112. package/static/dist/umi.5b8ae363.js +0 -1
@@ -41,6 +41,13 @@ class Application {
41
41
  this.isShuttingDown = false;
42
42
  this.workerMetadataMap = new Map();
43
43
  this.app = (0, express_1.default)();
44
+ // 创建一个全局中间件,删除查询参数中的t
45
+ this.app.use((req, res, next) => {
46
+ if (req.query.t) {
47
+ delete req.query.t;
48
+ }
49
+ next();
50
+ });
44
51
  }
45
52
  async start() {
46
53
  try {
@@ -60,21 +67,74 @@ class Application {
60
67
  }
61
68
  }
62
69
  startMasterProcess() {
63
- this.forkWorker('http');
64
- this.forkWorker('grpc');
70
+ // Fork gRPC worker first and wait for it to be ready
71
+ const grpcWorker = this.forkWorker('grpc');
72
+ // Wait for gRPC worker to signal it's ready before starting HTTP worker
73
+ this.waitForWorkerReady(grpcWorker, 30000)
74
+ .then(() => {
75
+ logger_1.default.info('✌️ gRPC worker is ready, starting HTTP worker');
76
+ this.httpWorker = this.forkWorker('http');
77
+ })
78
+ .catch((error) => {
79
+ logger_1.default.error('✌️ Failed to wait for gRPC worker:', error);
80
+ process.exit(1);
81
+ });
65
82
  cluster_1.default.on('exit', (worker, code, signal) => {
66
83
  const metadata = this.workerMetadataMap.get(worker.id);
67
84
  if (metadata) {
68
85
  if (!this.isShuttingDown) {
69
- logger_1.default.error(`${metadata.serviceType} worker ${worker.process.pid} died (${signal || code}). Restarting...`);
70
- const newWorker = this.forkWorker(metadata.serviceType);
71
- logger_1.default.info(`Restarted ${metadata.serviceType} worker (New PID: ${newWorker.process.pid})`);
86
+ logger_1.default.error(`✌️ ${metadata.serviceType} worker ${worker.process.pid} died (${signal || code}). Restarting...`);
87
+ // If gRPC worker died, restart it and wait for it to be ready
88
+ if (metadata.serviceType === 'grpc') {
89
+ const newGrpcWorker = this.forkWorker('grpc');
90
+ this.waitForWorkerReady(newGrpcWorker, 30000)
91
+ .then(() => {
92
+ logger_1.default.info('✌️ gRPC worker restarted and ready');
93
+ // Re-register cron jobs by notifying the HTTP worker
94
+ if (this.httpWorker) {
95
+ try {
96
+ this.httpWorker.send('reregister-crons');
97
+ logger_1.default.info('✌️ Sent reregister-crons message to HTTP worker');
98
+ }
99
+ catch (error) {
100
+ logger_1.default.error('✌️ Failed to send reregister-crons message:', error);
101
+ }
102
+ }
103
+ })
104
+ .catch((error) => {
105
+ logger_1.default.error('✌️ Failed to restart gRPC worker:', error);
106
+ process.exit(1);
107
+ });
108
+ }
109
+ else {
110
+ // For HTTP worker, just restart it
111
+ const newWorker = this.forkWorker(metadata.serviceType);
112
+ this.httpWorker = newWorker;
113
+ logger_1.default.info(`✌️ Restarted ${metadata.serviceType} worker (PID: ${newWorker.process.pid})`);
114
+ }
72
115
  }
73
116
  this.workerMetadataMap.delete(worker.id);
74
117
  }
75
118
  });
76
119
  this.setupMasterShutdown();
77
120
  }
121
+ waitForWorkerReady(worker, timeoutMs) {
122
+ return new Promise((resolve, reject) => {
123
+ const messageHandler = (msg) => {
124
+ if (msg === 'ready') {
125
+ worker.removeListener('message', messageHandler);
126
+ clearTimeout(timeoutId);
127
+ resolve();
128
+ }
129
+ };
130
+ worker.on('message', messageHandler);
131
+ // Timeout after specified milliseconds
132
+ const timeoutId = setTimeout(() => {
133
+ worker.removeListener('message', messageHandler);
134
+ reject(new Error(`Worker failed to start within ${timeoutMs / 1000} seconds`));
135
+ }, timeoutMs);
136
+ });
137
+ }
78
138
  forkWorker(serviceType) {
79
139
  const worker = cluster_1.default.fork({ SERVICE_TYPE: serviceType });
80
140
  this.workerMetadataMap.set(worker.id, {
@@ -86,10 +146,13 @@ class Application {
86
146
  return worker;
87
147
  }
88
148
  async initializeDatabase() {
89
- await require('./loaders/db').default();
149
+ const dbLoader = await Promise.resolve().then(() => __importStar(require('./loaders/db')));
150
+ await dbLoader.default();
90
151
  }
91
152
  setupMiddlewares() {
92
- this.app.use((0, helmet_1.default)());
153
+ this.app.use((0, helmet_1.default)({
154
+ contentSecurityPolicy: false,
155
+ }));
93
156
  this.app.use((0, cors_1.default)(config_1.default.cors));
94
157
  this.app.use((0, compression_1.default)());
95
158
  this.app.use(monitoring_1.monitoringMiddleware);
@@ -105,14 +168,14 @@ class Application {
105
168
  if (worker) {
106
169
  const exitPromise = new Promise((resolve) => {
107
170
  worker.once('exit', () => {
108
- logger_1.default.info(`Worker ${worker.process.pid} exited`);
171
+ logger_1.default.info(`✌️ Worker ${worker.process.pid} exited`);
109
172
  resolve();
110
173
  });
111
174
  try {
112
175
  worker.send('shutdown');
113
176
  }
114
177
  catch (error) {
115
- 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);
116
179
  }
117
180
  });
118
181
  workerPromises.push(exitPromise);
@@ -123,7 +186,7 @@ class Application {
123
186
  Promise.all(workerPromises),
124
187
  new Promise((resolve) => {
125
188
  setTimeout(() => {
126
- logger_1.default.warn('Worker shutdown timeout reached');
189
+ logger_1.default.warn('✌️ Worker shutdown timeout reached');
127
190
  resolve();
128
191
  }, 10000);
129
192
  }),
@@ -131,7 +194,7 @@ class Application {
131
194
  process.exit(0);
132
195
  }
133
196
  catch (error) {
134
- logger_1.default.error('Error during worker shutdown:', error);
197
+ logger_1.default.error('✌️ Error during worker shutdown:', error);
135
198
  process.exit(1);
136
199
  }
137
200
  };
@@ -142,7 +205,7 @@ class Application {
142
205
  var _a;
143
206
  const serviceType = process.env.SERVICE_TYPE;
144
207
  if (!serviceType || !['http', 'grpc'].includes(serviceType)) {
145
- logger_1.default.error('Invalid SERVICE_TYPE:', serviceType);
208
+ logger_1.default.error('✌️ Invalid SERVICE_TYPE:', serviceType);
146
209
  process.exit(1);
147
210
  }
148
211
  logger_1.default.info(`✌️ ${serviceType} worker started (PID: ${process.pid})`);
@@ -156,7 +219,7 @@ class Application {
156
219
  (_a = process.send) === null || _a === void 0 ? void 0 : _a.call(process, 'ready');
157
220
  }
158
221
  catch (error) {
159
- logger_1.default.error(`${serviceType} worker failed:`, error);
222
+ logger_1.default.error(`✌️ ${serviceType} worker failed:`, error);
160
223
  process.exit(1);
161
224
  }
162
225
  }
@@ -164,9 +227,11 @@ class Application {
164
227
  this.setupMiddlewares();
165
228
  const { HttpServerService } = await Promise.resolve().then(() => __importStar(require('./services/http')));
166
229
  this.httpServerService = typedi_1.Container.get(HttpServerService);
167
- await require('./loaders/app').default({ app: this.app });
230
+ const appLoader = await Promise.resolve().then(() => __importStar(require('./loaders/app')));
231
+ await appLoader.default({ app: this.app });
168
232
  const server = await this.httpServerService.initialize(this.app, config_1.default.port);
169
- await require('./loaders/server').default({ server });
233
+ const serverLoader = await Promise.resolve().then(() => __importStar(require('./loaders/server')));
234
+ await serverLoader.default({ server });
170
235
  this.setupWorkerShutdown('http');
171
236
  }
172
237
  async startGrpcService() {
@@ -176,10 +241,23 @@ class Application {
176
241
  this.setupWorkerShutdown('grpc');
177
242
  }
178
243
  setupWorkerShutdown(serviceType) {
179
- process.on('message', (msg) => {
244
+ process.on('message', async (msg) => {
180
245
  if (msg === 'shutdown') {
181
246
  this.gracefulShutdown(serviceType);
182
247
  }
248
+ else if (msg === 'reregister-crons' && serviceType === 'http') {
249
+ // Re-register cron jobs when gRPC worker restarts
250
+ try {
251
+ logger_1.default.info('✌️ Received reregister-crons message, re-registering cron jobs...');
252
+ const CronService = (await Promise.resolve().then(() => __importStar(require('./services/cron')))).default;
253
+ const cronService = typedi_1.Container.get(CronService);
254
+ await cronService.autosave_crontab();
255
+ logger_1.default.info('✌️ Cron jobs re-registered successfully');
256
+ }
257
+ catch (error) {
258
+ logger_1.default.error('✌️ Failed to re-register cron jobs:', error);
259
+ }
260
+ }
183
261
  });
184
262
  const shutdown = () => this.gracefulShutdown(serviceType);
185
263
  process.on('SIGTERM', shutdown);
@@ -200,14 +278,14 @@ class Application {
200
278
  process.exit(0);
201
279
  }
202
280
  catch (error) {
203
- logger_1.default.error(`[${serviceType}] Error during shutdown:`, error);
281
+ logger_1.default.error(`✌️ [${serviceType}] Error during shutdown:`, error);
204
282
  process.exit(1);
205
283
  }
206
284
  }
207
285
  }
208
286
  const app = new Application();
209
287
  app.start().catch((error) => {
210
- logger_1.default.error('Application failed to start:', error);
288
+ logger_1.default.error('🙅‍♀️ Application failed to start:', error);
211
289
  process.exit(1);
212
290
  });
213
291
  //# sourceMappingURL=app.js.map
@@ -9,7 +9,7 @@ dotenv_1.default.config({
9
9
  path: path_1.default.join(__dirname, '../../.env'),
10
10
  });
11
11
  const config = {
12
- port: parseInt(process.env.BACK_PORT || '5600', 10),
12
+ port: parseInt(process.env.BACK_PORT || '5700', 10),
13
13
  grpcPort: parseInt(process.env.GRPC_PORT || '5500', 10),
14
14
  nodeEnv: process.env.NODE_ENV || 'development',
15
15
  isDevelopment: process.env.NODE_ENV === 'development',
@@ -136,5 +136,5 @@ exports.default = Object.assign(Object.assign({}, config), { jwt: config.jwt, ro
136
136
  sqliteFile,
137
137
  sshdPath,
138
138
  systemLogPath,
139
- dependenceCachePath });
139
+ dependenceCachePath, maxTokensPerPlatform: 10 });
140
140
  //# sourceMappingURL=index.js.map
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
29
  return (mod && mod.__esModule) ? mod : { "default": mod };
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.updateLinuxMirrorFile = exports.detectOS = exports.isDemoEnv = exports.getUninstallCommand = exports.getInstallCommand = exports.getGetCommand = exports.setSystemTimezone = exports.rmPath = exports.safeJSONParse = exports.getUniqPath = exports.parseContentVersion = exports.parseVersion = exports.getPid = exports.killTask = exports.psTree = exports.parseBody = exports.parseHeaders = exports.promiseExecSuccess = exports.promiseExec = exports.readDir = exports.readDirs = exports.dirSort = exports.concurrentRun = exports.handleLogPath = exports.createFile = exports.fileExist = exports.getPlatform = exports.getToken = exports.getLastModifyFilePath = exports.removeAnsi = exports.getFileContentByName = void 0;
32
+ exports.updateLinuxMirrorFile = exports.detectOS = exports.isDemoEnv = exports.getUninstallCommand = exports.getInstallCommand = exports.getGetCommand = exports.setSystemTimezone = exports.rmPath = exports.safeJSONParse = exports.getUniqPath = exports.parseContentVersion = exports.parseVersion = exports.killAllTasks = exports.getAllPids = exports.getPid = exports.killTask = exports.psTree = exports.parseBody = exports.parseHeaders = exports.promiseExecSuccess = exports.promiseExec = exports.readDir = exports.readDirs = exports.dirSort = exports.concurrentRun = exports.handleLogPath = exports.createFile = exports.fileExist = exports.getPlatform = exports.getToken = exports.getLastModifyFilePath = exports.removeAnsi = exports.getFileContentByName = void 0;
33
33
  const fs = __importStar(require("fs/promises"));
34
34
  const path = __importStar(require("path"));
35
35
  const child_process_1 = require("child_process");
@@ -395,6 +395,29 @@ async function getPid(cmd) {
395
395
  return pid ? Number(pid) : undefined;
396
396
  }
397
397
  exports.getPid = getPid;
398
+ async function getAllPids(cmd) {
399
+ const taskCommand = `ps -eo pid,command | grep "${cmd}" | grep -v grep | awk '{print $1}'`;
400
+ const pidsStr = await promiseExec(taskCommand);
401
+ if (!pidsStr)
402
+ return [];
403
+ return pidsStr
404
+ .split('\n')
405
+ .map((p) => Number(p.trim()))
406
+ .filter((p) => !isNaN(p) && p > 0);
407
+ }
408
+ exports.getAllPids = getAllPids;
409
+ async function killAllTasks(cmd) {
410
+ const pids = await getAllPids(cmd);
411
+ for (const pid of pids) {
412
+ try {
413
+ await killTask(pid);
414
+ }
415
+ catch (error) {
416
+ // Ignore errors if process already terminated
417
+ }
418
+ }
419
+ }
420
+ exports.killAllTasks = killAllTasks;
398
421
  async function parseVersion(path) {
399
422
  return (0, js_yaml_1.load)(await fs.readFile(path, 'utf8'));
400
423
  }
@@ -27,6 +27,8 @@ class Crontab {
27
27
  this.extra_schedules = options.extra_schedules;
28
28
  this.task_before = options.task_before;
29
29
  this.task_after = options.task_after;
30
+ this.log_name = options.log_name;
31
+ this.allow_multiple_instances = options.allow_multiple_instances || 0;
30
32
  }
31
33
  }
32
34
  exports.Crontab = Crontab;
@@ -65,5 +67,7 @@ exports.CrontabModel = _1.sequelize.define('Crontab', {
65
67
  extra_schedules: sequelize_1.DataTypes.JSON,
66
68
  task_before: sequelize_1.DataTypes.STRING,
67
69
  task_after: sequelize_1.DataTypes.STRING,
70
+ log_name: sequelize_1.DataTypes.STRING,
71
+ allow_multiple_instances: sequelize_1.DataTypes.NUMBER,
68
72
  });
69
73
  //# sourceMappingURL=cron.js.map
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EnvModel = exports.minPosition = exports.stepPosition = exports.initPosition = exports.maxPosition = exports.EnvStatus = exports.Env = void 0;
4
- const _1 = require(".");
5
4
  const sequelize_1 = require("sequelize");
5
+ const _1 = require(".");
6
6
  class Env {
7
7
  constructor(options) {
8
8
  this.value = options.value;
@@ -15,6 +15,7 @@ class Env {
15
15
  this.position = options.position;
16
16
  this.name = options.name;
17
17
  this.remarks = options.remarks || '';
18
+ this.isPinned = options.isPinned || 0;
18
19
  }
19
20
  }
20
21
  exports.Env = Env;
@@ -34,5 +35,6 @@ exports.EnvModel = _1.sequelize.define('Env', {
34
35
  position: sequelize_1.DataTypes.NUMBER,
35
36
  name: { type: sequelize_1.DataTypes.STRING, unique: 'compositeIndex' },
36
37
  remarks: sequelize_1.DataTypes.STRING,
38
+ isPinned: sequelize_1.DataTypes.NUMBER,
37
39
  });
38
40
  //# sourceMappingURL=env.js.map
@@ -196,6 +196,7 @@ class LarkNotification extends NotificationBaseInfo {
196
196
  constructor() {
197
197
  super(...arguments);
198
198
  this.larkKey = '';
199
+ this.larkSecret = '';
199
200
  }
200
201
  }
201
202
  exports.LarkNotification = LarkNotification;
@@ -22,42 +22,36 @@ exports.default = async () => {
22
22
  await subscription_1.SubscriptionModel.sync();
23
23
  await cronView_1.CrontabViewModel.sync();
24
24
  // 初始化新增字段
25
- try {
26
- await data_1.sequelize.query('alter table CrontabViews add column filterRelation VARCHAR(255)');
25
+ const migrations = [
26
+ {
27
+ table: 'CrontabViews',
28
+ column: 'filterRelation',
29
+ type: 'VARCHAR(255)',
30
+ },
31
+ { table: 'Subscriptions', column: 'proxy', type: 'VARCHAR(255)' },
32
+ { table: 'CrontabViews', column: 'type', type: 'NUMBER' },
33
+ { table: 'Subscriptions', column: 'autoAddCron', type: 'NUMBER' },
34
+ { table: 'Subscriptions', column: 'autoDelCron', type: 'NUMBER' },
35
+ { table: 'Crontabs', column: 'sub_id', type: 'NUMBER' },
36
+ { table: 'Crontabs', column: 'extra_schedules', type: 'JSON' },
37
+ { table: 'Crontabs', column: 'task_before', type: 'TEXT' },
38
+ { table: 'Crontabs', column: 'task_after', type: 'TEXT' },
39
+ { table: 'Crontabs', column: 'log_name', type: 'VARCHAR(255)' },
40
+ {
41
+ table: 'Crontabs',
42
+ column: 'allow_multiple_instances',
43
+ type: 'NUMBER',
44
+ },
45
+ { table: 'Envs', column: 'isPinned', type: 'NUMBER' },
46
+ ];
47
+ for (const migration of migrations) {
48
+ try {
49
+ await data_1.sequelize.query(`alter table ${migration.table} add column ${migration.column} ${migration.type}`);
50
+ }
51
+ catch (error) {
52
+ // Column already exists or other error, continue
53
+ }
27
54
  }
28
- catch (error) { }
29
- try {
30
- await data_1.sequelize.query('alter table Subscriptions add column proxy VARCHAR(255)');
31
- }
32
- catch (error) { }
33
- try {
34
- await data_1.sequelize.query('alter table CrontabViews add column type NUMBER');
35
- }
36
- catch (error) { }
37
- try {
38
- await data_1.sequelize.query('alter table Subscriptions add column autoAddCron NUMBER');
39
- }
40
- catch (error) { }
41
- try {
42
- await data_1.sequelize.query('alter table Subscriptions add column autoDelCron NUMBER');
43
- }
44
- catch (error) { }
45
- try {
46
- await data_1.sequelize.query('alter table Crontabs add column sub_id NUMBER');
47
- }
48
- catch (error) { }
49
- try {
50
- await data_1.sequelize.query('alter table Crontabs add column extra_schedules JSON');
51
- }
52
- catch (error) { }
53
- try {
54
- await data_1.sequelize.query('alter table Crontabs add column task_before TEXT');
55
- }
56
- catch (error) { }
57
- try {
58
- await data_1.sequelize.query('alter table Crontabs add column task_after TEXT');
59
- }
60
- catch (error) { }
61
55
  logger_1.default.info('✌️ DB loaded');
62
56
  }
63
57
  catch (error) {
@@ -5,9 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const path_1 = __importDefault(require("path"));
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
+ const os_1 = __importDefault(require("os"));
8
9
  const chokidar_1 = __importDefault(require("chokidar"));
9
10
  const index_1 = __importDefault(require("../config/index"));
10
- const util_1 = require("../config/util");
11
+ const logger_1 = __importDefault(require("./logger"));
11
12
  async function linkToNodeModule(src, dst) {
12
13
  const target = path_1.default.join(index_1.default.rootPath, 'node_modules', dst || src);
13
14
  const source = path_1.default.join(index_1.default.rootPath, src);
@@ -20,8 +21,17 @@ async function linkToNodeModule(src, dst) {
20
21
  catch (error) { }
21
22
  }
22
23
  async function linkCommand() {
23
- const commandPath = await (0, util_1.promiseExec)('which node');
24
- const commandDir = path_1.default.dirname(commandPath);
24
+ const homeDir = os_1.default.homedir();
25
+ let userBinDir = path_1.default.join(homeDir, 'bin');
26
+ try {
27
+ await promises_1.default.mkdir(userBinDir, { recursive: true });
28
+ await linkCommandToDir(userBinDir);
29
+ }
30
+ catch (error) {
31
+ logger_1.default.error('Linking command failed:', error);
32
+ }
33
+ }
34
+ async function linkCommandToDir(commandDir) {
25
35
  const linkShell = [
26
36
  {
27
37
  src: 'update.sh',
@@ -38,6 +48,13 @@ async function linkCommand() {
38
48
  const source = path_1.default.join(index_1.default.rootPath, 'shell', link.src);
39
49
  const target = path_1.default.join(commandDir, link.dest);
40
50
  const tmpTarget = path_1.default.join(commandDir, link.tmp);
51
+ try {
52
+ const stats = await promises_1.default.lstat(tmpTarget);
53
+ if (stats) {
54
+ await promises_1.default.unlink(tmpTarget);
55
+ }
56
+ }
57
+ catch (error) { }
41
58
  await promises_1.default.symlink(source, tmpTarget);
42
59
  await promises_1.default.rename(tmpTarget, target);
43
60
  }
@@ -51,7 +68,7 @@ exports.default = async (src = 'deps') => {
51
68
  persistent: true,
52
69
  });
53
70
  watcher
54
- .on('add', (path) => linkToNodeModule(src))
55
- .on('change', (path) => linkToNodeModule(src));
71
+ .on('add', () => linkToNodeModule(src))
72
+ .on('change', () => linkToNodeModule(src));
56
73
  };
57
74
  //# sourceMappingURL=deps.js.map
@@ -14,6 +14,8 @@ const express_urlrewrite_1 = __importDefault(require("express-urlrewrite"));
14
14
  const celebrate_1 = require("celebrate");
15
15
  const serverEnv_1 = require("../config/serverEnv");
16
16
  const store_1 = require("../shared/store");
17
+ const auth_1 = require("../shared/auth");
18
+ const path_1 = __importDefault(require("path"));
17
19
  exports.default = ({ app }) => {
18
20
  app.set('trust proxy', 'loopback');
19
21
  app.use((0, cors_1.default)());
@@ -21,11 +23,13 @@ exports.default = ({ app }) => {
21
23
  app.use(`${config_1.default.api.prefix}/static`, express_1.default.static(config_1.default.uploadPath));
22
24
  app.use(body_parser_1.default.json({ limit: '50mb' }));
23
25
  app.use(body_parser_1.default.urlencoded({ limit: '50mb', extended: true }));
26
+ const frontendPath = path_1.default.join(config_1.default.rootPath, 'static/dist');
27
+ app.use(express_1.default.static(frontendPath));
24
28
  app.use((0, express_jwt_1.expressjwt)({
25
29
  secret: config_1.default.jwt.secret,
26
30
  algorithms: ['HS384'],
27
31
  }).unless({
28
- path: [...config_1.default.apiWhiteList, /^\/open\//],
32
+ path: [...config_1.default.apiWhiteList, /^\/(?!api\/).*/],
29
33
  }));
30
34
  app.use((req, res, next) => {
31
35
  if (!req.headers) {
@@ -39,6 +43,9 @@ exports.default = ({ app }) => {
39
43
  });
40
44
  app.use(async (req, res, next) => {
41
45
  var _a;
46
+ if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) {
47
+ return next();
48
+ }
42
49
  const headerToken = (0, util_1.getToken)(req);
43
50
  if (req.path.startsWith('/open/')) {
44
51
  const apps = await store_1.shareStore.getApps();
@@ -61,11 +68,8 @@ exports.default = ({ app }) => {
61
68
  return next();
62
69
  }
63
70
  const authInfo = await store_1.shareStore.getAuthInfo();
64
- if (authInfo && headerToken) {
65
- const { token = '', tokens = {} } = authInfo;
66
- if (headerToken === token || tokens[req.platform] === headerToken) {
67
- return next();
68
- }
71
+ if ((0, auth_1.isValidToken)(authInfo, headerToken, req.platform)) {
72
+ return next();
69
73
  }
70
74
  const errorCode = headerToken ? 'invalid_token' : 'credentials_required';
71
75
  const errorMessage = headerToken
@@ -94,10 +98,15 @@ exports.default = ({ app }) => {
94
98
  });
95
99
  app.use((0, express_urlrewrite_1.default)('/open/*', '/api/$1'));
96
100
  app.use(config_1.default.api.prefix, (0, api_1.default)());
97
- app.use((req, res, next) => {
98
- const err = new Error('Not Found');
99
- err['status'] = 404;
100
- next(err);
101
+ app.get('*', (_, res, next) => {
102
+ const indexPath = path_1.default.join(frontendPath, 'index.html');
103
+ res.sendFile(indexPath, (err) => {
104
+ if (err) {
105
+ const err = new Error('Not Found');
106
+ err['status'] = 404;
107
+ next(err);
108
+ }
109
+ });
101
110
  });
102
111
  app.use((0, celebrate_1.errors)());
103
112
  app.use((err, req, res, next) => {
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
@@ -85,7 +108,8 @@ exports.default = async () => {
85
108
  await dependence_2.DependenceModel.update({ status: dependence_2.DependenceStatus.queued, log: [] }, { where: { id: docs.map((x) => x.id) } });
86
109
  setTimeout(async () => {
87
110
  await dependenceService.installDependenceOneByOne(docs);
88
- require('./bootAfter').default();
111
+ const bootAfterLoader = await Promise.resolve().then(() => __importStar(require('./bootAfter')));
112
+ bootAfterLoader.default();
89
113
  }, 5000);
90
114
  };
91
115
  // 初始化更新 linux/python/nodejs 镜像源配置
@@ -7,6 +7,7 @@ const typedi_1 = require("typedi");
7
7
  const system_1 = __importDefault(require("../services/system"));
8
8
  const schedule_1 = __importDefault(require("../services/schedule"));
9
9
  const subscription_1 = __importDefault(require("../services/subscription"));
10
+ const sshKey_1 = __importDefault(require("../services/sshKey"));
10
11
  const config_1 = __importDefault(require("../config"));
11
12
  const util_1 = require("../config/util");
12
13
  const path_1 = require("path");
@@ -14,6 +15,7 @@ exports.default = async () => {
14
15
  const systemService = typedi_1.Container.get(system_1.default);
15
16
  const scheduleService = typedi_1.Container.get(schedule_1.default);
16
17
  const subscriptionService = typedi_1.Container.get(subscription_1.default);
18
+ const sshKeyService = typedi_1.Container.get(sshKey_1.default);
17
19
  // 生成内置token
18
20
  let tokenCommand = `ts-node-transpile-only ${(0, path_1.join)(config_1.default.rootPath, 'back/token.ts')}`;
19
21
  const tokenFile = (0, path_1.join)(config_1.default.rootPath, 'static/build/token.js');
@@ -46,6 +48,10 @@ exports.default = async () => {
46
48
  }, true);
47
49
  }
48
50
  systemService.updateTimezone(data.info);
51
+ // Apply global SSH key if configured
52
+ if (data.info.globalSshKey) {
53
+ await sshKeyService.addGlobalSSHKey(data.info.globalSshKey, 'global');
54
+ }
49
55
  }
50
56
  await subscriptionService.setSshConfig();
51
57
  const subs = await subscriptionService.list();
@@ -8,6 +8,7 @@ const typedi_1 = require("typedi");
8
8
  const sock_1 = __importDefault(require("../services/sock"));
9
9
  const util_1 = require("../config/util");
10
10
  const store_1 = require("../shared/store");
11
+ const auth_1 = require("../shared/auth");
11
12
  exports.default = async ({ server }) => {
12
13
  const echo = sockjs_1.default.createServer({ prefix: '/api/ws', log: () => { } });
13
14
  const sockService = typedi_1.Container.get(sock_1.default);
@@ -18,18 +19,15 @@ exports.default = async ({ server }) => {
18
19
  const authInfo = await store_1.shareStore.getAuthInfo();
19
20
  const platform = (0, util_1.getPlatform)(conn.headers['user-agent'] || '') || 'desktop';
20
21
  const headerToken = conn.url.replace(`${conn.pathname}?token=`, '');
21
- if (authInfo) {
22
- const { token = '', tokens = {} } = authInfo;
23
- if (headerToken === token || tokens[platform] === headerToken) {
24
- sockService.addClient(conn);
25
- conn.on('data', (message) => {
26
- conn.write(message);
27
- });
28
- conn.on('close', function () {
29
- sockService.removeClient(conn);
30
- });
31
- return;
32
- }
22
+ if ((0, auth_1.isValidToken)(authInfo, headerToken, platform)) {
23
+ sockService.addClient(conn);
24
+ conn.on('data', (message) => {
25
+ conn.write(message);
26
+ });
27
+ conn.on('close', function () {
28
+ sockService.removeClient(conn);
29
+ });
30
+ return;
33
31
  }
34
32
  conn.close('404');
35
33
  });