feat: implement advanced access control system with user blocking, rate limiting, and enhanced login security; update UI components for improved user experience and documentation
This commit is contained in:
290
packages/backend/convex/limparPerfisAntigos.ts
Normal file
290
packages/backend/convex/limparPerfisAntigos.ts
Normal file
@@ -0,0 +1,290 @@
|
||||
import { internalMutation, query } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
/**
|
||||
* Listar todos os perfis (roles) do sistema
|
||||
*/
|
||||
export const listarTodosRoles = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id("roles"),
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
setor: v.optional(v.string()),
|
||||
customizado: v.boolean(),
|
||||
editavel: v.optional(v.boolean()),
|
||||
_creationTime: v.number(),
|
||||
})
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
return roles.map((role) => ({
|
||||
_id: role._id,
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
setor: role.setor,
|
||||
customizado: role.customizado,
|
||||
editavel: role.editavel,
|
||||
_creationTime: role._creationTime,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Limpar perfis antigos/duplicados
|
||||
*
|
||||
* CRITÉRIOS:
|
||||
* - Manter apenas: ti_master (nível 0), admin (nível 2), ti_usuario (nível 2)
|
||||
* - Remover: admin antigo (nível 0), ti genérico (nível 1), outros duplicados
|
||||
*/
|
||||
export const limparPerfisAntigos = internalMutation({
|
||||
args: {},
|
||||
returns: v.object({
|
||||
removidos: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
motivo: v.string(),
|
||||
})
|
||||
),
|
||||
mantidos: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivel: v.number(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
|
||||
const removidos: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivel: number;
|
||||
motivo: string;
|
||||
}> = [];
|
||||
|
||||
const mantidos: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivel: number;
|
||||
}> = [];
|
||||
|
||||
// Perfis que devem ser mantidos (apenas 1 de cada)
|
||||
const perfisCorretos = new Map<string, boolean>();
|
||||
perfisCorretos.set("ti_master", false);
|
||||
perfisCorretos.set("admin", false);
|
||||
perfisCorretos.set("ti_usuario", false);
|
||||
|
||||
for (const role of roles) {
|
||||
let deveManter = false;
|
||||
let motivo = "";
|
||||
|
||||
// TI_MASTER - Manter apenas o de nível 0
|
||||
if (role.nome === "ti_master") {
|
||||
if (role.nivel === 0 && !perfisCorretos.get("ti_master")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("ti_master", true);
|
||||
} else {
|
||||
motivo = role.nivel !== 0
|
||||
? "TI_MASTER deve ser nível 0, este é nível " + role.nivel
|
||||
: "TI_MASTER duplicado";
|
||||
}
|
||||
}
|
||||
// ADMIN - Manter apenas o de nível 2
|
||||
else if (role.nome === "admin") {
|
||||
if (role.nivel === 2 && !perfisCorretos.get("admin")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("admin", true);
|
||||
} else {
|
||||
motivo = role.nivel !== 2
|
||||
? "ADMIN deve ser nível 2, este é nível " + role.nivel
|
||||
: "ADMIN duplicado";
|
||||
}
|
||||
}
|
||||
// TI_USUARIO - Manter apenas o de nível 2
|
||||
else if (role.nome === "ti_usuario") {
|
||||
if (role.nivel === 2 && !perfisCorretos.get("ti_usuario")) {
|
||||
deveManter = true;
|
||||
perfisCorretos.set("ti_usuario", true);
|
||||
} else {
|
||||
motivo = role.nivel !== 2
|
||||
? "TI_USUARIO deve ser nível 2, este é nível " + role.nivel
|
||||
: "TI_USUARIO duplicado";
|
||||
}
|
||||
}
|
||||
// Perfis genéricos antigos (remover)
|
||||
else if (role.nome === "ti") {
|
||||
motivo = "Perfil genérico 'ti' obsoleto - usar 'ti_master' ou 'ti_usuario'";
|
||||
}
|
||||
// Outros perfis específicos de setores (manter se forem nível >= 2)
|
||||
else if (
|
||||
role.nome === "rh" ||
|
||||
role.nome === "financeiro" ||
|
||||
role.nome === "controladoria" ||
|
||||
role.nome === "licitacoes" ||
|
||||
role.nome === "compras" ||
|
||||
role.nome === "juridico" ||
|
||||
role.nome === "comunicacao" ||
|
||||
role.nome === "programas_esportivos" ||
|
||||
role.nome === "secretaria_executiva" ||
|
||||
role.nome === "gestao_pessoas" ||
|
||||
role.nome === "usuario"
|
||||
) {
|
||||
if (role.nivel >= 2) {
|
||||
deveManter = true;
|
||||
} else {
|
||||
motivo = `Perfil de setor com nível incorreto (${role.nivel}), deveria ser >= 2`;
|
||||
}
|
||||
}
|
||||
// Perfis customizados (manter sempre)
|
||||
else if (role.customizado) {
|
||||
deveManter = true;
|
||||
}
|
||||
// Outros perfis desconhecidos
|
||||
else {
|
||||
motivo = "Perfil desconhecido ou obsoleto";
|
||||
}
|
||||
|
||||
if (deveManter) {
|
||||
mantidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
});
|
||||
console.log(`✅ MANTIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel}`);
|
||||
} else {
|
||||
// Verificar se há usuários usando este perfil
|
||||
const usuariosComRole = await ctx.db
|
||||
.query("usuarios")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
|
||||
if (usuariosComRole.length > 0) {
|
||||
console.log(
|
||||
`⚠️ AVISO: Não é possível remover "${role.nome}" porque ${usuariosComRole.length} usuário(s) ainda usa(m) este perfil`
|
||||
);
|
||||
mantidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
});
|
||||
} else {
|
||||
// Remover permissões associadas
|
||||
const permissoes = await ctx.db
|
||||
.query("rolePermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
for (const perm of permissoes) {
|
||||
await ctx.db.delete(perm._id);
|
||||
}
|
||||
|
||||
// Remover menu permissões associadas
|
||||
const menuPerms = await ctx.db
|
||||
.query("menuPermissoes")
|
||||
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||
.collect();
|
||||
for (const menuPerm of menuPerms) {
|
||||
await ctx.db.delete(menuPerm._id);
|
||||
}
|
||||
|
||||
// Remover o role
|
||||
await ctx.db.delete(role._id);
|
||||
|
||||
removidos.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivel: role.nivel,
|
||||
motivo: motivo || "Não especificado",
|
||||
});
|
||||
console.log(
|
||||
`🗑️ REMOVIDO: ${role.nome} (${role.descricao}) - Nível ${role.nivel} - Motivo: ${motivo}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { removidos, mantidos };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Verificar se existem perfis com níveis incorretos
|
||||
*/
|
||||
export const verificarNiveisIncorretos = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
nome: v.string(),
|
||||
descricao: v.string(),
|
||||
nivelAtual: v.number(),
|
||||
nivelCorreto: v.number(),
|
||||
problema: v.string(),
|
||||
})
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
const roles = await ctx.db.query("roles").collect();
|
||||
const problemas: Array<{
|
||||
nome: string;
|
||||
descricao: string;
|
||||
nivelAtual: number;
|
||||
nivelCorreto: number;
|
||||
problema: string;
|
||||
}> = [];
|
||||
|
||||
for (const role of roles) {
|
||||
// TI_MASTER deve ser nível 0
|
||||
if (role.nome === "ti_master" && role.nivel !== 0) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 0,
|
||||
problema: "TI_MASTER deve ter acesso total (nível 0)",
|
||||
});
|
||||
}
|
||||
|
||||
// ADMIN deve ser nível 2
|
||||
if (role.nome === "admin" && role.nivel !== 2) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 2,
|
||||
problema: "ADMIN deve ser editável (nível 2)",
|
||||
});
|
||||
}
|
||||
|
||||
// TI_USUARIO deve ser nível 2
|
||||
if (role.nome === "ti_usuario" && role.nivel !== 2) {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: 2,
|
||||
problema: "TI_USUARIO deve ser editável (nível 2)",
|
||||
});
|
||||
}
|
||||
|
||||
// Perfil genérico "ti" não deveria existir
|
||||
if (role.nome === "ti") {
|
||||
problemas.push({
|
||||
nome: role.nome,
|
||||
descricao: role.descricao,
|
||||
nivelAtual: role.nivel,
|
||||
nivelCorreto: -1, // Indica que deve ser removido
|
||||
problema: "Perfil genérico obsoleto - usar ti_master ou ti_usuario",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return problemas;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user