fix(auth): prevent admin from revoking their last users.manage role
- add self-lockout guard in handleRevokeUserRole api handler - sequence role additions before removals and handle delete errors in UserEditModal - document the security rule in core/users README
This commit is contained in:
@@ -526,8 +526,26 @@ async function handleAssignUserRole(request, { id: userId }) {
|
||||
// DELETE /zen/api/users/:id/roles/:roleId (admin only)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function handleRevokeUserRole(_request, { id: userId, roleId }) {
|
||||
async function handleRevokeUserRole(_request, { id: userId, roleId }, context) {
|
||||
try {
|
||||
if (context.session.user.id === userId) {
|
||||
const roleHasPerm = await query(
|
||||
`SELECT 1 FROM zen_auth_role_permissions WHERE role_id = $1 AND permission_key = $2`,
|
||||
[roleId, PERMISSIONS.USERS_MANAGE]
|
||||
);
|
||||
if (roleHasPerm.rows.length > 0) {
|
||||
const otherRoles = await query(
|
||||
`SELECT 1 FROM zen_auth_user_roles ur
|
||||
JOIN zen_auth_role_permissions rp ON rp.role_id = ur.role_id
|
||||
WHERE ur.user_id = $1 AND rp.permission_key = $2 AND ur.role_id != $3
|
||||
LIMIT 1`,
|
||||
[userId, PERMISSIONS.USERS_MANAGE, roleId]
|
||||
);
|
||||
if (otherRoles.rows.length === 0) {
|
||||
return apiError('Forbidden', "Vous ne pouvez pas retirer ce rôle car c'est votre seule source de la permission de gestion des utilisateurs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
await revokeUserRole(userId, roleId);
|
||||
return apiSuccess({ success: true });
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user