Files
myip/app.py

231 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Flask, request, render_template_string
import requests
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
RIPESTAT_BASE = "https://stat.ripe.net/data"
HTML_TEMPLATE = """<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<title>myip IP & RIPE Lookup</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/myip.css">
</head>
<body>
<div class="card">
{% if show_logo %}
<a href="https://www.netech-solution.it" class="logo-link" target="_blank" rel="noopener">
<img src="/static/logo.png" class="logo" alt="Logo">
</a>
{% endif %}
<div class="badge">
<span class="badge-dot"></span>
<span>IP &amp; RIPE Lookup</span>
</div>
<h1 class="title">Il tuo IP pubblico è:</h1>
<div class="ip-wrapper">
<span id="ip-value" class="ip">{{ ip }}</span>
</div>
<button id="copy-btn" class="copy-btn copy-btn-below" type="button">
<span class="copy-icon">📋</span>
<span class="copy-label">Copia IP</span>
</button>
<div class="divider"></div>
{% if ripe %}
<div class="ripe-title">Informazioni RIPE</div>
{% if ripe.holder %}
<div class="ripe-item"><strong>Provider:</strong> {{ ripe.holder }}</div>
{% endif %}
{% if ripe.prefix %}
<div class="ripe-item"><strong>Prefisso annunciato:</strong> {{ ripe.prefix }}</div>
{% endif %}
{% if ripe.asns %}
<div class="ripe-item"><strong>ASN:</strong> {{ ripe.asns | join(', ') }}</div>
{% endif %}
{% if ripe.routing_status %}
<div class="ripe-item"><strong>Routing Status:</strong> {{ ripe.routing_status }}</div>
{% endif %}
{% if ripe.reverse_dns %}
<div class="ripe-item"><strong>Reverse DNS:</strong> {{ ripe.reverse_dns }}</div>
{% endif %}
{% if ripe.geoloc %}
<div class="ripe-item">
<strong>GeoLocation:</strong>
{% if ripe.geoloc.code %}
<img src="https://flagsapi.com/{{ ripe.geoloc.code }}/flat/24.png" class="flag-icon" alt="{{ ripe.geoloc.code }}">
{% endif %}
{{ ripe.geoloc.country }}
</div>
{% endif %}
{% if ripe.abuse %}
<div class="ripe-item"><strong>Abuse Contact:</strong> {{ ripe.abuse }}</div>
{% endif %}
<div class="ripe-muted">Dati ottenuti tramite RIPEstat Data API.</div>
{% else %}
<div class="ripe-title">Informazioni RIPE</div>
<div class="ripe-muted">
Non è stato possibile recuperare i dettagli RIPE per questo indirizzo.
</div>
{% endif %}
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
var card = document.querySelector(".card");
if (card) card.classList.add("card-visible");
var btn = document.getElementById("copy-btn");
var ipSpan = document.getElementById("ip-value");
if (!btn || !ipSpan) return;
btn.addEventListener("click", function () {
var ip = ipSpan.textContent.trim();
if (!ip) return;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(ip).then(function () {
var labelEl = btn.querySelector(".copy-label");
var original = labelEl.textContent;
btn.classList.add("copy-btn-success");
labelEl.textContent = "Copiato!";
setTimeout(function () {
btn.classList.remove("copy-btn-success");
labelEl.textContent = original;
}, 1500);
}).catch(console.error);
}
});
});
</script>
</body>
</html>
"""
def get_client_ip():
"""Determina l'IP reale del client dietro proxy / load balancer."""
xff = request.headers.get("X-Forwarded-For", "")
if xff:
parts = [p.strip() for p in xff.split(",") if p.strip()]
if parts:
return parts[0]
xri = request.headers.get("X-Real-IP")
if xri:
return xri.strip()
return request.remote_addr or "Sconosciuto"
def fetch_ripe_info(ip: str):
"""Recupera informazioni RIPEstat estese per l'IP."""
info = {
"prefix": None,
"asns": [],
"holder": None,
"routing_status": None,
"reverse_dns": None,
"geoloc": None,
"abuse": None,
}
try:
# 1. Network info (prefisso + ASN)
ni = requests.get(
f"{RIPESTAT_BASE}/network-info/data.json",
params={"resource": ip},
timeout=2,
).json().get("data", {})
info["prefix"] = ni.get("prefix")
asns = ni.get("asns") or []
info["asns"] = [f"AS{a}" for a in asns]
# 2. AS overview (holder/provider)
if asns:
ao = requests.get(
f"{RIPESTAT_BASE}/as-overview/data.json",
params={"resource": asns[0]},
timeout=2,
).json().get("data", {})
info["holder"] = ao.get("holder")
# 3. Routing status / visibility
rs = requests.get(
f"{RIPESTAT_BASE}/routing-status/data.json",
params={"resource": ip},
timeout=2,
).json().get("data", {})
info["routing_status"] = rs.get("status")
# 4. Reverse DNS
rd = requests.get(
f"{RIPESTAT_BASE}/reverse-dns/data.json",
params={"resource": ip},
timeout=2,
).json().get("data", {}).get("result", [])
info["reverse_dns"] = rd[0].get("name") if rd else None
# 5. GeoLocation
gl = requests.get(
f"{RIPESTAT_BASE}/geoloc/data.json",
params={"resource": ip},
timeout=2,
).json().get("data", {})
country = None
if gl.get("locations"):
country = gl["locations"][0].get("country", {})
if country:
info["geoloc"] = {
"country": country.get("name"),
"code": country.get("code"),
}
# 6. Abuse Contact
ac = requests.get(
f"{RIPESTAT_BASE}/abuse-contact-finder/data.json",
params={"resource": ip},
timeout=2,
).json().get("data", {})
emails = ac.get("emails") or []
info["abuse"] = emails[0] if emails else None
except Exception:
# In caso di errore lasciamo info parziali / vuote
pass
return info
@app.route("/")
def index():
ip = get_client_ip()
ripe_info = fetch_ripe_info(ip) if ip != "Sconosciuto" else None
return render_template_string(
HTML_TEMPLATE,
ip=ip,
ripe=ripe_info,
show_logo=True,
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)