104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
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;
|