Skip to content

Commit

Permalink
updates to protected and login router
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelberston committed Nov 19, 2024
1 parent cc806b6 commit 2aca808
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 26 deletions.
14 changes: 14 additions & 0 deletions backend/routes/loginRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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.
Expand Down Expand Up @@ -40,6 +53,7 @@ const LoginRouter = require("express").Router();
*/
LoginRouter.post(
'/',
loginLimiter,
[
usernameValidator,
passwordValidator
Expand Down
44 changes: 31 additions & 13 deletions backend/routes/protectedRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
14 changes: 1 addition & 13 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 2aca808

Please sign in to comment.