mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
fix: validate image-only uploads and respect allowed_file_types setting for journey photos
Add fileFilter to the journey photo multer config (shared by entry photo upload and gallery upload routes): - Rejects any non-image MIME type (including SVG which carries XSS risk) - Checks the extension against the admin-configured allowed_file_types setting (same getAllowedExtensions() used by the trip file upload route) - Returns HTTP 400 with a descriptive message on rejection Also fix the global error handler to return err.message for 4xx responses instead of the generic 'Internal server error', so fileFilter rejections produce a readable error on the client.
This commit is contained in:
+4
-2
@@ -372,8 +372,10 @@ export function createApp(): express.Application {
|
||||
} else {
|
||||
console.error('Unhandled error:', err);
|
||||
}
|
||||
const status = err.statusCode || 500;
|
||||
res.status(status).json({ error: 'Internal server error' });
|
||||
const status = err.statusCode || err.status || 500;
|
||||
// Expose the message for client errors (4xx); keep 'Internal server error' for 5xx.
|
||||
const message = status < 500 ? err.message : 'Internal server error';
|
||||
res.status(status).json({ error: message });
|
||||
});
|
||||
|
||||
return app;
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as svc from '../services/journeyService';
|
||||
import { db } from '../db/database';
|
||||
import { createOrUpdateJourneyShareLink, getJourneyShareLink, deleteJourneyShareLink, getPublicJourney } from '../services/journeyShareService';
|
||||
import { uploadToImmich } from '../services/memories/immichService';
|
||||
import { getAllowedExtensions } from '../services/fileService';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -25,9 +26,26 @@ const storage = multer.diskStorage({
|
||||
},
|
||||
});
|
||||
|
||||
const imageFilter: multer.Options['fileFilter'] = (_req, file, cb) => {
|
||||
if (!file.mimetype.startsWith('image/') || file.mimetype.includes('svg')) {
|
||||
const err: Error & { statusCode?: number } = new Error('Only image files are allowed');
|
||||
err.statusCode = 400;
|
||||
return cb(err);
|
||||
}
|
||||
const ext = path.extname(file.originalname).toLowerCase().replace('.', '');
|
||||
const allowed = getAllowedExtensions().split(',').map(e => e.trim().toLowerCase());
|
||||
if (!allowed.includes('*') && !allowed.includes(ext)) {
|
||||
const err: Error & { statusCode?: number } = new Error(`File type .${ext} is not allowed`);
|
||||
err.statusCode = 400;
|
||||
return cb(err);
|
||||
}
|
||||
cb(null, true);
|
||||
};
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: 20 * 1024 * 1024 },
|
||||
fileFilter: imageFilter,
|
||||
});
|
||||
|
||||
// ── Static prefix routes (MUST come before /:id) ─────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user