add changes

This commit is contained in:
AD2025
2025-11-11 00:25:50 +02:00
commit e3ca132c5e
86 changed files with 22238 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
const jwt = require('jsonwebtoken');
const config = require('../config/config');
const { User } = require('../models');
/**
* Middleware to verify JWT token
*/
exports.verifyToken = async (req, res, next) => {
try {
// Get token from header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
success: false,
message: 'No token provided. Authorization header must be in format: Bearer <token>'
});
}
// Extract token
const token = authHeader.substring(7); // Remove 'Bearer ' prefix
// Verify token
const decoded = jwt.verify(token, config.jwt.secret);
// Attach user info to request
req.user = decoded;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({
success: false,
message: 'Token expired. Please login again.'
});
} else if (error.name === 'JsonWebTokenError') {
return res.status(401).json({
success: false,
message: 'Invalid token. Please login again.'
});
} else {
return res.status(500).json({
success: false,
message: 'Error verifying token',
error: error.message
});
}
}
};
/**
* Middleware to check if user is admin
*/
exports.isAdmin = async (req, res, next) => {
try {
// Verify token first (should be called after verifyToken)
if (!req.user) {
return res.status(401).json({
success: false,
message: 'Authentication required'
});
}
// Check if user has admin role
if (req.user.role !== 'admin') {
return res.status(403).json({
success: false,
message: 'Access denied. Admin privileges required.'
});
}
next();
} catch (error) {
return res.status(500).json({
success: false,
message: 'Error checking admin privileges',
error: error.message
});
}
};
/**
* Middleware to check if user owns the resource or is admin
*/
exports.isOwnerOrAdmin = async (req, res, next) => {
try {
// Verify token first (should be called after verifyToken)
if (!req.user) {
return res.status(401).json({
success: false,
message: 'Authentication required'
});
}
const resourceUserId = req.params.userId || req.body.userId;
// Allow if admin or if user owns the resource
if (req.user.role === 'admin' || req.user.userId === resourceUserId) {
next();
} else {
return res.status(403).json({
success: false,
message: 'Access denied. You can only access your own resources.'
});
}
} catch (error) {
return res.status(500).json({
success: false,
message: 'Error checking resource ownership',
error: error.message
});
}
};
/**
* Optional auth middleware - attaches user if token present, but doesn't fail if missing
*/
exports.optionalAuth = async (req, res, next) => {
try {
const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.substring(7);
try {
const decoded = jwt.verify(token, config.jwt.secret);
req.user = decoded;
} catch (error) {
// Token invalid or expired - continue as guest
req.user = null;
}
}
next();
} catch (error) {
// Any error - continue as guest
next();
}
};

View File

@@ -0,0 +1,83 @@
const jwt = require('jsonwebtoken');
const config = require('../config/config');
const { GuestSession } = require('../models');
/**
* Middleware to verify guest session token
*/
exports.verifyGuestToken = async (req, res, next) => {
try {
// Get token from header
const guestToken = req.headers['x-guest-token'];
if (!guestToken) {
return res.status(401).json({
success: false,
message: 'No guest token provided. X-Guest-Token header is required.'
});
}
// Verify token
const decoded = jwt.verify(guestToken, config.jwt.secret);
// Check if guestId exists in payload
if (!decoded.guestId) {
return res.status(401).json({
success: false,
message: 'Invalid guest token. Missing guestId.'
});
}
// Verify guest session exists in database
const guestSession = await GuestSession.findOne({
where: { guestId: decoded.guestId }
});
if (!guestSession) {
return res.status(404).json({
success: false,
message: 'Guest session not found.'
});
}
// Check if session is expired
if (new Date() > new Date(guestSession.expiresAt)) {
return res.status(410).json({
success: false,
message: 'Guest session has expired. Please start a new session.'
});
}
// Check if session was converted to user account
if (guestSession.isConverted) {
return res.status(410).json({
success: false,
message: 'Guest session has been converted to a user account. Please login with your credentials.'
});
}
// Attach guest session to request
req.guestSession = guestSession;
req.guestId = decoded.guestId;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({
success: false,
message: 'Guest token expired. Please start a new session.'
});
} else if (error.name === 'JsonWebTokenError') {
return res.status(401).json({
success: false,
message: 'Invalid guest token. Please start a new session.'
});
} else {
return res.status(500).json({
success: false,
message: 'Error verifying guest token',
error: error.message
});
}
}
};

View File

@@ -0,0 +1,86 @@
const { body, validationResult } = require('express-validator');
/**
* Validation middleware for user registration
*/
exports.validateRegistration = [
body('username')
.trim()
.notEmpty()
.withMessage('Username is required')
.isLength({ min: 3, max: 50 })
.withMessage('Username must be between 3 and 50 characters')
.matches(/^[a-zA-Z0-9_]+$/)
.withMessage('Username can only contain letters, numbers, and underscores'),
body('email')
.trim()
.notEmpty()
.withMessage('Email is required')
.isEmail()
.withMessage('Please provide a valid email address')
.normalizeEmail(),
body('password')
.notEmpty()
.withMessage('Password is required')
.isLength({ min: 8 })
.withMessage('Password must be at least 8 characters long')
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
.withMessage('Password must contain at least one uppercase letter, one lowercase letter, and one number'),
body('guestSessionId')
.optional()
.trim()
.notEmpty()
.withMessage('Guest session ID cannot be empty if provided'),
// Check for validation errors
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validation failed',
errors: errors.array().map(err => ({
field: err.path,
message: err.msg
}))
});
}
next();
}
];
/**
* Validation middleware for user login
*/
exports.validateLogin = [
body('email')
.trim()
.notEmpty()
.withMessage('Email is required')
.isEmail()
.withMessage('Please provide a valid email address')
.normalizeEmail(),
body('password')
.notEmpty()
.withMessage('Password is required'),
// Check for validation errors
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: 'Validation failed',
errors: errors.array().map(err => ({
field: err.path,
message: err.msg
}))
});
}
next();
}
];