diff --git a/server/geo-service.js b/server/geo-service.js index e7a458e..68a4726 100644 --- a/server/geo-service.js +++ b/server/geo-service.js @@ -9,10 +9,28 @@ const db = require('./db'); const ipInfoToken = process.env.IPINFO_TOKEN; +/** + * Normalizes geo data for consistent display + */ +function normalizeGeo(geo) { + if (!geo) return geo; + + // Custom normalization for TW, HK, MO to "China, {CODE}" + const specialRegions = ['TW']; + if (specialRegions.includes(geo.country?.toUpperCase())) { + return { + ...geo, + city: `China, ${geo.country.toUpperCase()}`, + country_name: 'China' + }; + } + return geo; +} + async function getLocation(ip) { // Normalize IP (strip port if present) const cleanIp = ip.split(':')[0]; - + // Skip local/reserved IPs if (isLocalIp(cleanIp)) { return null; @@ -26,7 +44,7 @@ async function getLocation(ip) { const data = rows[0]; const age = Date.now() - new Date(data.last_updated).getTime(); if (age < 30 * 24 * 60 * 60 * 1000) { - return data; + return normalizeGeo(data); } } @@ -34,7 +52,7 @@ async function getLocation(ip) { console.log(`[Geo Service] Resolving location for IP: ${cleanIp}`); const url = `https://ipinfo.io/${cleanIp}/json${ipInfoToken ? `?token=${ipInfoToken}` : ''}`; const response = await axios.get(url, { timeout: 5000 }); - const geo = response.data; + const geo = normalizeGeo(response.data); if (geo && geo.loc) { const [lat, lon] = geo.loc.split(',').map(Number); @@ -80,12 +98,12 @@ async function getLocation(ip) { function isLocalIp(ip) { if (ip === 'localhost' || ip === '127.0.0.1' || ip === '::1') return true; - + // RFC1918 private addresses const p1 = /^10\./; const p2 = /^172\.(1[6-9]|2[0-9]|3[0-1])\./; const p3 = /^192\.168\./; - + return p1.test(ip) || p2.test(ip) || p3.test(ip); }