Chat-With-AI / src /core /security /vpnDetect.ts
NathMen12's picture
Upload 56 files
ef73937 verified
Raw
History Blame Contribute Delete
3.48 kB
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<string, { result: boolean; timestamp: number }>();
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<string, string | string[] | undefined>; 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';
}