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..b2e14db 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -1,10 +1,12 @@ 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; @@ -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..ab4dac0 --- /dev/null +++ b/backend/validators/authValidator.js @@ -0,0 +1,38 @@ +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") + , + + email: z.string() + .trim() + .toLowerCase() + .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@$!%*?&]+$/, + 'Password must contain uppercase, lowercase, number, and special character' + ), +}); + + +const loginSchema = z.object({ + email: z.string() + .trim() + .toLowerCase() + .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") +}); + + +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..fb64f9b --- /dev/null +++ b/backend/validators/validationRequest.js @@ -0,0 +1,20 @@ +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; + req.body = result.data; + next(); +} + +module.exports = { validateRequest }; \ No newline at end of file