flwo / apps /server /src /middleware /auth.js
moustafa7's picture
Initial commit
24727a3
Raw History Blame Contribute Delete
2.45 kB
import jwt from 'jsonwebtoken'
import { config } from '../config/index.js'
import { safeRedis } from '../config/redis.js'
import { AppError } from '../lib/AppError.js'
import { prisma } from '../config/database.js'
import { SAFE_USER_SELECT, ROLE_HIERARCHY, CACHE_PREFIX } from '../lib/constants.js'
export async function authenticate(req, res, next) {
try {
const authHeader = req.headers.authorization
if (!authHeader?.startsWith('Bearer ')) {
throw new AppError('لم يتم توفير رمز المصادقة', 401, 'NO_TOKEN')
}
const token = authHeader.split(' ')[1]
const isBlacklisted = await safeRedis.get(CACHE_PREFIX.BLACKLIST(token))
if (isBlacklisted) throw new AppError('رمز المصادقة ملغي', 401, 'TOKEN_REVOKED')
let decoded
try {
decoded = jwt.verify(token, config.JWT_ACCESS_SECRET)
} catch (err) {
if (err.name === 'TokenExpiredError') throw new AppError('انتهت صلاحية الجلسة', 401, 'TOKEN_EXPIRED')
throw new AppError('رمز المصادقة غير صحيح', 401, 'INVALID_TOKEN')
}
const isSuspended = await safeRedis.get(CACHE_PREFIX.SUSPENDED(decoded.sub))
if (isSuspended) throw new AppError('بيانات تسجيل الدخول غير صحيحة', 401, 'INVALID_CREDENTIALS')
const user = await prisma.user.findUnique({
where: { id: decoded.sub },
select: { ...SAFE_USER_SELECT, bannedUntil: true },
})
if (!user || !user.isActive) {
throw new AppError('بيانات تسجيل الدخول غير صحيحة', 401, 'INVALID_CREDENTIALS')
}
if (user.bannedUntil && new Date(user.bannedUntil) > new Date()) {
throw new AppError('تم حظر حسابك مؤقتاً', 403, 'ACCOUNT_BANNED')
}
req.user = user
next()
} catch (err) {
next(err)
}
}
export function requireRole(...roles) {
return (req, res, next) => {
if (!req.user) return next(new AppError('غير مصادق', 401, 'UNAUTHORIZED'))
if (!roles.includes(req.user.role)) {
return next(new AppError('ليس لديك صلاحية', 403, 'FORBIDDEN'))
}
next()
}
}
export const requireAdmin = requireRole('ADMIN', 'SUPER_ADMIN')
export const requireSupport = requireRole('ADMIN', 'SUPPORT', 'ACCOUNTS', 'SUPER_ADMIN')
export function canModifyUser(actorRole, targetRole) {
const allowed = ROLE_HIERARCHY[actorRole] || []
return allowed.includes(targetRole)
}