feat: add env-based super admin authentication and complete role & permission system
deploy-chabokan / deploy (push) Canceled after 0s
deploy-chabokan / deploy (push) Canceled after 0s
This commit is contained in:
@@ -1,30 +1,73 @@
|
||||
const Permission = require('../components/permission/permissionModel')
|
||||
const Role = require('../components/role/roleModel')
|
||||
const AppError = require('../globalErrorHandler/AppError')
|
||||
const catchAsync = require('../globalErrorHandler/catchAsync')
|
||||
const User = require('../components/user/userModel')
|
||||
const ErrorLocalization = require('../globalErrorHandler/errorLocalization')
|
||||
const el = new ErrorLocalization()
|
||||
|
||||
let checker = (arr, target) => arr.includes(target)
|
||||
let checker = (arr, target) => {
|
||||
if (!Array.isArray(arr)) return false
|
||||
return arr.some((item) => {
|
||||
const id = (item?._id || item)?.toString()
|
||||
const key = item?.key
|
||||
return id === target?.toString() || (key && key === target)
|
||||
})
|
||||
}
|
||||
|
||||
const requires = (...permissions) => {
|
||||
return async (req, res, next) => {
|
||||
const role = await Role.findById(req.user.role)
|
||||
const perm = await Permission.findOne({ key: permissions[0] })
|
||||
const rolePerm = role?.permissions || []
|
||||
const userPerm = req.user.extraPermissions || []
|
||||
try {
|
||||
if (!req.user) {
|
||||
return next(new AppError('NotLoggedIn', 401, {}))
|
||||
}
|
||||
|
||||
// some features: permission denied when all roles are not same --> we want to access user with either roles
|
||||
if (
|
||||
!checker(rolePerm, perm?._id) &&
|
||||
!checker(userPerm, perm?._id) &&
|
||||
role._id.toString() !== process.env.SUPER_ADMIN_ROLE_ID
|
||||
) {
|
||||
throw new AppError('NoPermissionAccess', 403, {})
|
||||
const superAdminRoleId = process.env.SUPER_ADMIN_ROLE_ID || '66a2da5b9b989a8909948848'
|
||||
|
||||
// Super Admin bypass: full access to all endpoints
|
||||
if (
|
||||
req.user.isAdmin === true ||
|
||||
req.user.role?.englishName === 'SuperAdmin' ||
|
||||
req.user.role?._id?.toString() === superAdminRoleId ||
|
||||
req.user.role?.toString() === superAdminRoleId
|
||||
) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Retrieve role and its permissions
|
||||
let role = req.user.role
|
||||
if (role && (typeof role === 'string' || !role.permissions || !role.englishName)) {
|
||||
role = await Role.findById(role._id || role).populate('permissions')
|
||||
}
|
||||
|
||||
const rolePermissions = role?.permissions || []
|
||||
const userExtraPermissions = req.user.extraPermissions || []
|
||||
|
||||
// Find target permissions from DB
|
||||
const targetPerms = await Permission.find({ key: { $in: permissions } })
|
||||
const targetIds = targetPerms.map((p) => p._id.toString())
|
||||
const targetKeys = permissions
|
||||
|
||||
// Check if any required permission is present in role or user extra permissions
|
||||
const hasPermission =
|
||||
rolePermissions.some((rp) => {
|
||||
const rpId = (rp._id || rp).toString()
|
||||
const rpKey = rp.key
|
||||
return targetIds.includes(rpId) || targetKeys.includes(rpKey)
|
||||
}) ||
|
||||
userExtraPermissions.some((up) => {
|
||||
const upId = (up._id || up).toString()
|
||||
const upKey = up.key
|
||||
return targetIds.includes(upId) || targetKeys.includes(upKey)
|
||||
})
|
||||
|
||||
if (!hasPermission) {
|
||||
return next(new AppError('NoPermissionAccess', 403, {}))
|
||||
}
|
||||
|
||||
next()
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,23 +79,26 @@ const adminCheck = () => {
|
||||
}).populate('role')
|
||||
|
||||
if (!user) {
|
||||
throw new AppError('UserDoesNotExist', 403, {})
|
||||
return next(new AppError('UserDoesNotExist', 403, {}))
|
||||
}
|
||||
|
||||
const perm = await Permission.findOne(
|
||||
{ key: 'admindashboard' },
|
||||
null,
|
||||
null
|
||||
)
|
||||
const superAdminRoleId = process.env.SUPER_ADMIN_ROLE_ID || '66a2da5b9b989a8909948848'
|
||||
|
||||
if (
|
||||
user.isAdmin === true ||
|
||||
user.role?.englishName === 'SuperAdmin' ||
|
||||
user.role?._id?.toString() === superAdminRoleId ||
|
||||
user.role?.toString() === superAdminRoleId
|
||||
) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const perm = await Permission.findOne({ key: 'admindashboard' })
|
||||
let rolePerm = user.role?.permissions || []
|
||||
let userPerm = user.extraPermissions || []
|
||||
// some features: permission denied when all roles are not same --> we want to access user with either roles
|
||||
if (
|
||||
!checker(rolePerm, perm?._id) &&
|
||||
!checker(userPerm, perm?._id) &&
|
||||
user.role?._id.toString() !== process.env.SUPER_ADMIN_ROLE_ID
|
||||
) {
|
||||
throw new AppError('NoPermissionAccess', 403, {})
|
||||
|
||||
if (!checker(rolePerm, perm?._id) && !checker(userPerm, perm?._id)) {
|
||||
return next(new AppError('NoPermissionAccess', 403, {}))
|
||||
}
|
||||
|
||||
next()
|
||||
@@ -61,9 +107,7 @@ const adminCheck = () => {
|
||||
err.message = el.getErrorText(err.name, err.parameters, 'persian')
|
||||
res.status(500).json({
|
||||
status: 'error',
|
||||
message:
|
||||
err.message ||
|
||||
'An error occurred while checking permissions.',
|
||||
message: err.message || 'An error occurred while checking permissions.',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user