diff --git a/back/services/cron.ts b/back/services/cron.ts index 380428a3..751e49ce 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -477,7 +477,11 @@ export default class CronService { ); let { id, command, log_path, log_name } = cron; - const uniqPath = log_name || (await getUniqPath(command, `${id}`)); + // Sanitize log_name to prevent path traversal + const sanitizedLogName = log_name + ? log_name.replace(/[\/\\\.]/g, '_').replace(/^_+|_+$/g, '') + : ''; + const uniqPath = sanitizedLogName || (await getUniqPath(command, `${id}`)); const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS'); const logDirPath = path.resolve(config.logPath, `${uniqPath}`); if (log_path?.split('/')?.every((x) => x !== uniqPath)) { diff --git a/back/validation/schedule.ts b/back/validation/schedule.ts index f8a503b8..56e15f84 100644 --- a/back/validation/schedule.ts +++ b/back/validation/schedule.ts @@ -37,5 +37,14 @@ export const commonCronSchema = { extra_schedules: Joi.array().optional().allow(null), task_before: Joi.string().optional().allow('').allow(null), task_after: Joi.string().optional().allow('').allow(null), - log_name: Joi.string().optional().allow('').allow(null), + log_name: Joi.string() + .optional() + .allow('') + .allow(null) + .pattern(/^[a-zA-Z0-9_-]+$/) + .max(100) + .messages({ + 'string.pattern.base': '日志名称只能包含字母、数字、下划线和连字符', + 'string.max': '日志名称不能超过100个字符', + }), }; diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 9b7d1ad7..1acaf8ad 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -524,5 +524,7 @@ "清除成功": "Clean successful", "日志名称": "Log Name", "自定义日志文件夹名称,用于区分不同任务的日志,留空则自动生成": "Custom log folder name to distinguish logs from different tasks. Leave blank to auto-generate", - "请输入自定义日志文件夹名称": "Please enter a custom log folder name" + "请输入自定义日志文件夹名称": "Please enter a custom log folder name", + "日志名称只能包含字母、数字、下划线和连字符": "Log name can only contain letters, numbers, underscores and hyphens", + "日志名称不能超过100个字符": "Log name cannot exceed 100 characters" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 42788752..75d40598 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -524,5 +524,7 @@ "清除成功": "清除成功", "日志名称": "日志名称", "自定义日志文件夹名称,用于区分不同任务的日志,留空则自动生成": "自定义日志文件夹名称,用于区分不同任务的日志,留空则自动生成", - "请输入自定义日志文件夹名称": "请输入自定义日志文件夹名称" + "请输入自定义日志文件夹名称": "请输入自定义日志文件夹名称", + "日志名称只能包含字母、数字、下划线和连字符": "日志名称只能包含字母、数字、下划线和连字符", + "日志名称不能超过100个字符": "日志名称不能超过100个字符" } diff --git a/src/pages/crontab/modal.tsx b/src/pages/crontab/modal.tsx index 7f87f427..34c0f9b9 100644 --- a/src/pages/crontab/modal.tsx +++ b/src/pages/crontab/modal.tsx @@ -186,8 +186,21 @@ const CronModal = ({ tooltip={intl.get( '自定义日志文件夹名称,用于区分不同任务的日志,留空则自动生成', )} + rules={[ + { + pattern: /^[a-zA-Z0-9_-]*$/, + message: intl.get('日志名称只能包含字母、数字、下划线和连字符'), + }, + { + max: 100, + message: intl.get('日志名称不能超过100个字符'), + }, + ]} > - +