From bbcacf3272fa298234fc6d6c9707795bd206558c Mon Sep 17 00:00:00 2001 From: om-dev007 Date: Mon, 29 Jun 2026 15:15:08 +0530 Subject: [PATCH] feat(auth): add request validation and input sanitization for auth endpoints --- backend/package-lock.json | 26 +++++++ backend/package.json | 1 + backend/src/controllers/authController.ts | 5 -- .../src/middleware/validationMiddleware.ts | 72 +++++++++++++++++++ backend/src/routes/authRoutes.ts | 5 +- 5 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 backend/src/middleware/validationMiddleware.ts diff --git a/backend/package-lock.json b/backend/package-lock.json index 03b2478..1c7292f 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -20,6 +20,7 @@ "dotenv": "^16.6.1", "express": "^4.19.2", "express-rate-limit": "^8.5.2", + "express-validator": "^7.3.2", "google-auth-library": "^10.5.0", "helmet": "^8.2.0", "jsonwebtoken": "^9.0.3", @@ -1784,6 +1785,18 @@ "express": ">= 4.11" } }, + "node_modules/express-validator": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.3.2.tgz", + "integrity": "sha512-ctLw1Vl6dXVH62dIQMDdTAQkrh480mkFuG6/SGXOaVlwPNukhRAe7EgJIMJ2TSAni8iwHBRp530zAZE5ZPF2IA==", + "dependencies": { + "lodash": "^4.18.1", + "validator": "~13.15.23" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", @@ -2760,6 +2773,11 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -4129,6 +4147,14 @@ "dev": true, "license": "MIT" }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/backend/package.json b/backend/package.json index 2f21197..9f99311 100644 --- a/backend/package.json +++ b/backend/package.json @@ -26,6 +26,7 @@ "dotenv": "^16.6.1", "express": "^4.19.2", "express-rate-limit": "^8.5.2", + "express-validator": "^7.3.2", "google-auth-library": "^10.5.0", "helmet": "^8.2.0", "jsonwebtoken": "^9.0.3", diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/authController.ts index 6097a4a..eeff6f4 100644 --- a/backend/src/controllers/authController.ts +++ b/backend/src/controllers/authController.ts @@ -18,11 +18,6 @@ const generateToken = (id: string) => { export const registerUser = async (req: Request, res: Response) => { const { name, email, password } = req.body; - if (!name || !email || !password) { - res.status(400).json({ message: 'Please add all fields' }); - return; - } - const userExists = await prisma.user.findUnique({ where: { email } }); if (userExists) { diff --git a/backend/src/middleware/validationMiddleware.ts b/backend/src/middleware/validationMiddleware.ts new file mode 100644 index 0000000..f1b40a2 --- /dev/null +++ b/backend/src/middleware/validationMiddleware.ts @@ -0,0 +1,72 @@ +import { Request, Response, NextFunction } from 'express'; +import { body, validationResult } from 'express-validator'; + +/** + * Register Validation + */ +export const registerValidation = [ + body('name') + .trim() + .notEmpty() + .withMessage('Name is required') + .isLength({ min: 2, max: 50 }) + .withMessage('Name must be between 2 and 50 characters'), + + body('email') + .trim() + .notEmpty() + .withMessage('Email is required') + .isEmail() + .withMessage('Please provide a valid email address') + .normalizeEmail(), + + body('password') + .trim() + .notEmpty() + .withMessage('Password is required') + .isLength({ min: 8 }) + .withMessage('Password must be at least 8 characters long'), +]; + +/** + * Login Validation + */ +export const loginValidation = [ + body('email') + .trim() + .notEmpty() + .withMessage('Email is required') + .isEmail() + .withMessage('Please provide a valid email address') + .normalizeEmail(), + + body('password') + .trim() + .notEmpty() + .withMessage('Password is required'), +]; + +/** + * Validation Error Handler + */ +export const validateRequest = ( + req: Request, + res: Response, + next: NextFunction +): void => { + const errors = validationResult(req); + + if (!errors.isEmpty()) { + res.status(400).json({ + success: false, + errors: errors.array().map(error => ({ + field: error.type === 'field' ? error.path : undefined, + message: error.msg, + })), + }); + + return; + } + + next(); +}; \ No newline at end of file diff --git a/backend/src/routes/authRoutes.ts b/backend/src/routes/authRoutes.ts index ac2c7c8..0d0da71 100644 --- a/backend/src/routes/authRoutes.ts +++ b/backend/src/routes/authRoutes.ts @@ -2,9 +2,10 @@ import express from 'express'; const router = express.Router(); import { registerUser, loginUser, getMe, googleAuth } from '../controllers/authController'; import { protect } from '../middleware/authMiddleware'; +import { registerValidation, loginValidation, validateRequest } from '../middleware/validationMiddleware'; -router.post('/', registerUser); -router.post('/login', loginUser); +router.post('/', registerValidation, validateRequest ,registerUser); +router.post('/login', loginValidation, validateRequest ,loginUser); router.post('/google', googleAuth); router.get('/me', protect, getMe);