@@ -27,7 +27,7 @@ import { ScheduleType } from '../interface/schedule';
2727
2828@Service ( )
2929export default class CronService {
30- constructor ( @Inject ( 'logger' ) private logger : winston . Logger ) { }
30+ constructor ( @Inject ( 'logger' ) private logger : winston . Logger ) { }
3131
3232 private isNodeCron ( cron : Crontab ) {
3333 const { schedule, extra_schedules } = cron ;
@@ -49,9 +49,27 @@ export default class CronService {
4949 return this . isOnceSchedule ( schedule ) || this . isBootSchedule ( schedule ) ;
5050 }
5151
52+ private async getLogName ( cron : Crontab ) {
53+ const { log_name, command, id } = cron ;
54+ if ( log_name === '/dev/null' ) {
55+ return log_name ;
56+ }
57+ let uniqPath = await getUniqPath ( command , `${ id } ` ) ;
58+ if ( log_name ) {
59+ const normalizedLogName = log_name . startsWith ( '/' ) ? log_name : path . join ( config . logPath , log_name ) ;
60+ if ( normalizedLogName . startsWith ( config . logPath ) ) {
61+ uniqPath = log_name ;
62+ }
63+ }
64+ const logDirPath = path . resolve ( config . logPath , `${ uniqPath } ` ) ;
65+ await fs . mkdir ( logDirPath , { recursive : true } ) ;
66+ return uniqPath ;
67+ }
68+
5269 public async create ( payload : Crontab ) : Promise < Crontab > {
5370 const tab = new Crontab ( payload ) ;
5471 tab . saved = false ;
72+ tab . log_name = await this . getLogName ( tab ) ;
5573 const doc = await this . insert ( tab ) ;
5674
5775 if ( isDemoEnv ( ) ) {
@@ -82,6 +100,7 @@ export default class CronService {
82100 const doc = await this . getDb ( { id : payload . id } ) ;
83101 const tab = new Crontab ( { ...doc , ...payload } ) ;
84102 tab . saved = false ;
103+ tab . log_name = await this . getLogName ( tab ) ;
85104 const newDoc = await this . updateDb ( tab ) ;
86105
87106 if ( doc . isDisabled === 1 || isDemoEnv ( ) ) {
@@ -142,7 +161,7 @@ export default class CronService {
142161 let cron ;
143162 try {
144163 cron = await this . getDb ( { id } ) ;
145- } catch ( err ) { }
164+ } catch ( err ) { }
146165 if ( ! cron ) {
147166 continue ;
148167 }
@@ -476,61 +495,14 @@ export default class CronService {
476495 `[panel][开始执行任务] 参数: ${ JSON . stringify ( params ) } ` ,
477496 ) ;
478497
479- let { id, command, log_path, log_name } = cron ;
480-
481- // Check if log_name is an absolute path
482- const isAbsolutePath = log_name && log_name . startsWith ( '/' ) ;
483-
484- let uniqPath : string ;
485- let absolutePath : string ;
486- let logPath : string ;
487-
488- if ( isAbsolutePath ) {
489- // Special case: /dev/null is allowed as-is to discard logs
490- if ( log_name === '/dev/null' ) {
491- uniqPath = log_name ;
492- absolutePath = log_name ;
493- logPath = log_name ;
494- } else {
495- // For other absolute paths, ensure they are within the safe log directory
496- const normalizedLogName = path . normalize ( log_name ! ) ;
497- const normalizedLogPath = path . normalize ( config . logPath ) ;
498-
499- if ( ! normalizedLogName . startsWith ( normalizedLogPath ) ) {
500- this . logger . error (
501- `[panel][日志路径安全检查失败] 绝对路径必须在日志目录内: ${ log_name } ` ,
502- ) ;
503- // Fallback to auto-generated path for security
504- const fallbackUniqPath = await getUniqPath ( command , `${ id } ` ) ;
505- const logTime = dayjs ( ) . format ( 'YYYY-MM-DD-HH-mm-ss-SSS' ) ;
506- const logDirPath = path . resolve ( config . logPath , `${ fallbackUniqPath } ` ) ;
507- if ( log_path ?. split ( '/' ) ?. every ( ( x ) => x !== fallbackUniqPath ) ) {
508- await fs . mkdir ( logDirPath , { recursive : true } ) ;
509- }
510- logPath = `${ fallbackUniqPath } /${ logTime } .log` ;
511- absolutePath = path . resolve ( config . logPath , `${ logPath } ` ) ;
512- uniqPath = fallbackUniqPath ;
513- } else {
514- // Absolute path is safe, use it
515- uniqPath = log_name ! ;
516- absolutePath = log_name ! ;
517- logPath = log_name ! ;
518- }
519- }
520- } else {
521- // Sanitize log_name to prevent path traversal for relative paths
522- const sanitizedLogName = log_name
523- ? log_name . replace ( / [ \/ \\ \. ] / g, '_' ) . replace ( / ^ _ + | _ + $ / g, '' )
524- : '' ;
525- uniqPath = sanitizedLogName || ( await getUniqPath ( command , `${ id } ` ) ) ;
526- const logTime = dayjs ( ) . format ( 'YYYY-MM-DD-HH-mm-ss-SSS' ) ;
527- const logDirPath = path . resolve ( config . logPath , `${ uniqPath } ` ) ;
528- if ( log_path ?. split ( '/' ) ?. every ( ( x ) => x !== uniqPath ) ) {
529- await fs . mkdir ( logDirPath , { recursive : true } ) ;
530- }
531- logPath = `${ uniqPath } /${ logTime } .log` ;
532- absolutePath = path . resolve ( config . logPath , `${ logPath } ` ) ;
533- }
498+ let { id, command, log_name } = cron ;
499+
500+ const uniqPath = log_name === '/dev/null' ? ( await getUniqPath ( command , `${ id } ` ) ) : log_name ;
501+ const logTime = dayjs ( ) . format ( 'YYYY-MM-DD-HH-mm-ss-SSS' ) ;
502+ const logDirPath = path . resolve ( config . logPath , `${ uniqPath } ` ) ;
503+ await fs . mkdir ( logDirPath , { recursive : true } ) ;
504+ const logPath = `${ uniqPath } /${ logTime } .log` ;
505+ const absolutePath = path . resolve ( config . logPath , `${ logPath } ` ) ;
534506 const cp = spawn (
535507 `real_log_path=${ logPath } no_delay=true ${ this . makeCommand (
536508 cron ,
@@ -610,7 +582,9 @@ export default class CronService {
610582 if ( ! doc ) {
611583 return '' ;
612584 }
613-
585+ if ( doc . log_name === '/dev/null' ) {
586+ return '日志设置为忽略' ;
587+ }
614588 const absolutePath = path . resolve ( config . logPath , `${ doc . log_path } ` ) ;
615589 const logFileExist = doc . log_path && ( await fileExist ( absolutePath ) ) ;
616590 if ( logFileExist ) {
@@ -653,9 +627,7 @@ export default class CronService {
653627 if ( ! command . startsWith ( TASK_PREFIX ) && ! command . startsWith ( QL_PREFIX ) ) {
654628 command = `${ TASK_PREFIX } ${ tab . command } ` ;
655629 }
656- let commandVariable = `real_time=${ Boolean ( realTime ) } no_tee=true ID=${
657- tab . id
658- } `;
630+ let commandVariable = `real_time=${ Boolean ( realTime ) } log_name=${ tab . log_name } no_tee=true ID=${ tab . id } ` ;
659631 if ( tab . task_before ) {
660632 commandVariable += `task_before='${ tab . task_before
661633 . replace ( / ' / g, "'\\''" )
0 commit comments