Adds visitor dashboard and related features
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
"""Probe the GeoLite2 database to find IPs that resolve to real countries.
|
||||
|
||||
Run inside the api container:
|
||||
docker compose exec api python /app/probe_geo.py
|
||||
|
||||
Or locally if the DB is present:
|
||||
python probe_geo.py /path/to/GeoLite2-City.mmdb
|
||||
|
||||
Tests a curated list of well-known public IPs and prints the ones that resolve.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
import maxminddb
|
||||
|
||||
# Well-known public IPs from various countries
|
||||
CANDIDATE_IPS = [
|
||||
# United States
|
||||
("23.21.30.100", "US"),
|
||||
("72.14.198.234", "US"),
|
||||
("68.49.71.1", "US"),
|
||||
("208.67.222.222", "US"), # OpenDNS
|
||||
("74.125.200.100", "US"), # Google
|
||||
("151.101.1.69", "US"), # Fastly
|
||||
("142.250.80.46", "US"), # Google
|
||||
("216.58.214.206", "US"), # Google
|
||||
("172.217.164.110", "US"), # Google
|
||||
("13.107.42.14", "US"), # Microsoft
|
||||
("20.190.128.1", "US"), # Microsoft
|
||||
("52.84.74.1", "US"), # AWS CloudFront
|
||||
("99.86.0.1", "US"), # AWS
|
||||
# United Kingdom
|
||||
("81.2.69.142", "GB"),
|
||||
("212.58.224.10", "GB"),
|
||||
("51.140.137.15", "GB"),
|
||||
("178.173.57.1", "GB"),
|
||||
# France
|
||||
("51.140.137.15", "FR"),
|
||||
("193.70.150.1", "FR"),
|
||||
# Japan
|
||||
("210.170.232.46", "JP"),
|
||||
("133.244.200.1", "JP"),
|
||||
("202.214.69.1", "JP"), # NTT
|
||||
("210.188.206.1", "JP"), # Softbank
|
||||
# Germany
|
||||
("217.160.0.1", "DE"),
|
||||
("212.227.156.1", "DE"),
|
||||
("2a02:2e0::1", "DE"), # IPv6 - may not resolve
|
||||
("217.69.70.1", "DE"),
|
||||
# Australia
|
||||
("101.168.100.1", "AU"),
|
||||
("203.50.224.1", "AU"),
|
||||
("1.35.128.1", "AU"), # Telstra
|
||||
# Brazil
|
||||
("177.72.120.1", "BR"),
|
||||
("200.149.130.1", "BR"),
|
||||
("189.75.1.1", "BR"),
|
||||
# Canada
|
||||
("76.69.248.1", "CA"),
|
||||
("24.199.12.1", "CA"),
|
||||
("99.248.1.1", "CA"), # Bell
|
||||
# India
|
||||
("117.239.1.1", "IN"),
|
||||
("180.151.1.1", "IN"),
|
||||
("106.192.1.1", "IN"),
|
||||
# South Korea
|
||||
("1.235.198.1", "KR"),
|
||||
("211.36.1.1", "KR"),
|
||||
# Netherlands
|
||||
("185.30.1.1", "NL"),
|
||||
("94.23.1.1", "NL"),
|
||||
# Mexico
|
||||
("189.203.1.1", "MX"),
|
||||
("200.44.1.1", "MX"),
|
||||
# Italy
|
||||
("217.20.1.1", "IT"),
|
||||
("93.45.1.1", "IT"),
|
||||
# Spain
|
||||
("213.99.1.1", "ES"),
|
||||
("88.0.1.1", "ES"),
|
||||
# Sweden
|
||||
("213.248.1.1", "SE"),
|
||||
# Poland
|
||||
("79.133.1.1", "PL"),
|
||||
# Argentina
|
||||
("190.15.1.1", "AR"),
|
||||
# South Africa
|
||||
("196.201.1.1", "ZA"),
|
||||
# Egypt
|
||||
("213.53.1.1", "EG"),
|
||||
# Turkey
|
||||
("37.146.1.1", "TR"),
|
||||
# Russia
|
||||
("77.88.55.1", "RU"), # Yandex DNS
|
||||
("5.255.255.1", "RU"),
|
||||
]
|
||||
|
||||
|
||||
def probe(db_path: str):
|
||||
"""Test each candidate IP against the GeoLite2 database."""
|
||||
reader = maxminddb.open_database(db_path)
|
||||
results = []
|
||||
|
||||
# Deduplicate IPs but keep all expected countries
|
||||
seen_ips = set()
|
||||
for ip, expected_country in CANDIDATE_IPS:
|
||||
if ip in seen_ips:
|
||||
continue
|
||||
seen_ips.add(ip)
|
||||
|
||||
try:
|
||||
result = reader.lookup(ip)
|
||||
if result is None:
|
||||
continue
|
||||
|
||||
country = result.get("country", {})
|
||||
city = result.get("city", {})
|
||||
location = result.get("location", {})
|
||||
|
||||
country_code = country.get("iso_code", "")
|
||||
country_name = country.get("names", {}).get("en", country_code)
|
||||
city_name = city.get("names", {}).get("en", "")
|
||||
lat = location.get("latitude")
|
||||
lon = location.get("longitude")
|
||||
|
||||
results.append({
|
||||
"ip": ip,
|
||||
"country": country_name,
|
||||
"country_code": country_code,
|
||||
"city": city_name,
|
||||
"latitude": lat,
|
||||
"longitude": lon,
|
||||
})
|
||||
except Exception as e:
|
||||
print(f" ERROR looking up {ip}: {e}")
|
||||
|
||||
reader.close()
|
||||
return results
|
||||
|
||||
|
||||
def main():
|
||||
# Determine DB path
|
||||
db_path = None
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
# Explicit path provided
|
||||
db_path = sys.argv[1]
|
||||
else:
|
||||
# Try common locations
|
||||
candidates = [
|
||||
"/app/geo/GeoLite2-City.mmdb", # container path
|
||||
os.path.join(os.path.dirname(__file__), "geo", "GeoLite2-City.mmdb"), # local
|
||||
]
|
||||
for p in candidates:
|
||||
if os.path.exists(p):
|
||||
db_path = p
|
||||
break
|
||||
|
||||
if db_path is None:
|
||||
print("GeoLite2-City.mmdb not found.")
|
||||
print("Usage:")
|
||||
print(" docker compose exec api python /app/probe_geo.py")
|
||||
print(" python probe_geo.py /path/to/GeoLite2-City.mmdb")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Probing GeoLite2 at: {db_path}")
|
||||
results = probe(db_path)
|
||||
|
||||
if not results:
|
||||
print("No IPs resolved! The database might be empty or outdated.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\nResolved {len(results)} IPs:\n")
|
||||
|
||||
# Group by country
|
||||
by_country = {}
|
||||
for r in results:
|
||||
by_country.setdefault(r["country_code"], []).append(r)
|
||||
|
||||
for cc in sorted(by_country.keys()):
|
||||
entries = by_country[cc]
|
||||
print(f" {cc} ({entries[0]['country']}):")
|
||||
for e in entries:
|
||||
print(f" {e['ip']:20s} -> {e['city'] or 'N/A':20s} ({e['latitude']}, {e['longitude']})")
|
||||
|
||||
# Output as Python tuples for inject_test_logs.py
|
||||
print(f"\n\nTuples for inject_test_logs.py TEST_IPS:")
|
||||
print("TEST_IPS = [")
|
||||
for r in results:
|
||||
print(f' ("{r["ip"]}", "{r["country"]}", "{r["city"]}"),')
|
||||
print("]")
|
||||
|
||||
# Also output JSON for convenience
|
||||
print(f"\nJSON output:")
|
||||
print(json.dumps(results, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user