From 7d07bebce2b5d4b66ec8bc727e1e03320ae1c6ca Mon Sep 17 00:00:00 2001 From: Likhi2005 Date: Sat, 16 May 2026 16:37:57 +0530 Subject: [PATCH 1/2] feat: add zod validation for auth routes --- backend/package.json | 3 ++- backend/routes/auth.js | 8 +++--- backend/validators/authValidator.js | 36 +++++++++++++++++++++++++ backend/validators/validationRequest.js | 19 +++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 backend/validators/authValidator.js create mode 100644 backend/validators/validationRequest.js diff --git a/backend/package.json b/backend/package.json index 9891c08..228584a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -20,7 +20,8 @@ "express-session": "^1.18.1", "mongoose": "^8.8.2", "passport": "^0.7.0", - "passport-local": "^1.0.0" + "passport-local": "^1.0.0", + "zod": "^4.4.3" }, "devDependencies": { "nodemon": "^3.1.9" diff --git a/backend/routes/auth.js b/backend/routes/auth.js index e26c7a9..84b57e7 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -1,12 +1,14 @@ const express = require("express"); const passport = require("passport"); const User = require("../models/User"); +const { signupSchema, loginSchema } = require("../validators/authValidator"); +const { validateRequest } = require("../validators/validationRequest"); const router = express.Router(); // Signup route -router.post("/signup", async (req, res) => { +router.post("/signup", validateRequest(signupSchema), async (req, res) => { - const { username, email, password } = req.body; + const { username, email, password } = req.validated; try { const existingUser = await User.findOne( {email} ); @@ -23,7 +25,7 @@ router.post("/signup", async (req, res) => { }); // Login route -router.post("/login", passport.authenticate('local'), (req, res) => { +router.post("/login", validateRequest(loginSchema), passport.authenticate('local'), (req, res) => { res.status(200).json( { message: 'Login successful', user: req.user } ); }); diff --git a/backend/validators/authValidator.js b/backend/validators/authValidator.js new file mode 100644 index 0000000..f7c75e4 --- /dev/null +++ b/backend/validators/authValidator.js @@ -0,0 +1,36 @@ +const { z } = require("zod"); + +const signupSchema = z.object({ + username: z.string() + .min(3, "Username must be at least 3 characters long") + .max(30, "Username must be at most 30 characters long") + .regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores") + .trim(), + + email: z.string() + .email("Invalid email address") + .toLowerCase() + .trim(), + + password: z.string() + .min(8, "Password must be at least 8 characters long") + .max(100, "Password must be at most 100 characters long") + .regex( + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/, + 'Password must contain uppercase, lowercase, number, and special character' + ), +}); + + +const loginSchema = z.object({ + email: z.string() + .email("Invalid email address") + .toLowerCase() + .trim(), + password: z.string() + .min(8, "Password must be at least 8 characters long") + .max(100, "Password must be at most 100 characters long") +}); + + +module.exports = { signupSchema, loginSchema }; \ No newline at end of file diff --git a/backend/validators/validationRequest.js b/backend/validators/validationRequest.js new file mode 100644 index 0000000..104b818 --- /dev/null +++ b/backend/validators/validationRequest.js @@ -0,0 +1,19 @@ +const validateRequest = (schema) => (req,res, next) => { + const result = schema.safeParse(req.body); + + if(!result.success) { + return res.status(400).json({ + success: false, + message: 'Validation failed', + errors: result.error.issues.map((err) => ({ + field: err.path.join('.'), + message: err.message, + })), + }); + } + + req.validated = result.data; + next(); +} + +module.exports = { validateRequest }; \ No newline at end of file From defd38db492a097052d8311f75b918e782a3c24a Mon Sep 17 00:00:00 2001 From: Likhi2005 Date: Sat, 16 May 2026 17:47:12 +0530 Subject: [PATCH 2/2] fix: sync validated data with req.body for passport compatibility --- backend/routes/auth.js | 2 +- backend/validators/authValidator.js | 14 ++++++++------ backend/validators/validationRequest.js | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/routes/auth.js b/backend/routes/auth.js index 84b57e7..b2e14db 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -8,7 +8,7 @@ const router = express.Router(); // Signup route router.post("/signup", validateRequest(signupSchema), async (req, res) => { - const { username, email, password } = req.validated; + const { username, email, password } = req.body; try { const existingUser = await User.findOne( {email} ); diff --git a/backend/validators/authValidator.js b/backend/validators/authValidator.js index f7c75e4..ab4dac0 100644 --- a/backend/validators/authValidator.js +++ b/backend/validators/authValidator.js @@ -2,21 +2,23 @@ const { z } = require("zod"); const signupSchema = z.object({ username: z.string() + .trim() .min(3, "Username must be at least 3 characters long") .max(30, "Username must be at most 30 characters long") .regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores") - .trim(), + , email: z.string() - .email("Invalid email address") + .trim() .toLowerCase() - .trim(), + .email("Invalid email address"), + password: z.string() .min(8, "Password must be at least 8 characters long") .max(100, "Password must be at most 100 characters long") .regex( - /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/, + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/, 'Password must contain uppercase, lowercase, number, and special character' ), }); @@ -24,9 +26,9 @@ const signupSchema = z.object({ const loginSchema = z.object({ email: z.string() - .email("Invalid email address") + .trim() .toLowerCase() - .trim(), + .email("Invalid email address"), password: z.string() .min(8, "Password must be at least 8 characters long") .max(100, "Password must be at most 100 characters long") diff --git a/backend/validators/validationRequest.js b/backend/validators/validationRequest.js index 104b818..fb64f9b 100644 --- a/backend/validators/validationRequest.js +++ b/backend/validators/validationRequest.js @@ -1,4 +1,4 @@ -const validateRequest = (schema) => (req,res, next) => { +const validateRequest = (schema) => (req, res, next) => { const result = schema.safeParse(req.body); if(!result.success) { @@ -13,6 +13,7 @@ const validateRequest = (schema) => (req,res, next) => { } req.validated = result.data; + req.body = result.data; next(); }