s3 image file validation
This commit is contained in:
@@ -1,13 +1,41 @@
|
||||
const express = require('express');
|
||||
const { User, UserAddress } = require('../models'); // Import from models/index.js to get models with associations
|
||||
const { authenticateToken } = require('../middleware/auth');
|
||||
const { uploadProfileImage } = require('../middleware/upload');
|
||||
const logger = require('../utils/logger');
|
||||
const userService = require('../services/UserService');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { validateS3Keys } = require('../utils/s3KeyValidator');
|
||||
const { IMAGE_LIMITS } = require('../config/imageLimits');
|
||||
const router = express.Router();
|
||||
|
||||
// Allowed fields for profile update (prevents mass assignment)
|
||||
const ALLOWED_PROFILE_FIELDS = [
|
||||
'firstName',
|
||||
'lastName',
|
||||
'email',
|
||||
'phone',
|
||||
'address1',
|
||||
'address2',
|
||||
'city',
|
||||
'state',
|
||||
'zipCode',
|
||||
'country',
|
||||
'imageFilename',
|
||||
'itemRequestNotificationRadius',
|
||||
];
|
||||
|
||||
/**
|
||||
* Extract only allowed fields from request body
|
||||
*/
|
||||
function extractAllowedProfileFields(body) {
|
||||
const result = {};
|
||||
for (const field of ALLOWED_PROFILE_FIELDS) {
|
||||
if (body[field] !== undefined) {
|
||||
result[field] = body[field];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
router.get('/profile', authenticateToken, async (req, res, next) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.user.id, {
|
||||
@@ -182,8 +210,22 @@ router.get('/:id', async (req, res, next) => {
|
||||
|
||||
router.put('/profile', authenticateToken, async (req, res, next) => {
|
||||
try {
|
||||
// Extract only allowed fields (prevents mass assignment)
|
||||
const allowedData = extractAllowedProfileFields(req.body);
|
||||
|
||||
// Validate imageFilename if provided
|
||||
if (allowedData.imageFilename !== undefined && allowedData.imageFilename !== null) {
|
||||
const keyValidation = validateS3Keys([allowedData.imageFilename], 'profiles', { maxKeys: IMAGE_LIMITS.profile });
|
||||
if (!keyValidation.valid) {
|
||||
return res.status(400).json({
|
||||
error: keyValidation.error,
|
||||
details: keyValidation.invalidKeys
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Use UserService to handle update and email notification
|
||||
const updatedUser = await userService.updateProfile(req.user.id, req.body);
|
||||
const updatedUser = await userService.updateProfile(req.user.id, allowedData);
|
||||
|
||||
res.json(updatedUser);
|
||||
} catch (error) {
|
||||
@@ -192,65 +234,4 @@ router.put('/profile', authenticateToken, async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Upload profile image endpoint
|
||||
router.post('/profile/image', authenticateToken, (req, res) => {
|
||||
uploadProfileImage(req, res, async (err) => {
|
||||
if (err) {
|
||||
const reqLogger = logger.withRequestId(req.id);
|
||||
reqLogger.error("Profile image upload error", {
|
||||
error: err.message,
|
||||
userId: req.user.id
|
||||
});
|
||||
return res.status(400).json({ error: err.message });
|
||||
}
|
||||
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ error: 'No file uploaded' });
|
||||
}
|
||||
|
||||
try {
|
||||
// Delete old profile image if exists
|
||||
const user = await User.findByPk(req.user.id);
|
||||
if (user.imageFilename) {
|
||||
const oldImagePath = path.join(__dirname, '../uploads/profiles', user.imageFilename);
|
||||
try {
|
||||
await fs.unlink(oldImagePath);
|
||||
} catch (unlinkErr) {
|
||||
const reqLogger = logger.withRequestId(req.id);
|
||||
reqLogger.warn("Error deleting old profile image", {
|
||||
error: unlinkErr.message,
|
||||
userId: req.user.id,
|
||||
oldImagePath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update user with new image filename
|
||||
await user.update({
|
||||
imageFilename: req.file.filename
|
||||
});
|
||||
|
||||
const reqLogger = logger.withRequestId(req.id);
|
||||
reqLogger.info("Profile image uploaded successfully", {
|
||||
userId: req.user.id,
|
||||
filename: req.file.filename
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Profile image uploaded successfully',
|
||||
filename: req.file.filename,
|
||||
imageUrl: `/uploads/profiles/${req.file.filename}`
|
||||
});
|
||||
} catch (error) {
|
||||
const reqLogger = logger.withRequestId(req.id);
|
||||
reqLogger.error("Profile image database update failed", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
userId: req.user.id
|
||||
});
|
||||
res.status(500).json({ error: 'Failed to update profile image' });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user