s3 image file validation
This commit is contained in:
@@ -3,8 +3,56 @@ const { Op } = require("sequelize");
|
||||
const { Item, User, Rental } = require("../models"); // Import from models/index.js to get models with associations
|
||||
const { authenticateToken, requireVerifiedEmail, requireAdmin, optionalAuth } = require("../middleware/auth");
|
||||
const logger = require("../utils/logger");
|
||||
const { validateS3Keys } = require("../utils/s3KeyValidator");
|
||||
const { IMAGE_LIMITS } = require("../config/imageLimits");
|
||||
const router = express.Router();
|
||||
|
||||
// Allowed fields for item create/update (prevents mass assignment)
|
||||
const ALLOWED_ITEM_FIELDS = [
|
||||
'name',
|
||||
'description',
|
||||
'pickUpAvailable',
|
||||
'localDeliveryAvailable',
|
||||
'localDeliveryRadius',
|
||||
'shippingAvailable',
|
||||
'inPlaceUseAvailable',
|
||||
'pricePerHour',
|
||||
'pricePerDay',
|
||||
'pricePerWeek',
|
||||
'pricePerMonth',
|
||||
'replacementCost',
|
||||
'address1',
|
||||
'address2',
|
||||
'city',
|
||||
'state',
|
||||
'zipCode',
|
||||
'country',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'imageFilenames',
|
||||
'isAvailable',
|
||||
'rules',
|
||||
'availableAfter',
|
||||
'availableBefore',
|
||||
'specifyTimesPerDay',
|
||||
'weeklyTimes',
|
||||
];
|
||||
|
||||
/**
|
||||
* Extract only allowed fields from request body
|
||||
* @param {Object} body - Request body
|
||||
* @returns {Object} - Object with only allowed fields
|
||||
*/
|
||||
function extractAllowedFields(body) {
|
||||
const result = {};
|
||||
for (const field of ALLOWED_ITEM_FIELDS) {
|
||||
if (body[field] !== undefined) {
|
||||
result[field] = body[field];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
router.get("/", async (req, res, next) => {
|
||||
try {
|
||||
const {
|
||||
@@ -232,8 +280,27 @@ router.get("/:id", optionalAuth, async (req, res, next) => {
|
||||
|
||||
router.post("/", authenticateToken, requireVerifiedEmail, async (req, res, next) => {
|
||||
try {
|
||||
// Extract only allowed fields (prevents mass assignment)
|
||||
const allowedData = extractAllowedFields(req.body);
|
||||
|
||||
// Validate imageFilenames if provided
|
||||
if (allowedData.imageFilenames) {
|
||||
const imageFilenames = Array.isArray(allowedData.imageFilenames)
|
||||
? allowedData.imageFilenames
|
||||
: [];
|
||||
|
||||
const keyValidation = validateS3Keys(imageFilenames, 'items', { maxKeys: IMAGE_LIMITS.items });
|
||||
if (!keyValidation.valid) {
|
||||
return res.status(400).json({
|
||||
error: keyValidation.error,
|
||||
details: keyValidation.invalidKeys
|
||||
});
|
||||
}
|
||||
allowedData.imageFilenames = imageFilenames;
|
||||
}
|
||||
|
||||
const item = await Item.create({
|
||||
...req.body,
|
||||
...allowedData,
|
||||
ownerId: req.user.id,
|
||||
});
|
||||
|
||||
@@ -300,7 +367,26 @@ router.put("/:id", authenticateToken, async (req, res, next) => {
|
||||
return res.status(403).json({ error: "Unauthorized" });
|
||||
}
|
||||
|
||||
await item.update(req.body);
|
||||
// Extract only allowed fields (prevents mass assignment)
|
||||
const allowedData = extractAllowedFields(req.body);
|
||||
|
||||
// Validate imageFilenames if provided
|
||||
if (allowedData.imageFilenames !== undefined) {
|
||||
const imageFilenames = Array.isArray(allowedData.imageFilenames)
|
||||
? allowedData.imageFilenames
|
||||
: [];
|
||||
|
||||
const keyValidation = validateS3Keys(imageFilenames, 'items', { maxKeys: IMAGE_LIMITS.items });
|
||||
if (!keyValidation.valid) {
|
||||
return res.status(400).json({
|
||||
error: keyValidation.error,
|
||||
details: keyValidation.invalidKeys
|
||||
});
|
||||
}
|
||||
allowedData.imageFilenames = imageFilenames;
|
||||
}
|
||||
|
||||
await item.update(allowedData);
|
||||
|
||||
const updatedItem = await Item.findByPk(item.id, {
|
||||
include: [
|
||||
|
||||
Reference in New Issue
Block a user