fix: assertCanAssignRole/assertCanActOnUser validam existência do papel mesmo com bypass do super_admin
Bug encontrado em teste manual: convidar usuário com role_key inexistente, sendo o ator super_admin, pulava a checagem de peso inteira (incluindo a validação de existência) e caía direto na constraint FK do banco, virando um 500 não tratado em vez de um 400 claro. Agora a existência do papel é sempre validada antes do bypass de peso. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { ForbiddenException } from "@nestjs/common";
|
import { BadRequestException, ForbiddenException } from "@nestjs/common";
|
||||||
import { rolesRepo } from "@eden/database";
|
import { rolesRepo } from "@eden/database";
|
||||||
import { SUPER_ADMIN_ROLE } from "./permissions.js";
|
import { SUPER_ADMIN_ROLE } from "./permissions.js";
|
||||||
|
|
||||||
@@ -7,20 +7,23 @@ import { SUPER_ADMIN_ROLE } from "./permissions.js";
|
|||||||
* heavier than their own, nor act on a user whose *current* role is
|
* heavier than their own, nor act on a user whose *current* role is
|
||||||
* heavier than the actor's — orthogonal to the resource/action/scope
|
* heavier than the actor's — orthogonal to the resource/action/scope
|
||||||
* permission check. super_admin (weight 100, hardcoded ceiling) always
|
* permission check. super_admin (weight 100, hardcoded ceiling) always
|
||||||
* passes both checks.
|
* passes the *weight comparison* — but role existence is still validated
|
||||||
|
* even for super_admin, otherwise an invalid role key would sail past
|
||||||
|
* this check and only fail later as an unhandled FK-constraint 500 from
|
||||||
|
* the database (an earlier bug caught by manual testing: this function
|
||||||
|
* must be the single place that turns "role doesn't exist" into a clean
|
||||||
|
* 400, not the DB constraint).
|
||||||
*/
|
*/
|
||||||
async function getWeight(roleKey: string): Promise<number> {
|
async function getWeight(roleKey: string): Promise<number> {
|
||||||
const role = await rolesRepo.getRoleByKey(roleKey);
|
const role = await rolesRepo.getRoleByKey(roleKey);
|
||||||
if (!role) throw new ForbiddenException("Papel inválido");
|
if (!role) throw new BadRequestException(`Papel '${roleKey}' não existe`);
|
||||||
return role.weight;
|
return role.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assertCanAssignRole(actorRoleKey: string, targetRoleKey: string): Promise<void> {
|
export async function assertCanAssignRole(actorRoleKey: string, targetRoleKey: string): Promise<void> {
|
||||||
|
const targetWeight = await getWeight(targetRoleKey);
|
||||||
if (actorRoleKey === SUPER_ADMIN_ROLE) return;
|
if (actorRoleKey === SUPER_ADMIN_ROLE) return;
|
||||||
const [actorWeight, targetWeight] = await Promise.all([
|
const actorWeight = await getWeight(actorRoleKey);
|
||||||
getWeight(actorRoleKey),
|
|
||||||
getWeight(targetRoleKey),
|
|
||||||
]);
|
|
||||||
if (targetWeight > actorWeight) {
|
if (targetWeight > actorWeight) {
|
||||||
throw new ForbiddenException("Você não pode atribuir um papel com peso maior que o seu.");
|
throw new ForbiddenException("Você não pode atribuir um papel com peso maior que o seu.");
|
||||||
}
|
}
|
||||||
@@ -30,11 +33,9 @@ export async function assertCanActOnUser(
|
|||||||
actorRoleKey: string,
|
actorRoleKey: string,
|
||||||
targetUserRoleKey: string,
|
targetUserRoleKey: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const targetWeight = await getWeight(targetUserRoleKey);
|
||||||
if (actorRoleKey === SUPER_ADMIN_ROLE) return;
|
if (actorRoleKey === SUPER_ADMIN_ROLE) return;
|
||||||
const [actorWeight, targetWeight] = await Promise.all([
|
const actorWeight = await getWeight(actorRoleKey);
|
||||||
getWeight(actorRoleKey),
|
|
||||||
getWeight(targetUserRoleKey),
|
|
||||||
]);
|
|
||||||
if (targetWeight > actorWeight) {
|
if (targetWeight > actorWeight) {
|
||||||
throw new ForbiddenException("Você não pode alterar um usuário com papel de peso maior que o seu.");
|
throw new ForbiddenException("Você não pode alterar um usuário com papel de peso maior que o seu.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user