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