UNPKG

secure-express-setup

Version:

Military-grade one-command security setup for Express.js applications

66 lines (60 loc) 2.02 kB
// lib/fileValidation.js /** * File validation helper that dynamically imports 'file-type' (ESM-only) * Exports a factory function (setupFileValidation) that returns { validateFile, middleware } */ function setupFileValidation() { const allowedMimeTypes = [ 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'application/pdf', 'text/plain' ]; // lazy detector that works with ESM-only file-type v18+ async function detectFileType(buffer) { if (!buffer) return null; const ft = await import('file-type'); if (ft && typeof ft.fileTypeFromBuffer === 'function') { return await ft.fileTypeFromBuffer(buffer); } if (ft && typeof ft.fromBuffer === 'function') { return await ft.fromBuffer(buffer); } return null; } async function validateFile(buffer, allowedTypes = allowedMimeTypes) { try { const type = await detectFileType(buffer); if (!type) throw new Error('Unable to determine file type'); if (!allowedTypes.includes(type.mime)) { throw new Error(`File type ${type.mime} not allowed`); } return { valid: true, mime: type.mime, ext: type.ext }; } catch (err) { return { valid: false, error: err.message }; } } return { validateFile, middleware: (allowedTypes) => { return async (req, res, next) => { try { if (!req.file && !req.files) return next(); const files = req.files || [req.file]; for (const file of files) { const result = await validateFile(file.buffer, allowedTypes); if (!result.valid) { return res.status(400).json({ error: 'Invalid file type', details: result.error }); } } next(); } catch (err) { return res.status(500).json({ error: 'File validation error', details: err.message }); } }; } }; } module.exports = setupFileValidation;