163 lines
4.9 KiB
TypeScript
163 lines
4.9 KiB
TypeScript
/**
|
|
* Route handlers for the proxy detection API
|
|
*/
|
|
|
|
import { FastifyRequest } from 'fastify';
|
|
import { extractIPsFromHeaders } from './proxyService';
|
|
import { ApiResponse, HealthResponse, DetailedDebugResponse } from './types';
|
|
import { config } from './config';
|
|
import {
|
|
getClientIP,
|
|
getFullIPChain,
|
|
normalizeHeaders,
|
|
extractGeolocation,
|
|
extractProxyInfo
|
|
} from './utils';
|
|
|
|
// In-memory cache for results
|
|
const cachedResults: ApiResponse[] = [];
|
|
|
|
/**
|
|
* Health check endpoint
|
|
*/
|
|
export async function healthHandler(): Promise<HealthResponse> {
|
|
return {
|
|
status: 'healthy',
|
|
timestamp: Date.now(),
|
|
uptime: process.uptime(),
|
|
version: config.api.version
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Main proxy detection endpoint
|
|
*/
|
|
export async function mainHandler(request: FastifyRequest): Promise<ApiResponse> {
|
|
const headers = request.headers;
|
|
const normalizedHeaders = normalizeHeaders(headers);
|
|
|
|
const result = extractIPsFromHeaders(normalizedHeaders);
|
|
const ipInfo = getFullIPChain(request);
|
|
|
|
// Enhanced response with more context
|
|
const response: ApiResponse = {
|
|
success: true,
|
|
clientIP: ipInfo.clientIP,
|
|
ipChain: ipInfo.ipChain,
|
|
foundIPs: result.ips,
|
|
totalFound: result.ips.length,
|
|
headersSources: result.sources,
|
|
|
|
// Additional context
|
|
geolocation: extractGeolocation(normalizedHeaders),
|
|
proxy: extractProxyInfo(normalizedHeaders),
|
|
|
|
allHeaders: normalizedHeaders,
|
|
timestamp: Date.now()
|
|
};
|
|
|
|
// Cache management
|
|
if (cachedResults.length > config.server.maxCachedResults) {
|
|
cachedResults.shift();
|
|
}
|
|
cachedResults.push(response);
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* Random cached result endpoint
|
|
*/
|
|
export async function randomHandler(): Promise<ApiResponse | { message: string }> {
|
|
if (cachedResults.length === 0) {
|
|
return { message: 'No data yet' };
|
|
}
|
|
|
|
const randomIndex = Math.floor(Math.random() * cachedResults.length);
|
|
return cachedResults[randomIndex];
|
|
}
|
|
|
|
export async function allHandler(): Promise<string[] | { message: string }> {
|
|
if (cachedResults.length === 0) {
|
|
return { message: 'No data yet' };
|
|
}
|
|
return cachedResults.map(result => result.clientIP);
|
|
}
|
|
|
|
/**
|
|
* Detailed debug endpoint with all possible headers
|
|
*/
|
|
export async function detailedDebugHandler(request: FastifyRequest): Promise<DetailedDebugResponse> {
|
|
const headers = request.headers;
|
|
|
|
return {
|
|
allSources: {
|
|
// CDN Headers
|
|
'cf-connecting-ip': headers['cf-connecting-ip'],
|
|
'cf-pseudo-ipv4': headers['cf-pseudo-ipv4'],
|
|
'cf-ipcountry': headers['cf-ipcountry'],
|
|
'true-client-ip': headers['true-client-ip'],
|
|
'x-akamai-edgescape': headers['x-akamai-edgescape'],
|
|
'fastly-client-ip': headers['fastly-client-ip'],
|
|
|
|
// Standard Headers
|
|
'x-forwarded-for': headers['x-forwarded-for'],
|
|
'x-original-forwarded-for': headers['x-original-forwarded-for'],
|
|
'x-client-ip': headers['x-client-ip'],
|
|
'x-real-ip': headers['x-real-ip'],
|
|
'x-originating-ip': headers['x-originating-ip'],
|
|
'x-remote-ip': headers['x-remote-ip'],
|
|
'x-remote-addr': headers['x-remote-addr'],
|
|
|
|
// Load Balancer
|
|
'x-cluster-client-ip': headers['x-cluster-client-ip'],
|
|
'forwarded': headers['forwarded'],
|
|
'x-forwarded': headers['x-forwarded'],
|
|
'x-appengine-remote-addr': headers['x-appengine-remote-addr'],
|
|
|
|
// Cloud Provider
|
|
'x-azure-clientip': headers['x-azure-clientip'],
|
|
'x-azure-ref': headers['x-azure-ref'],
|
|
|
|
// Proxy/Firewall
|
|
'wl-proxy-client-ip': headers['wl-proxy-client-ip'],
|
|
'proxy-client-ip': headers['proxy-client-ip'],
|
|
'x-sucuri-clientip': headers['x-sucuri-clientip'],
|
|
'incap-client-ip': headers['incap-client-ip'],
|
|
|
|
// Mobile/Carrier
|
|
'x-nokia-msisdn': headers['x-nokia-msisdn'],
|
|
'x-up-calling-line-id': headers['x-up-calling-line-id'],
|
|
'http_client_ip': headers['http_client_ip'],
|
|
'http_x_forwarded_for': headers['http_x_forwarded_for'],
|
|
'remote_addr': headers['remote_addr'],
|
|
|
|
// Alternative
|
|
'x-coming-from': headers['x-coming-from'],
|
|
'x-forwarded-host': headers['x-forwarded-host'],
|
|
'x-host': headers['x-host'],
|
|
|
|
// Framework defaults
|
|
'fastify-ip': request.ip,
|
|
'socket-remote': request.socket.remoteAddress
|
|
},
|
|
detectedClientIP: getClientIP(request),
|
|
fastifyIPs: request.ips || [],
|
|
|
|
// Additional useful info
|
|
geolocation: {
|
|
'cf-ipcountry': headers['cf-ipcountry'], // Cloudflare country
|
|
'cf-ray': headers['cf-ray'], // Cloudflare ray ID
|
|
'x-forwarded-proto': headers['x-forwarded-proto'], // Protocol
|
|
'x-forwarded-port': headers['x-forwarded-port'], // Port
|
|
},
|
|
|
|
security: {
|
|
'x-sucuri-country': headers['x-sucuri-country'],
|
|
'x-forwarded-ssl': headers['x-forwarded-ssl'],
|
|
'x-url-scheme': headers['x-url-scheme'],
|
|
},
|
|
|
|
timestamp: Date.now()
|
|
};
|
|
}
|