diff --git a/Dockerfile b/Dockerfile
index dfcbf85..55136b4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,4 +4,4 @@ COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
-CMD ["python","app.py"]
+CMD ["python","app.py"]
\ No newline at end of file
diff --git a/README.md b/README.md
index aba9c29..6c40a3c 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,3 @@
-# IP WebApp
+# myip WebApp Modern UI
-Una semplice webapp Flask che mostra:
-- IP pubblico del visitatore
-- Informazioni RIPE (ASN, holder, prefix)
-
-## Build
-
-```
-docker build -t ip-webapp .
-```
-
-## Run
-
-```
-docker run --rm -p 8080:8000 ip-webapp
-```
-
-Visita: http://localhost:8080
+Include Montserrat, animations, copy-IP button, favicon.
diff --git a/app.py b/app.py
index f6c8bc2..382f322 100644
--- a/app.py
+++ b/app.py
@@ -1,53 +1,138 @@
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)
HTML_TEMPLATE = """
- Il tuo IP pubblico
+ myip – IP & RIPE Lookup
+
+
+
+
+
+
+
- Il tuo IP pubblico è: {{ ip }}
- {% if ripe %}
- Informazioni RIPE
- Provider: {{ ripe.holder }}
- Prefisso: {{ ripe.prefix }}
- ASN: {{ ripe.asns|join(', ') }}
- {% endif %}
+
+ {% if show_logo %}
+

+ {% endif %}
+
+
+ IP & RIPE Lookup
+
+
Il tuo IP pubblico è:
+
+
+ {{ ip }}
+
+
+
+
+
+ {% if ripe %}
+
Informazioni RIPE
+ {% if ripe.holder %}
+
Provider: {{ ripe.holder }}
+ {% endif %}
+ {% if ripe.prefix %}
+
Prefisso: {{ ripe.prefix }}
+ {% endif %}
+ {% if ripe.asns %}
+
ASN: {{ ripe.asns | join(', ') }}
+ {% endif %}
+
Dati ottenuti tramite RIPEstat Data API.
+ {% else %}
+
Informazioni RIPE
+
+ Non è stato possibile recuperare i dettagli RIPE per questo indirizzo.
+
+ {% endif %}
+
+
+
"""
+RIPESTAT_BASE = "https://stat.ripe.net/data"
+
def get_client_ip():
xff = request.headers.get("X-Forwarded-For", "")
if xff:
- return xff.split(",")[0].strip()
+ 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):
try:
- ni = requests.get("https://stat.ripe.net/data/network-info/data.json",
- params={"resource": ip}, timeout=2).json().get("data", {})
- prefix = ni.get("prefix")
- asns = ni.get("asns") or []
- holder=None
+ ni_resp = requests.get(f"{RIPESTAT_BASE}/network-info/data.json", params={"resource": ip}, timeout=2)
+ ni_resp.raise_for_status()
+ ni_data = ni_resp.json().get("data", {})
+
+ prefix = ni_data.get("prefix")
+ asns = ni_data.get("asns") or []
+ holder = None
+
if asns:
- ao = requests.get("https://stat.ripe.net/data/as-overview/data.json",
- params={"resource": asns[0]}, timeout=2).json().get("data", {})
- holder = ao.get("holder")
- return {"prefix": prefix, "asns":[f"AS{a}" for a in asns], "holder": holder}
+ first_asn = asns[0]
+ ao_resp = requests.get(f"{RIPESTAT_BASE}/as-overview/data.json", params={"resource": first_asn}, timeout=2)
+ ao_resp.raise_for_status()
+ holder = ao_resp.json().get("data", {}).get("holder")
+
+ class R: pass
+ r = R()
+ r.prefix = prefix
+ r.asns = [f"AS{x}" for x in asns] if asns else []
+ r.holder = holder
+
+ return r if any([r.prefix, r.asns, r.holder]) else None
except:
return None
@app.route("/")
def index():
ip = get_client_ip()
- ripe = fetch_ripe_info(ip) if ip!="Sconosciuto" else None
- return render_template_string(HTML_TEMPLATE, ip=ip, ripe=ripe)
+ ripe = fetch_ripe_info(ip) if ip != "Sconosciuto" else None
+ return render_template_string(HTML_TEMPLATE, ip=ip, ripe=ripe, show_logo=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
diff --git a/static/favicon.png b/static/favicon.png
new file mode 100644
index 0000000..71399c1
Binary files /dev/null and b/static/favicon.png differ
diff --git a/static/logo.png b/static/logo.png
index e69de29..fa08dc4 100644
Binary files a/static/logo.png and b/static/logo.png differ
diff --git a/static/myip.css b/static/myip.css
new file mode 100644
index 0000000..f258416
--- /dev/null
+++ b/static/myip.css
@@ -0,0 +1,37 @@
+body {
+ margin: 0;
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-family: 'Montserrat', Helvetica, Arial, sans-serif;
+ background: #0181C4;
+}
+.card {
+ background: #ffffff;
+ padding: 2.5rem 3rem;
+ border-radius: 0;
+ box-shadow: 0 18px 40px rgba(15, 23, 42, 0.6);
+ max-width: 520px;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+}
+.title {
+ font-size: 1.25rem;
+ color: #101F2D;
+ margin-bottom: 0.5rem;
+}
+.ripe-title {
+ font-size: 1.1rem;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+ color: #101F2D;
+}
+.ripe-item {
+ font-size: 0.95rem;
+ color: #101F2D;
+ margin: 0.2rem 0;
+}
\ No newline at end of file