129
src/lib/proxy-utils.js
Archivo normal
129
src/lib/proxy-utils.js
Archivo normal
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Extrae la IP real del cliente considerando proxies como nginx
|
||||
* @param {Request} request - La request de Next.js
|
||||
* @returns {string} La IP del cliente
|
||||
*/
|
||||
export function getClientIP(request) {
|
||||
// Headers que pueden contener la IP real del cliente
|
||||
const forwardedFor = request.headers.get('x-forwarded-for');
|
||||
const realIP = request.headers.get('x-real-ip');
|
||||
const cfConnectingIP = request.headers.get('cf-connecting-ip'); // Cloudflare
|
||||
const trueClientIP = request.headers.get('true-client-ip'); // Cloudflare Enterprise
|
||||
const xClientIP = request.headers.get('x-client-ip');
|
||||
const xForwardedHost = request.headers.get('x-forwarded-host');
|
||||
|
||||
// Prioridad de headers (más confiables primero)
|
||||
let clientIP = null;
|
||||
|
||||
// 1. Cloudflare headers (muy confiables)
|
||||
if (trueClientIP) {
|
||||
clientIP = trueClientIP.trim();
|
||||
} else if (cfConnectingIP) {
|
||||
clientIP = cfConnectingIP.trim();
|
||||
}
|
||||
// 2. X-Real-IP (nginx real_ip_module)
|
||||
else if (realIP) {
|
||||
clientIP = realIP.trim();
|
||||
}
|
||||
// 3. X-Forwarded-For (puede contener múltiples IPs)
|
||||
else if (forwardedFor) {
|
||||
// X-Forwarded-For puede contener múltiples IPs separadas por comas
|
||||
// La primera es la IP original del cliente
|
||||
const ips = forwardedFor.split(',').map(ip => ip.trim());
|
||||
clientIP = ips[0];
|
||||
}
|
||||
// 4. Otros headers menos comunes
|
||||
else if (xClientIP) {
|
||||
clientIP = xClientIP.trim();
|
||||
}
|
||||
|
||||
// Validar que la IP obtenida sea válida
|
||||
if (clientIP && isValidIP(clientIP)) {
|
||||
return clientIP;
|
||||
}
|
||||
|
||||
// Fallback: usar una IP por defecto
|
||||
return '127.0.0.1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida si una cadena es una IP válida (IPv4 o IPv6)
|
||||
* @param {string} ip - La IP a validar
|
||||
* @returns {boolean} True si es válida
|
||||
*/
|
||||
function isValidIP(ip) {
|
||||
// Regex básico para IPv4
|
||||
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
// Regex básico para IPv6
|
||||
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$/;
|
||||
|
||||
if (ipv4Regex.test(ip)) {
|
||||
// Validar rangos de IPv4 (0-255)
|
||||
const parts = ip.split('.');
|
||||
return parts.every(part => {
|
||||
const num = parseInt(part, 10);
|
||||
return num >= 0 && num <= 255;
|
||||
});
|
||||
}
|
||||
|
||||
if (ipv6Regex.test(ip) || ip === '::1' || ip.startsWith('::ffff:')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene información detallada del proxy y cliente
|
||||
* @param {Request} request - La request de Next.js
|
||||
* @returns {object} Información del cliente y proxy
|
||||
*/
|
||||
export function getProxyInfo(request) {
|
||||
const headers = {};
|
||||
|
||||
// Recopilar todos los headers relevantes para debugging
|
||||
const proxyHeaders = [
|
||||
'x-forwarded-for',
|
||||
'x-real-ip',
|
||||
'x-forwarded-proto',
|
||||
'x-forwarded-host',
|
||||
'x-forwarded-port',
|
||||
'cf-connecting-ip',
|
||||
'true-client-ip',
|
||||
'x-client-ip',
|
||||
'x-cluster-client-ip',
|
||||
'forwarded'
|
||||
];
|
||||
|
||||
proxyHeaders.forEach(header => {
|
||||
const value = request.headers.get(header);
|
||||
if (value) {
|
||||
headers[header] = value;
|
||||
}
|
||||
});
|
||||
|
||||
const clientIP = getClientIP(request);
|
||||
|
||||
return {
|
||||
clientIP,
|
||||
proxyHeaders: headers,
|
||||
isProxied: Object.keys(headers).length > 0,
|
||||
userAgent: request.headers.get('user-agent') || 'unknown'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware helper para configurar trust proxy en desarrollo
|
||||
* @param {Request} request
|
||||
* @returns {object} Configuración de trust
|
||||
*/
|
||||
export function getTrustProxyConfig(request) {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const trustProxy = process.env.TRUST_PROXY === 'true';
|
||||
|
||||
return {
|
||||
trustProxy: isProduction || trustProxy,
|
||||
clientIP: getClientIP(request),
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
};
|
||||
}
|
||||
Referencia en una nueva incidencia
Block a user