Initial commit
This commit is contained in:
63
server/middleware/auth.js
Normal file
63
server/middleware/auth.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { User } = require('../models');
|
||||
|
||||
async function authenticateToken(req, res, next) {
|
||||
const authHeader = req.headers['authorization'];
|
||||
const token = authHeader && authHeader.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: 'Access token required'
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const user = await User.findByPk(decoded.userId, {
|
||||
attributes: ['id', 'username', 'email', 'role', 'is_active']
|
||||
});
|
||||
|
||||
if (!user || !user.is_active) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: 'Invalid or inactive user'
|
||||
});
|
||||
}
|
||||
|
||||
req.user = user;
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('Token verification error:', error);
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: 'Invalid or expired token'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function requireRole(roles) {
|
||||
return (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: 'Authentication required'
|
||||
});
|
||||
}
|
||||
|
||||
const userRoles = Array.isArray(roles) ? roles : [roles];
|
||||
if (!userRoles.includes(req.user.role)) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: 'Insufficient permissions'
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
authenticateToken,
|
||||
requireRole
|
||||
};
|
||||
57
server/middleware/errorHandler.js
Normal file
57
server/middleware/errorHandler.js
Normal file
@@ -0,0 +1,57 @@
|
||||
function errorHandler(error, req, res, next) {
|
||||
console.error('Error occurred:', error);
|
||||
|
||||
// Default error response
|
||||
let statusCode = 500;
|
||||
let message = 'Internal server error';
|
||||
let details = null;
|
||||
|
||||
// Handle specific error types
|
||||
if (error.name === 'ValidationError') {
|
||||
statusCode = 400;
|
||||
message = 'Validation error';
|
||||
details = error.details || error.message;
|
||||
} else if (error.name === 'UnauthorizedError') {
|
||||
statusCode = 401;
|
||||
message = 'Unauthorized';
|
||||
} else if (error.name === 'SequelizeValidationError') {
|
||||
statusCode = 400;
|
||||
message = 'Database validation error';
|
||||
details = error.errors.map(err => ({
|
||||
field: err.path,
|
||||
message: err.message
|
||||
}));
|
||||
} else if (error.name === 'SequelizeUniqueConstraintError') {
|
||||
statusCode = 409;
|
||||
message = 'Resource already exists';
|
||||
details = error.errors.map(err => ({
|
||||
field: err.path,
|
||||
message: err.message
|
||||
}));
|
||||
} else if (error.name === 'SequelizeForeignKeyConstraintError') {
|
||||
statusCode = 400;
|
||||
message = 'Invalid reference';
|
||||
} else if (error.status) {
|
||||
statusCode = error.status;
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
// Send error response
|
||||
const response = {
|
||||
success: false,
|
||||
message,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Include error details in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
response.error = details || error.message;
|
||||
response.stack = error.stack;
|
||||
} else if (details) {
|
||||
response.details = details;
|
||||
}
|
||||
|
||||
res.status(statusCode).json(response);
|
||||
}
|
||||
|
||||
module.exports = errorHandler;
|
||||
30
server/middleware/validation.js
Normal file
30
server/middleware/validation.js
Normal file
@@ -0,0 +1,30 @@
|
||||
function validateRequest(schema) {
|
||||
return (req, res, next) => {
|
||||
const { error, value } = schema.validate(req.body, {
|
||||
abortEarly: false,
|
||||
stripUnknown: true
|
||||
});
|
||||
|
||||
if (error) {
|
||||
const errorDetails = error.details.map(detail => ({
|
||||
field: detail.path.join('.'),
|
||||
message: detail.message,
|
||||
value: detail.context.value
|
||||
}));
|
||||
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Validation error',
|
||||
errors: errorDetails
|
||||
});
|
||||
}
|
||||
|
||||
// Replace req.body with validated and sanitized data
|
||||
req.body = value;
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
validateRequest
|
||||
};
|
||||
Reference in New Issue
Block a user