diff --git a/app.py b/app.py index c52f8bb..bb1567a 100644 --- a/app.py +++ b/app.py @@ -781,18 +781,48 @@ def api_track_upload(): "email_html": f"{SITE}/t/{token}/html", "note": "attach/email the HTML version — every view fires the pixel and lands in the inbox"}) +def _geo_cache(): + con = db() + con.execute("CREATE TABLE IF NOT EXISTS geo_cache(ip TEXT PRIMARY KEY, geo TEXT, ts INTEGER)") + return con + +def enrich_ip(ip): + """geo/ISP/ASN for an IP, cached 24h.""" + if not ip or ip == "created" or ip.startswith(("10.30.20.", "127.", "172.17.")): return {} + con = _geo_cache() + r = con.execute("SELECT geo FROM geo_cache WHERE ip=? AND ts > ?", (ip, int(time.time())-86400)).fetchone() + if r: return json.loads(r["geo"]) + st, b = http(f"http://ip-api.com/json/{ip}?fields=66846719") + d = jf(b) or {} + geo = {k: d.get(k) for k in ("country","countryCode","regionName","city","zip","lat","lon","timezone","isp","org","as","asname","mobile","proxy","hosting","reverse","query") if d.get(k) is not None} + con.execute("INSERT OR REPLACE INTO geo_cache(ip,geo,ts) VALUES(?,?,?)", (ip, json.dumps(geo), int(time.time()))) + con.commit() + return geo + +def _log_open(t, extra=""): + con = db() + ip = request.headers.get("X-Real-IP") or request.remote_addr or "?" + ua = request.headers.get("User-Agent","") + lang = request.headers.get("Accept-Language","") + ref = request.headers.get("Referer","") + geo = enrich_ip(ip) + where = "" + if geo: where = f" — {geo.get('city','')}, {geo.get('regionName','')} {geo.get('countryCode','')} · {geo.get('isp','')} · tz {geo.get('timezone','')}" + if geo.get("proxy"): where += " · VPN/proxy ⚠" + con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)", + (t["id"], int(time.time()), ip + (" " + json.dumps(geo) if geo else ""), ua[:200] + (f" | lang={lang}" if lang else "") + (f" | ref={ref[:100]}" if ref else ""))) + uid = t["user_id"] + if uid: + con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)", + (uid, "operator-bot", f"👁 '{esc(t['filename'])}' just opened{extra} — IP {esc(ip)}{esc(where)}
device: {esc(ua[:100])}{'
lang: ' + esc(lang) if lang else ''}{'
from: ' + esc(ref[:120]) if ref else ''}", int(time.time()))) + con.commit() + @app.route("/t/") def tracked_download(token): con = db() t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone() if not t or not t["paid"]: return "not found", 404 - con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)", - (t["id"], int(time.time()), request.headers.get("X-Real-IP") or request.remote_addr, request.headers.get("User-Agent",""))) - uid = t["user_id"] - if uid: - con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)", - (uid, "operator-bot", f"👁 your tracked file '{esc(t['filename'])}' was just opened — IP {esc(request.headers.get('X-Real-IP') or request.remote_addr)}, device: {esc(request.headers.get('User-Agent','')[:80])}", int(time.time()))) - con.commit() + _log_open(t, " (link)") path = os.path.join(UPLOAD_DIR, token + ".bin") if not os.path.exists(path): return "file gone", 404 return send_file(path, as_attachment=True, download_name=t["filename"]) @@ -802,13 +832,7 @@ def tracked_pixel(token): con = db() t = con.execute("SELECT * FROM trackables WHERE token=?", (token,)).fetchone() if t and t["paid"]: - con.execute("INSERT INTO track_events(trackable_id,ts,ip,ua) VALUES(?,?,?,?)", - (t["id"], int(time.time()), request.headers.get("X-Real-IP") or request.remote_addr, request.headers.get("User-Agent",""))) - uid = t["user_id"] - if uid: - con.execute("INSERT INTO messages(user_id,sender,body,created) VALUES(?,?,?,?)", - (uid, "operator-bot", f"👁 '{esc(t['filename'])}' was just viewed (email/pixel) — IP {esc(request.headers.get('X-Real-IP') or request.remote_addr)}", int(time.time()))) - con.commit() + _log_open(t, " (email/pixel)") px = base64.b64decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") return Response(px, mimetype="image/gif", headers={"Cache-Control": "no-store"})