From 213ee53347537ee8f3964490ec173b293bd52e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=9B=E4=B9=8B=E9=9B=A8?= <49258735+taozhiyu@users.noreply.github.com> Date: Tue, 5 Aug 2025 22:35:40 +0800 Subject: [PATCH] Add input validation to script API routes Introduces Joi-based validation using celebrate for query, params, and body inputs on all script API endpoints. Also normalizes empty 'path' values to an empty string where necessary to prevent errors. This improves API robustness and input safety. --- back/api/script.ts | 51 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/back/api/script.ts b/back/api/script.ts index 1bf85565..ee6db133 100644 --- a/back/api/script.ts +++ b/back/api/script.ts @@ -24,7 +24,14 @@ const upload = multer({ storage: storage }); export default (app: Router) => { app.use('/scripts', route); - route.get('/', async (req: Request, res: Response, next: NextFunction) => { + route.get( + '/', + celebrate({ + query: Joi.object({ + path: Joi.string().optional().allow(''), + }), + }), + async (req: Request, res: Response, next: NextFunction) => { const logger: Logger = Container.get('logger'); try { let result: IFile[] = []; @@ -68,6 +75,12 @@ export default (app: Router) => { route.get( '/detail', + celebrate({ + query: Joi.object({ + path: Joi.string().required(), + file: Joi.string().required(), + }), + }), async (req: Request, res: Response, next: NextFunction) => { try { const scriptService = Container.get(ScriptService); @@ -84,12 +97,20 @@ export default (app: Router) => { route.get( '/:file', + celebrate({ + params: Joi.object({ + file: Joi.string().required(), + }), + query: Joi.object({ + path: Joi.string().optional().allow(''), + }), + }), async (req: Request, res: Response, next: NextFunction) => { try { const scriptService = Container.get(ScriptService); const content = await scriptService.getFile( req.query.path as string, - req.params.file, + req.params?.file || '', ); res.send({ code: 200, data: content }); } catch (e) { @@ -101,6 +122,15 @@ export default (app: Router) => { route.post( '/', upload.single('file'), + celebrate({ + body: Joi.object({ + filename: Joi.string().required(), + path: Joi.string().optional().allow(''), + content: Joi.string().optional().allow(''), + originFilename: Joi.string().optional().allow(''), + directory: Joi.string().optional().allow(''), + }), + }), async (req: Request, res: Response, next: NextFunction) => { try { let { filename, path, content, originFilename, directory } = @@ -201,7 +231,7 @@ export default (app: Router) => { celebrate({ body: Joi.object({ filename: Joi.string().required(), - path: Joi.string().allow(''), + path: Joi.string().optional().allow(''), type: Joi.string().optional(), }), }), @@ -211,6 +241,9 @@ export default (app: Router) => { filename: string; path: string; }; + if (!path) { + path = ''; + } const scriptService = Container.get(ScriptService); const filePath = scriptService.checkFilePath(path, filename); if (!filePath) { @@ -276,6 +309,9 @@ export default (app: Router) => { const logger: Logger = Container.get('logger'); try { let { filename, content, path } = req.body; + if (!path) { + path = ''; + } const { name, ext } = parse(filename); const filePath = join(config.scriptPath, path, `${name}.swap${ext}`); await writeFileWithLock(filePath, content || ''); @@ -301,6 +337,9 @@ export default (app: Router) => { async (req: Request, res: Response, next: NextFunction) => { try { let { filename, path, pid } = req.body; + if (!path) { + path = ''; + } const { name, ext } = parse(filename); const filePath = join(config.scriptPath, path, `${name}.swap${ext}`); const logPath = join(config.logPath, path, `${name}.swap`); @@ -328,12 +367,14 @@ export default (app: Router) => { }), async (req: Request, res: Response, next: NextFunction) => { try { - let { filename, path, type, newFilename } = req.body as { + let { filename, path, newFilename } = req.body as { filename: string; path: string; - type: string; newFilename: string; }; + if (!path) { + path = ''; + } const filePath = join(config.scriptPath, path, filename); const newPath = join(config.scriptPath, path, newFilename); await fs.rename(filePath, newPath);