@@ -3,6 +3,7 @@ import rateLimit from 'express-rate-limit';
33import argon2 from 'argon2' ;
44import jwt from 'jsonwebtoken' ;
55import { createHash , randomBytes } from 'crypto' ;
6+ import { isIP } from 'net' ;
67
78import { query } from '../config/db.js' ;
89import { generateToken , authenticateToken } from '../middleware/auth.js' ;
@@ -139,16 +140,28 @@ function isPrivateIp(ip) {
139140 return false ;
140141}
141142
142- async function isVpnOrProxy ( ip ) {
143- if ( isPrivateIp ( ip ) ) {
144- console . log ( '[VPN] Skipping private IP:' , ip ) ;
143+ function normalizeClientIp ( ip ) {
144+ if ( typeof ip !== 'string' ) return null ;
145+ const trimmed = ip . trim ( ) ;
146+ if ( ! trimmed ) return null ;
147+ const withoutV4Mapped = trimmed . replace ( / ^ : : f f f f : / , '' ) ;
148+ return isIP ( withoutV4Mapped ) ? withoutV4Mapped : null ;
149+ }
150+
151+ export async function isVpnOrProxy ( ip ) {
152+ const cleanIp = normalizeClientIp ( ip ) ;
153+ if ( ! cleanIp ) {
154+ console . log ( '[VPN] Skipping invalid IP:' , ip ) ;
145155 return false ;
146156 }
147157
148- const cleanIp = ip . replace ( / ^ : : f f f f : / , '' ) ;
158+ if ( isPrivateIp ( cleanIp ) ) {
159+ console . log ( '[VPN] Skipping private IP:' , cleanIp ) ;
160+ return false ;
161+ }
149162
150163 try {
151- const res = await fetchWithTimeout ( `http://ip-api.com/json/${ cleanIp } ?fields=proxy,hosting,isp,org,query` ) ;
164+ const res = await fetchWithTimeout ( `http://ip-api.com/json/${ encodeURIComponent ( cleanIp ) } ?fields=proxy,hosting,isp,org,query` ) ;
152165 const data = await res . json ( ) ;
153166 console . log ( '[VPN] ip-api response for' , cleanIp , ':' , JSON . stringify ( data ) ) ;
154167 return data . proxy === true || data . hosting === true ;
@@ -157,7 +170,7 @@ async function isVpnOrProxy(ip) {
157170 }
158171
159172 try {
160- const res = await fetchWithTimeout ( `https://ipinfo.io/${ cleanIp } /json` ) ;
173+ const res = await fetchWithTimeout ( `https://ipinfo.io/${ encodeURIComponent ( cleanIp ) } /json` ) ;
161174 const data = await res . json ( ) ;
162175 console . log ( '[VPN] ipinfo response for' , cleanIp , ':' , JSON . stringify ( { org : data . org } ) ) ;
163176 const orgLower = ( data . org || '' ) . toLowerCase ( ) ;
0 commit comments