feat: add marked library for markdown parsing and enhance documentation handling with new cron job for scheduled checks
This commit is contained in:
@@ -1804,7 +1804,7 @@ export const enviarMensagemChatSistema = internalMutation({
|
||||
conteudo: args.mensagem,
|
||||
conteudoBusca: args.mensagem.toLowerCase(),
|
||||
tipo: 'texto',
|
||||
criadaEm: Date.now()
|
||||
enviadaEm: Date.now()
|
||||
});
|
||||
|
||||
// Atualizar última mensagem da conversa
|
||||
@@ -1831,6 +1831,99 @@ export const enviarMensagemChatSistema = internalMutation({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Notificar quando rate limit é excedido
|
||||
*/
|
||||
export const notificarRateLimitExcedido = internalMutation({
|
||||
args: {
|
||||
configId: v.id('rateLimitConfig'),
|
||||
tipo: v.union(v.literal('ip'), v.literal('usuario'), v.literal('endpoint'), v.literal('global')),
|
||||
identificador: v.string(),
|
||||
endpoint: v.string(),
|
||||
acaoExcedido: v.union(v.literal('bloquear'), v.literal('throttle'), v.literal('alertar')),
|
||||
limite: v.number(),
|
||||
janelaSegundos: v.number()
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const config = await ctx.db.get(args.configId);
|
||||
if (!config) return null;
|
||||
|
||||
// Buscar usuários TI para notificar
|
||||
const rolesTi = await ctx.db
|
||||
.query('roles')
|
||||
.withIndex('by_nivel', (q) => q.lte('nivel', 1))
|
||||
.collect();
|
||||
|
||||
const usuariosNotificados: Id<'usuarios'>[] = [];
|
||||
|
||||
for (const role of rolesTi) {
|
||||
const membros = await ctx.db
|
||||
.query('usuarios')
|
||||
.withIndex('by_role', (q) => q.eq('roleId', role._id))
|
||||
.collect();
|
||||
for (const usuario of membros) {
|
||||
usuariosNotificados.push(usuario._id);
|
||||
}
|
||||
}
|
||||
|
||||
// Criar notificações para usuários TI
|
||||
const tipoAcao = args.acaoExcedido === 'bloquear' ? 'bloqueado' : args.acaoExcedido === 'alertar' ? 'alertado' : 'throttled';
|
||||
const emoji = args.acaoExcedido === 'bloquear' ? '🚫' : '⚠️';
|
||||
const titulo = `${emoji} Rate Limit ${tipoAcao === 'bloqueado' ? 'Bloqueado' : tipoAcao === 'alertado' ? 'Alertado' : 'Throttled'}`;
|
||||
const descricao = `${args.tipo.toUpperCase()}: ${args.identificador} excedeu o limite de ${args.limite} requisições em ${args.janelaSegundos}s no endpoint ${args.endpoint}`;
|
||||
|
||||
for (const usuarioId of usuariosNotificados) {
|
||||
await ctx.db.insert('notificacoes', {
|
||||
usuarioId,
|
||||
tipo: 'alerta_seguranca',
|
||||
conversaId: undefined,
|
||||
mensagemId: undefined,
|
||||
remetenteId: undefined,
|
||||
titulo,
|
||||
descricao,
|
||||
lida: false,
|
||||
criadaEm: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// Criar evento de segurança se foi bloqueado
|
||||
if (args.acaoExcedido === 'bloquear') {
|
||||
// Determinar tipo de ataque baseado no contexto
|
||||
let tipoAtaque: AtaqueCiberneticoTipo = 'brute_force';
|
||||
if (args.tipo === 'ip') {
|
||||
tipoAtaque = 'ddos';
|
||||
} else if (args.tipo === 'usuario') {
|
||||
tipoAtaque = 'brute_force';
|
||||
}
|
||||
|
||||
// Criar evento de segurança
|
||||
const eventoId = await ctx.db.insert('securityEvents', {
|
||||
referencia: `rate_limit_${args.tipo}_${args.identificador}_${Date.now()}`,
|
||||
timestamp: Date.now(),
|
||||
tipoAtaque,
|
||||
severidade: 'alto',
|
||||
status: 'detectado',
|
||||
descricao: `Rate limit bloqueado: ${args.identificador} excedeu ${args.limite} requisições em ${args.janelaSegundos}s`,
|
||||
origemIp: args.tipo === 'ip' ? args.identificador : undefined,
|
||||
tags: ['rate_limit', 'bloqueio_automatico'],
|
||||
atualizadoEm: Date.now()
|
||||
});
|
||||
|
||||
// Disparar alertas se configurado
|
||||
ctx.scheduler
|
||||
.runAfter(0, internal.security.dispararAlertasInternos, {
|
||||
eventoId
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Erro ao agendar alertas de rate limit:', error);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const expirarBloqueiosIpAutomaticos = internalMutation({
|
||||
args: {},
|
||||
returns: v.null(),
|
||||
@@ -1961,6 +2054,24 @@ async function aplicarRateLimit(
|
||||
if (!result.ok) {
|
||||
const retryAfter = result.retryAfter ?? periodo;
|
||||
|
||||
// Criar notificações e eventos quando rate limit é excedido
|
||||
// Usar scheduler para não bloquear a requisição
|
||||
if ('runMutation' in ctx) {
|
||||
ctx.scheduler
|
||||
.runAfter(0, internal.security.notificarRateLimitExcedido, {
|
||||
configId: config._id,
|
||||
tipo,
|
||||
identificador,
|
||||
endpoint: endpoint ?? 'default',
|
||||
acaoExcedido: config.acaoExcedido,
|
||||
limite: config.limite,
|
||||
janelaSegundos: config.janelaSegundos
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Erro ao agendar notificação de rate limit:', error);
|
||||
});
|
||||
}
|
||||
|
||||
if (config.acaoExcedido === 'bloquear') {
|
||||
return {
|
||||
permitido: false,
|
||||
|
||||
Reference in New Issue
Block a user