- Implemented an internal mutation for login that captures the user's IP address and user agent for better security and tracking. - Enhanced the HTTP login endpoint to extract and log client IP, improving the overall authentication process. - Added validation for IP addresses to ensure only valid formats are recorded, enhancing data integrity. - Updated the login mutation to handle rate limiting and user status checks more effectively, providing clearer feedback on login attempts.
151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
import { httpRouter } from "convex/server";
|
|
import { httpAction } from "./_generated/server";
|
|
import { internal } from "./_generated/api";
|
|
import { getClientIP } from "./utils/getClientIP";
|
|
import { v } from "convex/values";
|
|
|
|
const http = httpRouter();
|
|
|
|
/**
|
|
* Endpoint de teste para debug - retorna todos os headers disponíveis
|
|
* GET /api/debug/headers
|
|
*/
|
|
http.route({
|
|
path: "/api/debug/headers",
|
|
method: "GET",
|
|
handler: httpAction(async (ctx, request) => {
|
|
const headers: Record<string, string> = {};
|
|
request.headers.forEach((value, key) => {
|
|
headers[key] = value;
|
|
});
|
|
|
|
const ip = getClientIP(request);
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
headers,
|
|
extractedIP: ip,
|
|
url: request.url,
|
|
}),
|
|
{
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}),
|
|
});
|
|
|
|
/**
|
|
* Endpoint HTTP para login que captura automaticamente o IP do cliente
|
|
* POST /api/login
|
|
* Body: { matriculaOuEmail: string, senha: string }
|
|
*/
|
|
http.route({
|
|
path: "/api/login",
|
|
method: "POST",
|
|
handler: httpAction(async (ctx, request) => {
|
|
try {
|
|
// Debug: Log todos os headers disponíveis
|
|
console.log("=== DEBUG: Headers HTTP ===");
|
|
const headersEntries: string[] = [];
|
|
request.headers.forEach((value, key) => {
|
|
headersEntries.push(`${key}: ${value}`);
|
|
});
|
|
console.log("Headers:", headersEntries.join(", "));
|
|
console.log("Request URL:", request.url);
|
|
|
|
// Extrair IP do cliente do request
|
|
let clientIP = getClientIP(request);
|
|
console.log("IP extraído:", clientIP);
|
|
|
|
// Se não encontrou IP, tentar obter do URL ou usar valor padrão
|
|
if (!clientIP) {
|
|
try {
|
|
const url = new URL(request.url);
|
|
// Tentar pegar do query param se disponível
|
|
const ipParam = url.searchParams.get("client_ip");
|
|
if (ipParam && /^(\d{1,3}\.){3}\d{1,3}$/.test(ipParam)) {
|
|
clientIP = ipParam;
|
|
console.log("IP obtido do query param:", clientIP);
|
|
} else {
|
|
// Se ainda não tiver IP, usar um identificador baseado no timestamp
|
|
// Isso pelo menos diferencia requisições
|
|
console.warn("IP não encontrado nos headers. Usando fallback.");
|
|
clientIP = undefined; // Deixar como undefined para registrar como não disponível
|
|
}
|
|
} catch {
|
|
console.warn("Erro ao processar URL para IP");
|
|
}
|
|
}
|
|
|
|
// Extrair User-Agent
|
|
const userAgent = request.headers.get("user-agent") || undefined;
|
|
|
|
// Ler body da requisição
|
|
const body = await request.json();
|
|
|
|
if (!body.matriculaOuEmail || !body.senha) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
sucesso: false,
|
|
erro: "Matrícula/Email e senha são obrigatórios",
|
|
}),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}
|
|
|
|
// Chamar a mutation de login interna com IP e userAgent
|
|
const resultado = await ctx.runMutation(internal.autenticacao.loginComIP, {
|
|
matriculaOuEmail: body.matriculaOuEmail,
|
|
senha: body.senha,
|
|
ipAddress: clientIP,
|
|
userAgent: userAgent,
|
|
});
|
|
|
|
return new Response(JSON.stringify(resultado), {
|
|
status: 200,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
"Access-Control-Allow-Headers": "Content-Type",
|
|
},
|
|
});
|
|
} catch (error) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
sucesso: false,
|
|
erro: error instanceof Error ? error.message : "Erro ao processar login",
|
|
}),
|
|
{
|
|
status: 500,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}
|
|
}),
|
|
});
|
|
|
|
/**
|
|
* Endpoint OPTIONS para CORS preflight
|
|
*/
|
|
http.route({
|
|
path: "/api/login",
|
|
method: "OPTIONS",
|
|
handler: httpAction(async () => {
|
|
return new Response(null, {
|
|
status: 200,
|
|
headers: {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
"Access-Control-Allow-Headers": "Content-Type",
|
|
},
|
|
});
|
|
}),
|
|
});
|
|
|
|
export default http;
|