Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 0 additions & 5 deletions backend/src/controllers/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
72 changes: 72 additions & 0 deletions backend/src/middleware/validationMiddleware.ts
Original file line number Diff line number Diff line change
@@ -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'),
Comment on lines +8 to +28

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stop each validation chain after the first failure.

Without .bail(), whitespace-only name, email, or password values can produce multiple errors for the same field (required plus invalid/too short). That makes the centralized error payload less consistent than intended.

Suggested fix
 export const registerValidation = [
     body('name')
         .trim()
         .notEmpty()
         .withMessage('Name is required')
+        .bail()
         .isLength({ min: 2, max: 50 })
         .withMessage('Name must be between 2 and 50 characters'),

     body('email')
         .trim()
         .notEmpty()
         .withMessage('Email is required')
+        .bail()
         .isEmail()
         .withMessage('Please provide a valid email address')
         .normalizeEmail(),

     body('password')
         .trim()
         .notEmpty()
         .withMessage('Password is required')
+        .bail()
         .isLength({ min: 8 })
         .withMessage('Password must be at least 8 characters long'),
 ];

 export const loginValidation = [
     body('email')
         .trim()
         .notEmpty()
         .withMessage('Email is required')
+        .bail()
         .isEmail()
         .withMessage('Please provide a valid email address')
         .normalizeEmail(),

     body('password')
         .trim()
         .notEmpty()
         .withMessage('Password is required')
 ];

Also applies to: 35-46

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/middleware/validationMiddleware.ts` around lines 8 - 28, The
validation chains in validationMiddleware should stop after the first failure so
a single bad field does not emit multiple errors. Add .bail() in each
body('name'), body('email'), and body('password') chain after the required check
and before the type/length checks, and apply the same pattern to the other
validation block referenced by this review so the centralized error payload
stays one-error-per-field.

];

/**
* 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'),
Comment on lines +43 to +46

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Enforce the password length floor on login too.

Line 43-46 only reject empty passwords, so short values still reach loginUser and trigger the Prisma lookup / bcrypt compare path. That misses the stated auth-endpoint contract of keeping low-quality input out of the controller/database.

Suggested fix
 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'),
+        .withMessage('Password is required')
+        .bail()
+        .isLength({ min: 8 })
+        .withMessage('Password must be at least 8 characters long'),
 ];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
body('password')
.trim()
.notEmpty()
.withMessage('Password is required'),
body('password')
.trim()
.notEmpty()
.withMessage('Password is required')
.bail()
.isLength({ min: 8 })
.withMessage('Password must be at least 8 characters long'),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/middleware/validationMiddleware.ts` around lines 43 - 46, The
password validator in validationMiddleware only checks for non-empty input, so
short passwords still reach loginUser and the downstream Prisma/bcrypt flow.
Update the existing password rule used by the auth login validation to enforce
the same minimum length floor as registration, while keeping the current empty
check and message behavior. Use the body('password') validator chain in
validationMiddleware to add the length constraint so invalid short passwords are
rejected before controller/database work.

];

/**
* 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();
};
5 changes: 3 additions & 2 deletions backend/src/routes/authRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading