diff --git a/backend/routes/loginRouter.js b/backend/routes/loginRouter.js index 9dfa88e..e7efc8c 100644 --- a/backend/routes/loginRouter.js +++ b/backend/routes/loginRouter.js @@ -2,6 +2,7 @@ const bcrypt = require('bcrypt'); // Compare password const jwt = require('jsonwebtoken'); // Initiate JWT session const { validationResult } = require("express-validator"); // Validate credentials const logger = require("../logger.js"); +const rateLimit = require('express-rate-limit'); // Validation middleware const { usernameValidator, passwordValidator } = require('../validators.js'); @@ -11,6 +12,18 @@ const pool = require('../psql.js'); const LoginRouter = require("express").Router(); +// route rate limiters +const loginLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 10, // Limit each IP to 10 login attempts per windowMs + message: { + status: 429, + error: 'Too many login attempts, please try again later.' + }, + standardHeaders: true, + legacyHeaders: false, +}); + /** * @route POST /login * @desc Handles user login, validating credentials, checking user existence in the database, verifying password, and initiating a session via JWT if successful. @@ -40,6 +53,7 @@ const LoginRouter = require("express").Router(); */ LoginRouter.post( '/', + loginLimiter, [ usernameValidator, passwordValidator diff --git a/backend/routes/protectedRouter.js b/backend/routes/protectedRouter.js index 15cd060..3f23673 100644 --- a/backend/routes/protectedRouter.js +++ b/backend/routes/protectedRouter.js @@ -4,36 +4,54 @@ const jwt = require('jsonwebtoken'); const logger = require('../logger.js'); +const rateLimit = require('express-rate-limit'); const ProtectedRouter = require('express').Router(); +const authLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100 // limit each IP to 100 requests per windowMs +}); + +// Validate JWT_SECRET at startup +if (!process.env.JWT_SECRET || process.env.JWT_SECRET.length < 32) { + throw new Error('JWT_SECRET must be set and at least 32 characters long'); +} + // Middleware to authenticate token function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Extract token after 'Bearer' - if (!token) { - logger.warn(`Unauthorized attempt to access protected data from IP: %s`, req.ip); - return res.status(401).json({ message: 'Token missing.' }); + if (!token || !/^[\w-]*\.[\w-]*\.[\w-]*$/.test(token)) { + logger.warn(`Invalid token format from IP: ${req.ip}`); + return res.status(401).json({ message: 'Invalid authentication' }); } jwt.verify(token, process.env.JWT_SECRET, (err, user) => { - if (!process.env.JWT_SECRET) { - logger.error('JWT_SECRET environment variable is not set'); - return res.status(500).json({ message: 'Server configuration error' }); - } if (err) { - logger.warn(`Attempt to access protected data with expired JWT from IP: %s`, req.ip); + logger.warn(`JWT verification failed from IP: ${req.ip}`); return res.status(403).json({ message: 'Token invalid or expired.' }); } - req.user = user; + // Only store necessary user data + req.user = { + id: user.id, + role: user.role + }; next(); }); } -ProtectedRouter.get('/', authenticateToken, (req, res) => { - logger.info(`User %s accessed protected data from IP: %s`, req.user, req.ip); - res.status(200).json({ data: 'This is protected data.', user: req.user }); -}); +ProtectedRouter.get('/', + authLimiter, + authenticateToken, + (req, res) => { + logger.info(`User %s accessed protected data from IP: %s`, req.user, req.ip); + res.status(200).json({ + data: 'This is protected data.', + user: req.user.id + }); + } +); module.exports = ProtectedRouter; diff --git a/backend/server.js b/backend/server.js index 5698609..c7da403 100644 --- a/backend/server.js +++ b/backend/server.js @@ -91,21 +91,9 @@ app.get('/init-session', (req, res) => { res.sendStatus(200); // Respond with OK status }); -// route rate limiters -const loginLimiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 10, // Limit each IP to 10 login attempts per windowMs - message: { - status: 429, - error: 'Too many login attempts, please try again later.' - }, - standardHeaders: true, - legacyHeaders: false, -}); - // routes app.use('/users', UsersRouter); -app.use('/login', loginLimiter, LoginRouter); +app.use('/login', LoginRouter); app.use('/protected', ProtectedRouter); app.use('/advice', AdviceRouter);