From dd12dc99da0bbf5da5481fa64cb02acfaad42ed4 Mon Sep 17 00:00:00 2001 From: robbond Date: Wed, 21 Jan 2026 13:17:03 +0000 Subject: [PATCH] 21099 api serverside validation check --- .../representation/representationElements.js | 6 +- components/elements/index.js | 7 +- pages/api/file/uploadsinglefile.js | 75 ++++++++----------- 3 files changed, 38 insertions(+), 50 deletions(-) diff --git a/components/case/representation/representationElements.js b/components/case/representation/representationElements.js index db0675b3..94a577ce 100644 --- a/components/case/representation/representationElements.js +++ b/components/case/representation/representationElements.js @@ -1087,7 +1087,7 @@ export const RenderFileUpload = (field) => { setRejectedFiles([]); // Clear any previously rejected file errorsss }; - const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-()]+$/; + const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-:()]+$/; const validateFilename = (file, t) => { const name = file.name; @@ -1112,8 +1112,8 @@ export const RenderFileUpload = (field) => { }; } - // block characters < > : " / \ | ? * - if (/[<>:"/\\|?*]/.test(name)) { + // block characters < > " / \ | ? * + if (/[<>"/\\|?*]/.test(name)) { return { code: "filename-invalid-chars", message: `${name} ${t( diff --git a/components/elements/index.js b/components/elements/index.js index 72431681..2e6256f0 100644 --- a/components/elements/index.js +++ b/components/elements/index.js @@ -2175,7 +2175,7 @@ const RenderFileUpload = (field) => { setRejectedFiles([]); // Clear any previously rejected file errorsss }; - const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-()]+$/; + const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-:()]+$/; const validateFilename = (file, t) => { const name = file.name; @@ -2190,7 +2190,6 @@ const RenderFileUpload = (field) => { }; } - // broader blocklist (optional but recommended) if (!FILENAME_ALLOWED.test(name)) { return { code: "filename-invalid-chars", @@ -2200,8 +2199,8 @@ const RenderFileUpload = (field) => { }; } - // block characters < > : " / \ | ? * - if (/[<>:"/\\|?*]/.test(name)) { + // block characters < > " / \ | ? * + if (/[<>"/\\|?*]/.test(name)) { return { code: "filename-invalid-chars", message: `${name} ${t( diff --git a/pages/api/file/uploadsinglefile.js b/pages/api/file/uploadsinglefile.js index bc7af6e0..a99192fd 100644 --- a/pages/api/file/uploadsinglefile.js +++ b/pages/api/file/uploadsinglefile.js @@ -11,14 +11,31 @@ import { fileTypeFromBuffer } from "file-type"; import fs from "fs"; import path from "path"; +const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-:()]+$/; + +function validateFilenameServer(originalFilename) { + const name = path.basename(originalFilename || ""); + + if (!name) return { ok: false, reason: "Empty filename" }; + + if (name.includes("#")) return { ok: false, reason: "Filename contains #" }; + + if (/[<>"/\\|?*]/.test(name)) + return { ok: false, reason: "Filename contains reserved characters" }; + + if (!FILENAME_ALLOWED.test(name)) + return { ok: false, reason: "Filename contains invalid characters" }; + + if (name === "." || name === "..") + return { ok: false, reason: "Invalid filename" }; + + return { ok: true, name }; +} const ApiProxy = nextConnect(); ApiProxy.use(middleware); ApiProxy.post(async (req, res) => { var checkHash = req.query.hash; - // console.log(JSON.stringify(req.body)); - // console.log(JSON.stringify(req.body.appealData)); - // console.log(req.files); const containerID = req.body.containerID[0]; const casefolderID = req.body.casefolderID[0]; @@ -40,23 +57,21 @@ ApiProxy.post(async (req, res) => { var allowedFilesFormData = {}; var invalidFiles = []; // To store the names of invalid files - // for (const [fileName, fileDetails] of Object.entries(req.files)) { - // if (allowedMimeTypes.includes(fileDetails[0].headers["content-type"])) { - // allowedFilesFormData[fileName] = fileDetails.map((file) => ({ - // fieldName: file.fieldName, - // originalFilename: file.originalFilename, - // path: file.path, - // size: file.size, - // headers: file.headers, - // contentType: file.headers["content-type"], - // })); - // } - // } - for (const [fileName, fileDetails] of Object.entries(req.files)) { const file = fileDetails[0]; const filePath = file.path; + // validate ORIGINAL filename from upload + const fnCheck = validateFilenameServer(file.originalFilename); + + if (!fnCheck.ok) { + console.log( + `File ${file.originalFilename} rejected: ${fnCheck.reason}` + ); + invalidFiles.push(`${file.originalFilename} - Invalid filename`); + continue; // do not process further + } + // Check the MIME type from file headers const fileMimeType = file.headers["content-type"]; if (allowedMimeTypes.includes(fileMimeType)) { @@ -83,53 +98,27 @@ ApiProxy.post(async (req, res) => { `\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n\nFile ${fileName} has an invalid MIME type based on its content.\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\` ); invalidFiles.push(fileName); // Track invalid file - - // return res - // .status(400) - // .json({ error: `Invalid file type for ${fileName}` }); } } catch (error) { console.log( `Error reading file ${fileName} for MIME type validation`, error ); - // return res - // .status(500) - // .json({ error: "Failed to validate file type" }); } } else { console.log( `\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n\nFile ${fileName} has an unsupported MIME type: ${fileMimeType}\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\` ); invalidFiles.push(fileName); // Track invalid file - - // return res.status(400).json({ - // error: `Unsupported MIME type for ${fileName}`, - // }); } } - //console.log("allowedFilesFormData: ", allowedFilesFormData); - - // If no valid files are found - // if (Object.keys(allowedFilesFormData).length === 0) { - // return res.status(400).json({ - // error: "No valid files found", - // invalidFiles: invalidFiles, // Return the list of invalid files - // }); - // } - - invalidFiles = invalidFiles.map((fileName) => { - return `${fileName} - Invalid file`; - }); try { const data = await uploadSingleFile( allowedFilesFormData, containerID, casefolderID - ).then((data) => { - return res.status(200).json({ data, invalidFiles }); - }); + ); return res.status(200).json({ data, invalidFiles }); } catch (error) { consoleLogger(error);