Spaces:
Runtime error
Runtime error
File size: 2,454 Bytes
24727a3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 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)
}
|