webupdatev1
This commit is contained in:
@@ -9,6 +9,55 @@ const logger = require("../config/logger");
|
||||
const { uploadLimiter } = require("../config/rateLimiter");
|
||||
require("dotenv").config();
|
||||
|
||||
// Magic bytes for image file validation
|
||||
const MAGIC_BYTES = {
|
||||
jpeg: [0xff, 0xd8, 0xff],
|
||||
png: [0x89, 0x50, 0x4e, 0x47],
|
||||
gif: [0x47, 0x49, 0x46],
|
||||
webp: [0x52, 0x49, 0x46, 0x46],
|
||||
};
|
||||
|
||||
// Validate file content by checking magic bytes
|
||||
const validateFileContent = async (filePath, mimetype) => {
|
||||
try {
|
||||
const buffer = Buffer.alloc(8);
|
||||
const fd = await fs.open(filePath, "r");
|
||||
await fd.read(buffer, 0, 8, 0);
|
||||
await fd.close();
|
||||
|
||||
// Check JPEG
|
||||
if (mimetype === "image/jpeg" || mimetype === "image/jpg") {
|
||||
return buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff;
|
||||
}
|
||||
// Check PNG
|
||||
if (mimetype === "image/png") {
|
||||
return (
|
||||
buffer[0] === 0x89 &&
|
||||
buffer[1] === 0x50 &&
|
||||
buffer[2] === 0x4e &&
|
||||
buffer[3] === 0x47
|
||||
);
|
||||
}
|
||||
// Check GIF
|
||||
if (mimetype === "image/gif") {
|
||||
return buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46;
|
||||
}
|
||||
// Check WebP
|
||||
if (mimetype === "image/webp") {
|
||||
return (
|
||||
buffer[0] === 0x52 &&
|
||||
buffer[1] === 0x49 &&
|
||||
buffer[2] === 0x46 &&
|
||||
buffer[3] === 0x46
|
||||
);
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
logger.error("Magic byte validation error:", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Allowed file types
|
||||
const ALLOWED_MIME_TYPES = (
|
||||
process.env.ALLOWED_FILE_TYPES || "image/jpeg,image/png,image/gif,image/webp"
|
||||
@@ -97,6 +146,28 @@ router.post(
|
||||
const folderId = req.body.folder_id ? parseInt(req.body.folder_id) : null;
|
||||
const files = [];
|
||||
|
||||
// Validate file content with magic bytes
|
||||
for (const file of req.files) {
|
||||
const isValid = await validateFileContent(file.path, file.mimetype);
|
||||
if (!isValid) {
|
||||
logger.warn("File upload rejected - magic byte mismatch", {
|
||||
filename: file.filename,
|
||||
mimetype: file.mimetype,
|
||||
userId: uploadedBy,
|
||||
});
|
||||
// Clean up invalid file
|
||||
await fs
|
||||
.unlink(file.path)
|
||||
.catch((err) =>
|
||||
logger.error("Failed to clean up invalid file:", err)
|
||||
);
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `File ${file.originalname} failed security validation`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Insert each file into database
|
||||
for (const file of req.files) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user