Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/note.picotech.app/public_html/src/middleware/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const multer = require('multer');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const { AppError } = require('../middleware/errorHandler');
const fs = require('fs');
const crypto = require('crypto');
const { UserUploadLimit } = require('../models');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const uploadDir = path.join(__dirname, '../../storage/recordings');
// Ensure directory exists
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
cb(null, `${uuidv4()}${ext}`);
}
});
// File signature validation function
const validateFileSignature = async (filePath, mimeType) => {
try {
const buffer = await fs.promises.readFile(filePath, { length: 12 }); // Read first 12 bytes for signature check
// Audio file signatures (magic numbers) with optional offset
const signatures = {
'audio/mpeg': [[0xFF, 0xFB], [0xFF, 0xF3], [0xFF, 0xF2], [0x49, 0x44, 0x33]], // MP3 - offset 0
'audio/wav': [[0x52, 0x49, 0x46, 0x46]], // WAV - offset 0
'audio/mp4': [[0x66, 0x74, 0x79, 0x70, 4]], // MP4 - 'ftyp' at offset 4
'audio/m4a': [[0x66, 0x74, 0x79, 0x70, 4]], // M4A - 'ftyp' at offset 4
'audio/webm': [[0x1A, 0x45, 0xDF, 0xA3]], // WebM - offset 0
'audio/ogg': [[0x4F, 0x67, 0x67, 0x53]] // OGG - offset 0
};
const validSignatures = signatures[mimeType];
if (!validSignatures) {
return false;
}
// Check if file contains any of the valid signatures
const isValid = validSignatures.some(signature => {
const sig = Array.isArray(signature) ? signature : [signature];
const offset = sig.length > 4 && typeof sig[sig.length - 1] === 'number' ? sig.pop() : 0;
for (let i = 0; i < sig.length; i++) {
if (buffer[offset + i] !== sig[i]) {
return false;
}
}
return true;
});
return isValid;
} catch (error) {
return false;
}
};
// Check and update user upload limits (now using database)
const checkUserUploadLimits = async (userId, fileSize) => {
try {
await UserUploadLimit.checkAndUpdateLimits(userId, fileSize);
} catch (error) {
throw new AppError(error.message, 429);
}
};
const fileFilter = async (req, file, cb) => {
const allowedTypes = ['audio/mpeg', 'audio/wav', 'audio/mp4', 'audio/m4a', 'audio/webm', 'audio/ogg'];
// First check MIME type
if (!allowedTypes.includes(file.mimetype)) {
cb(new AppError('Invalid file type. Only audio files are allowed.', 400), false);
return;
}
// For now, accept the file - we'll validate signature after upload
// This is because multer needs the file to be written to disk first for signature validation
cb(null, true);
};
exports.uploadSingle = (fieldName) => {
const upload = multer({
storage,
fileFilter,
limits: {
fileSize: 50 * 1024 * 1024 // 50MB limit per file
}
}).single(fieldName);
// Return middleware that includes post-upload validation and user limits
return (req, res, next) => {
upload(req, res, async (err) => {
if (err) {
return next(err);
}
// If file was uploaded, validate its signature and check user limits
if (req.file) {
const isValidSignature = await validateFileSignature(req.file.path, req.file.mimetype);
if (!isValidSignature) {
// Clean up invalid file
try {
await fs.promises.unlink(req.file.path);
} catch (cleanupError) {
console.error('Failed to clean up invalid file:', cleanupError);
}
return next(new AppError('File content does not match expected audio format.', 400));
}
// Check per-user upload limits
try {
const userId = req.user?.id;
if (userId) {
checkUserUploadLimits(userId, req.file.size);
}
} catch (limitError) {
// Clean up file if limit exceeded
try {
await fs.unlink(req.file.path);
} catch (cleanupError) {
console.error('Failed to clean up file after limit check:', cleanupError);
}
return next(limitError);
}
}
next();
});
};
};
// Export validation function for use in other parts of the application
exports.validateFileSignature = validateFileSignature; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0034 ]-- |