diff --git a/src/pty/windowsPtyAgent.ts b/src/pty/windowsPtyAgent.ts index 8b36780a..de30a61f 100644 --- a/src/pty/windowsPtyAgent.ts +++ b/src/pty/windowsPtyAgent.ts @@ -203,7 +203,13 @@ export class WindowsPtyAgent { } private _getWindowsBuildNumber(): number { - const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release()); + const release = os.release(); + // Limit input length to prevent potential DoS attacks + if (release.length > 50) { + return 0; + } + // Use non-global regex with more specific pattern to prevent backtracking + const osVersion = /^(\d{1,5})\.(\d{1,5})\.(\d{1,10})/.exec(release); let buildNumber: number = 0; if (osVersion && osVersion.length === 4) { buildNumber = parseInt(osVersion[3]!); diff --git a/src/webui/src/terminal/init-dynamic-dirname.ts b/src/webui/src/terminal/init-dynamic-dirname.ts index 9b5b0008..b4e99f4c 100644 --- a/src/webui/src/terminal/init-dynamic-dirname.ts +++ b/src/webui/src/terminal/init-dynamic-dirname.ts @@ -1,21 +1,30 @@ -import path from 'path'; +import path from 'path' +import { fileURLToPath } from 'url' + +export function callsites () { + const _prepareStackTrace = Error.prepareStackTrace + try { + let result: NodeJS.CallSite[] = [] + Error.prepareStackTrace = (_, callSites) => { + const callSitesWithoutCurrent = callSites.slice(1) + result = callSitesWithoutCurrent + return callSitesWithoutCurrent + } + + new Error().stack + return result + } finally { + Error.prepareStackTrace = _prepareStackTrace + } +} Object.defineProperty(global, '__dirname', { - get() { - const err = new Error(); - const stack = err.stack?.split('\n') || []; - let callerFile = ''; - // 遍历错误堆栈,跳过当前文件所在行 - // 注意:堆栈格式可能不同,请根据实际环境调整索引及正则表达式 - for (const line of stack) { - const match = line.match(/\((.*):\d+:\d+\)/); - if (match?.[1]) { - callerFile = match[1]; - if (!callerFile.includes('init-dynamic-dirname.ts')) { - break; - } - } + get () { + const sites = callsites() + const file = sites?.[1]?.getFileName() + if (file) { + return path.dirname(fileURLToPath(file)) } - return callerFile ? path.dirname(callerFile) : ''; + return '' }, -}); +}) diff --git a/src/webui/src/terminal/terminal_manager.ts b/src/webui/src/terminal/terminal_manager.ts index 077510dd..135363d8 100644 --- a/src/webui/src/terminal/terminal_manager.ts +++ b/src/webui/src/terminal/terminal_manager.ts @@ -1,4 +1,4 @@ -import './init-dynamic-dirname'; +// import './init-dynamic-dirname'; import { WebUiConfig } from '@/webui'; import { AuthHelper } from '../helper/SignToken'; import { LogWrapper } from '@/common/log'; diff --git a/src/webui/src/uploader/disk.ts b/src/webui/src/uploader/disk.ts index d877ce9e..91fc1e04 100644 --- a/src/webui/src/uploader/disk.ts +++ b/src/webui/src/uploader/disk.ts @@ -66,7 +66,15 @@ export const createDiskStorage = (uploadPath: string) => { }; export const createDiskUpload = (uploadPath: string) => { - const upload = multer({ storage: createDiskStorage(uploadPath) }).array('files'); + const upload = multer({ + storage: createDiskStorage(uploadPath), + limits: { + fileSize: 100 * 1024 * 1024, // 100MB 文件大小限制 + files: 20, // 最多同时上传20个文件 + fieldSize: 1024 * 1024, // 1MB 字段大小限制 + fields: 10 // 最多10个字段 + } + }).array('files'); return upload; }; @@ -76,6 +84,18 @@ const diskUploader = (req: Request, res: Response) => { createDiskUpload(uploadPath)(req, res, (error) => { if (error) { // 错误处理 + if (error.code === 'LIMIT_FILE_SIZE') { + return reject(new Error('文件大小超过限制(最大100MB)')); + } + if (error.code === 'LIMIT_FILE_COUNT') { + return reject(new Error('文件数量超过限制(最多20个文件)')); + } + if (error.code === 'LIMIT_FIELD_VALUE') { + return reject(new Error('字段值大小超过限制')); + } + if (error.code === 'LIMIT_FIELD_COUNT') { + return reject(new Error('字段数量超过限制')); + } return reject(error); } return resolve(true);