s3 image file validation

This commit is contained in:
jackiettran
2025-12-12 13:33:24 -05:00
parent 763945fef4
commit 1dee5232a0
20 changed files with 657 additions and 654 deletions

View File

@@ -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: [