const crypto = require('crypto'); const fs = require('fs'); const multer = require('multer'); const path = require('path'); const MAX_PROFILE_PHOTO_SIZE_BYTES = 5 * 1024 * 1024; const PROFILE_UPLOADS_DIR = path.resolve(__dirname, '..', '..', 'uploads', 'profile'); const ALLOWED_MIME_TYPES = new Set(['image/jpeg', 'image/png']); const ensureProfileUploadsDir = () => { fs.mkdirSync(PROFILE_UPLOADS_DIR, { recursive: true }); }; const sanitizeFileBaseName = (originalName) => { const baseName = path.basename(originalName || 'profile_photo', path.extname(originalName || '')); const sanitized = baseName .replace(/[^a-zA-Z0-9_-]/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, '') .slice(0, 40); return sanitized || 'profile_photo'; }; const getExtensionFromMimeType = (mimeType) => (mimeType === 'image/png' ? '.png' : '.jpg'); const storage = multer.diskStorage({ destination: (req, file, cb) => { try { ensureProfileUploadsDir(); cb(null, PROFILE_UPLOADS_DIR); } catch (error) { cb(error); } }, filename: (req, file, cb) => { const safeBaseName = sanitizeFileBaseName(file.originalname); const uniqueSuffix = `${Date.now()}_${crypto.randomBytes(6).toString('hex')}`; const extension = getExtensionFromMimeType(file.mimetype); cb(null, `${safeBaseName}_${uniqueSuffix}${extension}`); } }); const internalUpload = multer({ storage, limits: { fileSize: MAX_PROFILE_PHOTO_SIZE_BYTES, files: 1 }, fileFilter: (req, file, cb) => { if (!ALLOWED_MIME_TYPES.has(file.mimetype)) { return cb(new Error('INVALID_FILE_TYPE')); } cb(null, true); } }); const uploadProfilePhoto = (req, res, next) => { internalUpload.single('foto_perfil')(req, res, (error) => { if (!error) { return next(); } if (error instanceof multer.MulterError) { if (error.code === 'LIMIT_FILE_SIZE') { return res.status(400).json({ error: 'Archivo demasiado grande. Maximo 5MB.' }); } return res.status(400).json({ error: 'Archivo invalido.' }); } if (error.message === 'INVALID_FILE_TYPE') { return res.status(400).json({ error: 'Tipo de archivo invalido. Solo se permite image/jpeg o image/png.' }); } console.error('Error uploading profile photo:', error); return res.status(500).json({ error: 'Internal server error' }); }); }; module.exports = { uploadProfilePhoto };