updated code

This commit is contained in:
Bojan Kucera 2025-06-05 22:27:33 -04:00
parent 4ae7a41554
commit d4b9b2eb50

View file

@ -21,16 +21,64 @@ const NODE_ENV = process.env.NODE_ENV || 'production';
const objs: ApiResponse[] = []
// Create Fastify instance with trust proxy enabled
// Create Fastify instance with comprehensive trust proxy
const fastify = Fastify({
logger: NODE_ENV === 'development',
trustProxy: process.env.TRUST_PROXY === 'true' || true
trustProxy: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.1', '::1'] // Trust k8s networks
});
// Enhanced IP detection function
function getClientIP(request: FastifyRequest): string {
const headers = request.headers;
// Try multiple headers in order of preference
const ipSources = [
headers['cf-connecting-ip']?.toString(), // Cloudflare
headers['true-client-ip']?.toString(), // Akamai/other CDNs
headers['x-forwarded-for']?.toString().split(',')[0]?.trim(), // Most common
headers['x-client-ip']?.toString(), // Apache
headers['x-cluster-client-ip']?.toString(), // Cluster
headers['forwarded']?.toString().match(/for=([^;,\s]+)/)?.[1], // RFC 7239
request.ip, // Fastify default
request.socket.remoteAddress // Socket
];
// Filter out internal/private IPs and return first public IP
for (const ip of ipSources) {
if (ip && ip !== 'unknown' && !isPrivateIP(ip)) {
return ip;
}
}
// If no public IP found, return the first non-unknown IP
return ipSources.find(ip => ip && ip !== 'unknown') || 'unknown';
}
// Check if IP is private/internal
function isPrivateIP(ip: string): boolean {
if (!ip || ip === 'unknown') return true;
// Remove any port number
const cleanIP = ip.split(':')[0];
// Private IP ranges
const privateRanges = [
/^10\./, // 10.0.0.0/8
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12
/^192\.168\./, // 192.168.0.0/16
/^127\./, // 127.0.0.0/8 (localhost)
/^169\.254\./, // 169.254.0.0/16 (link-local)
/^::1$/, // IPv6 localhost
/^fe80:/ // IPv6 link-local
];
return privateRanges.some(range => range.test(cleanIP));
}
// API Key authentication middleware
fastify.addHook('preHandler', async (request: FastifyRequest, reply: FastifyReply) => {
// Skip auth for health check endpoint
if (request.url === '/health') {
// Skip auth for health check and debug endpoints
if (request.url === '/health' || request.url === '/ip-debug') {
return;
}
@ -55,9 +103,8 @@ fastify.addHook('preHandler', async (request: FastifyRequest, reply: FastifyRepl
// Helper function to get full IP chain
function getFullIPChain(request: FastifyRequest): { clientIP: string, ipChain: string[] } {
// Fastify automatically parses X-Forwarded-For when trustProxy is enabled
const clientIP = request.ip || 'unknown';
const ipChain = request.ips || []; // Full chain of IPs
const clientIP = getClientIP(request);
const ipChain = request.ips || [];
return {
clientIP,
@ -84,6 +131,27 @@ const start = async () => {
};
});
// IP Debug endpoint (bypasses authentication) - for troubleshooting
fastify.get('/ip-debug', async (request) => {
return {
detectedClientIP: getClientIP(request),
fastifyIP: request.ip,
fastifyIPs: request.ips,
socketIP: request.socket.remoteAddress,
allIPHeaders: {
'x-forwarded-for': request.headers['x-forwarded-for'],
'x-real-ip': request.headers['x-real-ip'],
'cf-connecting-ip': request.headers['cf-connecting-ip'],
'true-client-ip': request.headers['true-client-ip'],
'x-client-ip': request.headers['x-client-ip'],
'x-cluster-client-ip': request.headers['x-cluster-client-ip'],
'forwarded': request.headers['forwarded']
},
isPrivateIP: isPrivateIP(request.headers['x-real-ip']?.toString() || ''),
timestamp: Date.now()
};
});
// Random endpoint for testing
fastify.get('/random', async () => {
return objs[Math.round(objs.length * Math.random())] || { message: 'No data yet' };
@ -103,7 +171,7 @@ const start = async () => {
const ipInfo = getFullIPChain(request);
const obj = {
success: true,
clientIP: ipInfo.clientIP, // Fastify's auto-detected client IP
clientIP: ipInfo.clientIP, // Enhanced client IP detection
ipChain: ipInfo.ipChain, // Full proxy chain
foundIPs: result.ips, // IPs found by our custom parser
totalFound: result.ips.length,
@ -122,6 +190,7 @@ const start = async () => {
console.log(`🚀 Proxy Detection API running on http://localhost:${PORT}`);
console.log(`📍 Available endpoints:`);
console.log(` GET /health - Health check (no auth required)`);
console.log(` GET /ip-debug - IP debugging info (no auth required)`);
console.log(` GET / - Extract all IP addresses from request headers`);
console.log(` GET /random - Get random cached result`);
console.log(`🔑 API Key required for protected endpoints`);