feat: implement security enhancements for Jitsi integration, including JWT token generation and automatic blocking of detected attacks, improving system resilience and user authentication

This commit is contained in:
2026-01-12 04:34:00 -03:00
parent b965514e53
commit 664d90c2e0
27 changed files with 6174 additions and 329 deletions

View File

@@ -16,7 +16,24 @@ http.route({
const method = request.method;
// Extrair IP do cliente
const ipOrigem = getClientIP(request);
const ipOrigem = getClientIP(request) ?? '0.0.0.0';
// Enforcement (blacklist + rate limit) antes de processar
const enforcement = await ctx.runMutation(api.security.enforceRequest, {
ip: ipOrigem,
path: url.pathname,
method
});
if (!enforcement.allowed) {
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (enforcement.retryAfterMs) {
headers['Retry-After'] = String(Math.ceil(enforcement.retryAfterMs / 1000));
}
return new Response(JSON.stringify(enforcement), {
status: enforcement.status,
headers
});
}
// Extrair headers
const headers: Record<string, string> = {};
@@ -38,8 +55,8 @@ http.route({
// Ignorar erros ao ler body
}
// Analisar requisição para detectar ataques
const resultado = await ctx.runMutation(api.security.analisarRequisicaoHTTP, {
// Analisar requisição para detectar ataques ANTES de processar
const analise = await ctx.runMutation(api.security.analisarRequisicaoHTTP, {
url: url.pathname + url.search,
method,
headers,
@@ -49,7 +66,25 @@ http.route({
userAgent: request.headers.get('user-agent') ?? undefined
});
return new Response(JSON.stringify(resultado), {
// Se ataque detectado e bloqueio automático aplicado, retornar 403 imediatamente
if (analise.ataqueDetectado && analise.bloqueadoAutomatico) {
return new Response(
JSON.stringify({
ataqueDetectado: true,
bloqueado: true,
tipoAtaque: analise.tipoAtaque,
severidade: analise.severidade,
mensagem: 'Ataque detectado e bloqueado automaticamente'
}),
{
status: 403,
headers: { 'Content-Type': 'application/json' }
}
);
}
// Se ataque detectado mas sem bloqueio automático, retornar resultado normalmente
return new Response(JSON.stringify(analise), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
@@ -61,6 +96,19 @@ http.route({
path: '/security/rate-limit/seed-dev',
method: 'POST',
handler: httpAction(async (ctx) => {
// Hardening: endpoint apenas para dev/staging.
// Em Convex, NODE_ENV pode ser 'production' mesmo em dev local,
// então também aceitamos deployments locais "anonymous-*", ou uma flag explícita.
const deployment = process.env.CONVEX_DEPLOYMENT;
const siteUrl = process.env.SITE_URL || process.env.CONVEX_SITE_URL;
const enabled =
process.env.SECURITY_DEV_TOOLS === 'true' ||
(typeof siteUrl === 'string' && /localhost|127\.0\.0\.1/i.test(siteUrl)) ||
(typeof deployment === 'string' && deployment.startsWith('anonymous-')) ||
process.env.NODE_ENV !== 'production';
if (!enabled) {
return new Response('Not found', { status: 404 });
}
const resultado = await ctx.runMutation(api.security.seedRateLimitDev, {});
return new Response(JSON.stringify(resultado), {
status: 200,