Skip to content

Commit 6597707

Browse files
committed
fix: use HTTP for ip-api.com free tier, add ipinfo fallback, handle IPv6
1 parent a6130ab commit 6597707

1 file changed

Lines changed: 30 additions & 7 deletions

File tree

routes/auth.js

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,44 @@ async function fetchWithTimeout(url, options = {}, timeout = 5000) {
9191
}
9292
}
9393

94+
function isPrivateIp(ip) {
95+
if (ip === '127.0.0.1' || ip === '::1' || ip === '0.0.0.0' || ip === '::ffff:127.0.0.1') return true;
96+
if (ip.startsWith('192.168.') || ip.startsWith('10.') || ip.startsWith('172.16.')) return true;
97+
if (ip.startsWith('fc00:') || ip.startsWith('fd00:') || ip.startsWith('fe80:')) return true;
98+
if (ip.startsWith('::ffff:192.168.') || ip.startsWith('::ffff:10.') || ip.startsWith('::ffff:172.16.')) return true;
99+
return false;
100+
}
101+
94102
async function isVpnOrProxy(ip) {
95-
if (ip === '127.0.0.1' || ip === '::1' || ip === '0.0.0.0' ||
96-
ip.startsWith('192.168.') || ip.startsWith('10.') || ip.startsWith('172.16.')) {
103+
if (isPrivateIp(ip)) {
97104
console.log('[VPN] Skipping private IP:', ip);
98105
return false;
99106
}
107+
108+
const cleanIp = ip.replace(/^::ffff:/, '');
109+
100110
try {
101-
const res = await fetchWithTimeout(`https://ip-api.com/json/${ip}?fields=proxy,hosting,isp,org,query`);
111+
const res = await fetchWithTimeout(`http://ip-api.com/json/${cleanIp}?fields=proxy,hosting,isp,org,query`);
102112
const data = await res.json();
103-
console.log('[VPN] ip-api response for', ip, ':', JSON.stringify(data));
104-
return data.proxy === true || data.hosting === true;
113+
console.log('[VPN] ip-api response for', cleanIp, ':', JSON.stringify(data));
114+
if (data.proxy === true || data.hosting === true) return true;
105115
} catch (err) {
106-
console.log('[VPN] ip-api failed for', ip, ':', err.message);
107-
return false;
116+
console.log('[VPN] ip-api failed for', cleanIp, ':', err.message);
117+
}
118+
119+
try {
120+
const res = await fetchWithTimeout(`https://ipinfo.io/${cleanIp}/json`);
121+
const data = await res.json();
122+
console.log('[VPN] ipinfo response for', cleanIp, ':', JSON.stringify({ org: data.org, hosting: data.hosting }));
123+
if (data.org && (data.org.startsWith('AS') || data.org.toLowerCase().includes('vpn') ||
124+
data.org.toLowerCase().includes('proxy') || data.org.toLowerCase().includes('hosting'))) {
125+
return true;
126+
}
127+
} catch (err) {
128+
console.log('[VPN] ipinfo failed for', cleanIp, ':', err.message);
108129
}
130+
131+
return false;
109132
}
110133

111134
const MAX_EMAIL_LENGTH = 254;

0 commit comments

Comments
 (0)