import jwt from 'jsonwebtoken'; import httpStatus from 'http-status'; import { Request, Response, NextFunction } from 'express'; import { PrismaClient } from '@prisma/client'; import ApiError from '../../utils/helper/ApiError'; import config from '../../../config/config'; const prisma = new PrismaClient(); interface DecodedToken { id: number; role?: string; iat: number; exp: number; } interface UserPayload { id: string; role?: string; } declare module 'express-serve-static-core' { interface Request { user?: UserPayload; } } /** * Verifies JWT and validates Host user (role_xid = 3) */ const verifyCallback = async ( req: Request, resolve: (value?: unknown) => void, reject: (reason?: Error) => void ) => { const token = req.header('x-auth-token') || req.cookies?.accessToken; if (!token) { return reject(new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate')); } try { const decoded = jwt.verify(token, config.jwt.secret) as DecodedToken; if (!decoded?.id) { return reject(new ApiError(httpStatus.UNAUTHORIZED, 'Invalid token payload')); } // ✅ Fetch user from Prisma (Host user only) const user = await prisma.user.findUnique({ where: { id: decoded.id }, include: { role: true }, }); if (!user) { return reject(new ApiError(httpStatus.UNAUTHORIZED, 'User not found')); } // ✅ Check if user is active if (!user.isActive) { return reject( new ApiError(httpStatus.FORBIDDEN, 'Your account is deactivated by admin.') ); } // ✅ Check User role (role_xid = 1) if (user.roleXid !== 1) { return reject( new ApiError(httpStatus.FORBIDDEN, 'Access restricted to host users only') ); } // Attach user to request req.user = { id: user.id.toString(), role: user.role?.roleName }; resolve(); } catch (error) { if (error instanceof jwt.TokenExpiredError) { return reject( new ApiError(httpStatus.UNAUTHORIZED, 'Your session has expired. Please log in again.') ); } return reject( new ApiError(httpStatus.FORBIDDEN, 'Invalid or expired authentication token.') ); } }; /** * Express middleware — use as `auth()` in routes */ const auth = () => async (req: Request, res: Response, next: NextFunction) => { return new Promise((resolve, reject) => { verifyCallback(req, resolve, reject); }) .then(() => next()) .catch((err) => next(err)); }; export default auth;