import axios from 'axios'; import { config } from '@config/index.js'; interface VPNAPIResponse { security: { is_vpn: boolean; is_proxy: boolean; is_tor: boolean; is_relay: boolean; is_datacenter: boolean; }; network: { asn: number; org: string; }; } const VPN_CHECK_CACHE = new Map(); const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours export async function checkVPN(ip: string): Promise<{ isVPN: boolean; isProxy: boolean; isDatacenter: boolean; isTOR: boolean; details?: string; }> { if (!config.VPN_DETECTION_ENABLED) { return { isVPN: false, isProxy: false, isDatacenter: false, isTOR: false }; } // Skip local/private IPs if (isPrivateIP(ip)) { return { isVPN: false, isProxy: false, isDatacenter: false, isTOR: false }; } // Check cache const cached = VPN_CHECK_CACHE.get(ip); if (cached && Date.now() - cached.timestamp < CACHE_TTL) { return { isVPN: cached.result, isProxy: false, isDatacenter: false, isTOR: false }; } try { let result: { isVPN: boolean; isProxy: boolean; isDatacenter: boolean; isTOR: boolean; details?: string }; if (config.IPAPI_KEY) { result = await checkWithIPAPI(ip); } else { result = await checkWithFreeAPI(ip); } VPN_CHECK_CACHE.set(ip, { result: result.isVPN || result.isProxy || result.isDatacenter, timestamp: Date.now() }); return result; } catch (error) { // On error, allow the request (fail open) console.warn(`VPN check failed for ${ip}:`, error); return { isVPN: false, isProxy: false, isDatacenter: false, isTOR: false, details: 'Check failed' }; } } async function checkWithIPAPI(ip: string) { const response = await axios.get(`http://ip-api.com/json/${ip}?fields=status,proxy,hosting,as,org`, { timeout: 5000, headers: { 'User-Agent': 'WhatsApp-Channel-Directory/1.0' }, }); if (response.data.status !== 'success') { throw new Error('IP API request failed'); } return { isVPN: false, isProxy: response.data.proxy === true, isDatacenter: response.data.hosting === true, isTOR: false, details: `ASN: ${response.data.as}, Org: ${response.data.org}`, }; } async function checkWithFreeAPI(ip: string): Promise<{ isVPN: boolean; isProxy: boolean; isDatacenter: boolean; isTOR: boolean; details?: string; }> { // Use a free API or local list - for now, return safe defaults // In production, integrate with a proper VPN detection service return { isVPN: false, isProxy: false, isDatacenter: false, isTOR: false, details: 'Free tier - limited detection', }; } function isPrivateIP(ip: string): boolean { const privateRanges = [ /^10\./, /^192\.168\./, /^172\.(1[6-9]|2[0-9]|3[0-1])\./, /^127\./, /^::1$/, /^fe80::/, /^fc00:/, /^fd00:/, ]; return privateRanges.some(range => range.test(ip)); } export function getClientIP(request: { headers: Record; ip?: string }): string { // Check various headers for real IP (behind proxy) const forwarded = request.headers['x-forwarded-for']; if (forwarded) { const ips = (Array.isArray(forwarded) ? forwarded[0] : forwarded).split(',').map(ip => ip.trim()); return ips[0]; } const realIP = request.headers['x-real-ip']; if (realIP) { return Array.isArray(realIP) ? realIP[0] : realIP; } return request.ip || 'unknown'; }