diff --git a/package.json b/package.json index 3bc3b484..04575588 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "date-fns": "^2.30.0", "dom": "^0.0.3", "express": "^4.18.2", + "file-type": "^20.4.1", "fs": "0.0.2", "google-map-react": "^2.2.1", "govuk-frontend": "^5.0.0", diff --git a/pages/api/file/uploadsinglefile.js b/pages/api/file/uploadsinglefile.js index 382c0888..d84d239a 100644 --- a/pages/api/file/uploadsinglefile.js +++ b/pages/api/file/uploadsinglefile.js @@ -7,6 +7,9 @@ import { import nextConnect from "next-connect"; import middleware from "../middleware/middleware"; import { consoleLogger } from "../../../actions"; +import { fileTypeFromBuffer } from "file-type"; +import fs from "fs"; +import path from "path"; const ApiProxy = nextConnect(); ApiProxy.use(middleware); @@ -36,19 +39,70 @@ ApiProxy.post(async (req, res) => { var allowedFilesFormData = {}; + // 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)) { - 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"], - })); + const file = fileDetails[0]; + const filePath = file.path; + + // Check the MIME type from file headers + const fileMimeType = file.headers["content-type"]; + if (allowedMimeTypes.includes(fileMimeType)) { + // Check file signature (magic number) using file-type + const buffer = fs.readFileSync(filePath); + + try { + const type = await fileTypeFromBuffer(buffer); // Correct usage of fileTypeFromBuffer + console.log("checking mime type ", type); + if (type && allowedMimeTypes.includes(type.mime)) { + // If the MIME type from the file signature matches the allowed list + allowedFilesFormData[fileName] = fileDetails.map( + (file) => ({ + fieldName: file.fieldName, + originalFilename: file.originalFilename, + path: file.path, + size: file.size, + headers: file.headers, + contentType: fileMimeType, + }) + ); + } else { + console.log( + `\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n\nFile ${fileName} has an invalid MIME type based on its content.\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\` + ); + 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\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\` + ); + return res.status(400).json({ + error: `Unsupported MIME type for ${fileName}`, + }); } } - //console.log("allowedFilesFormData: ", allowedFilesFormData); try {