From 1aa9db8e2a85967329469fb5c8ef6d72496c52e9 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Thu, 14 May 2026 07:27:23 +0000 Subject: [PATCH] Add real IP + geo location to Telegram notifications --- app/main.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/app/main.py b/app/main.py index 19de240..759e40e 100644 --- a/app/main.py +++ b/app/main.py @@ -65,6 +65,32 @@ logging.basicConfig( logger = logging.getLogger("portal") templates = Jinja2Templates(directory="templates") + +def _get_real_ip(request) -> str: + """Return real client IP, accounting for NPM → app proxy chain.""" + forwarded_for = request.headers.get("x-forwarded-for", "") + if forwarded_for: + # X-Forwarded-For: client, proxy1, proxy2 — take leftmost (real client) + return forwarded_for.split(",")[0].strip() + return request.client.host if request.client else "unknown" + + +def _get_geo(ip: str) -> str: + """Lookup city/country for IP via ip-api.com. Returns formatted string or empty.""" + try: + if ip in ("unknown", "127.0.0.1", "::1") or ip.startswith("10.") or ip.startswith("192.168."): + return "" + url = f"http://ip-api.com/json/{ip}?lang=ru&fields=status,country,regionName,city,query" + req = _urllib_request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) + with _urllib_request.urlopen(req, timeout=5) as resp: + data = _json.loads(resp.read()) + if data.get("status") == "success": + parts = [data.get("country", ""), data.get("regionName", ""), data.get("city", "")] + return ", ".join(p for p in parts if p) + except Exception: + pass + return "" + app = FastAPI(title="МОНТ - инфрастуктурный полигон") app.mount("/static", StaticFiles(directory="static"), name="static") @@ -466,6 +492,14 @@ async def request_access(request: Request, db: Session = Depends(get_db)): f"{products_text}" ) + ip = _get_real_ip(request) + geo = _get_geo(ip) + geo_text = "" + if geo: + geo_text += "\n📍 *Местоположение:* " + geo + geo_text += "\n🖥 *IP:* " + ip + text += geo_text + if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID: log_event("telegram_not_configured") return {"ok": True} @@ -519,6 +553,14 @@ async def contact_ruslan(request: Request): f"💬 *Сообщение:*\n{text}" ) + ip = _get_real_ip(request) + geo = _get_geo(ip) + geo_text = "" + if geo: + geo_text += f"\n📍 *Местоположение:* {geo}" + geo_text += f"\n🖥 *IP:* {ip}" + msg += geo_text + if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID: log_event("telegram_not_configured") return {"ok": True}