|
|
from fastapi import FastAPI, Request |
|
|
from fastapi.responses import RedirectResponse |
|
|
from user_agents import parse |
|
|
import geoip2.database |
|
|
from pathlib import Path |
|
|
import os |
|
|
import httpx |
|
|
|
|
|
app = FastAPI() |
|
|
|
|
|
|
|
|
GOOGLE_SHEET_WEBHOOK = os.getenv("GOOGLE_SHEET_WEBHOOK") |
|
|
if not GOOGLE_SHEET_WEBHOOK: |
|
|
raise RuntimeError("GOOGLE_SHEET_WEBHOOK environment variable not set") |
|
|
|
|
|
REDIRECT_URL = os.getenv("REDIRECT_URL") |
|
|
if not REDIRECT_URL: |
|
|
raise RuntimeError("REDIRECT_URL environment variable not set") |
|
|
|
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent |
|
|
CITY_DB_PATH = BASE_DIR / "databases" / "GeoLite2-City.mmdb" |
|
|
ASN_DB_PATH = BASE_DIR / "databases" / "GeoLite2-ASN.mmdb" |
|
|
|
|
|
city_reader = geoip2.database.Reader(str(CITY_DB_PATH)) |
|
|
asn_reader = geoip2.database.Reader(str(ASN_DB_PATH)) |
|
|
|
|
|
|
|
|
@app.get("/offer") |
|
|
async def track_ip(request: Request): |
|
|
|
|
|
|
|
|
client_ip = request.headers.get("X-Forwarded-For") |
|
|
if client_ip: |
|
|
client_ip = client_ip.split(",")[0].strip() |
|
|
else: |
|
|
client_ip = request.client.host |
|
|
|
|
|
|
|
|
ua_string = request.headers.get("User-Agent", "Unknown") |
|
|
ua = parse(ua_string) |
|
|
|
|
|
browser_info = { |
|
|
"browser": ua.browser.family, |
|
|
"version": ua.browser.version_string, |
|
|
"os": ua.os.family, |
|
|
"os_version": ua.os.version_string, |
|
|
"device": ua.device.family, |
|
|
"is_mobile": ua.is_mobile, |
|
|
"is_bot": ua.is_bot |
|
|
} |
|
|
|
|
|
|
|
|
geo_data = {} |
|
|
try: |
|
|
city = city_reader.city(client_ip) |
|
|
geo_data = { |
|
|
"country": city.country.name, |
|
|
"city": city.city.name, |
|
|
"region": city.subdivisions.most_specific.name, |
|
|
"latitude": city.location.latitude, |
|
|
"longitude": city.location.longitude |
|
|
} |
|
|
except Exception as e: |
|
|
print("Geo error:", e) |
|
|
|
|
|
|
|
|
asn_data = {} |
|
|
try: |
|
|
asn = asn_reader.asn(client_ip) |
|
|
asn_data = { |
|
|
"asn": asn.autonomous_system_number, |
|
|
"org": asn.autonomous_system_organization |
|
|
} |
|
|
except Exception as e: |
|
|
print("ASN error:", e) |
|
|
|
|
|
payload = { |
|
|
"ip": client_ip, |
|
|
"browser": browser_info, |
|
|
"geolocation": geo_data, |
|
|
"asn": asn_data |
|
|
} |
|
|
|
|
|
|
|
|
try: |
|
|
async with httpx.AsyncClient(timeout=5, follow_redirects=True) as client: |
|
|
await client.post( |
|
|
GOOGLE_SHEET_WEBHOOK, |
|
|
json=payload, |
|
|
headers={"Content-Type": "application/json"} |
|
|
) |
|
|
except Exception as e: |
|
|
print("Sheet error:", e) |
|
|
|
|
|
'''return payload''' |
|
|
|
|
|
|
|
|
return RedirectResponse( |
|
|
url=REDIRECT_URL, |
|
|
status_code=302 |
|
|
) |
|
|
|
|
|
|
|
|
@app.on_event("shutdown") |
|
|
def shutdown(): |
|
|
city_reader.close() |
|
|
asn_reader.close() |