fix graphics

This commit is contained in:
Francesco Picone
2025-12-29 12:44:48 +01:00
parent fad3035b45
commit c74867f22a
2 changed files with 216 additions and 60 deletions

View File

@@ -1,42 +1,103 @@
import os import os
import requests import requests
from datetime import datetime
CF_API_TOKEN = os.getenv("CF_API_TOKEN") # ----------------------------
ZONE = os.getenv("CF_ZONE") # Config da .env
SUBDOMAINS = os.getenv("CF_SUBDOMAINS").split(",") # ----------------------------
CF_API_TOKEN = os.getenv("CF_UI_API_TOKEN")
CF_ZONE = os.getenv("CF_ZONE")
CF_SUBDOMAINS = os.getenv("CF_UI_SUBDOMAINS", "").split(",")
PUBLIC_IP_API = os.getenv("PUBLIC_IP_API", "https://api.ipify.org") # opzionale
HEADERS = { HEADERS = {
"Authorization": f"Bearer {CF_API_TOKEN}", "Authorization": f"Bearer {CF_API_TOKEN}",
"Content-Type": "application/json" "Content-Type": "application/json"
} }
# ----------------------------
# Funzioni
# ----------------------------
def get_public_ip(): def get_public_ip():
return requests.get("https://api.ipify.org", timeout=5).text.strip() """Recupera l'IP pubblico"""
try:
ip = requests.get(PUBLIC_IP_API, timeout=5).text.strip()
return ip
except Exception:
return "N/A"
def get_dns_status(): def get_zone_id():
ip_pubblico = get_public_ip() """Recupera l'ID della zona Cloudflare"""
out = [] try:
resp = requests.get(
zone = requests.get(
"https://api.cloudflare.com/client/v4/zones", "https://api.cloudflare.com/client/v4/zones",
headers=HEADERS, headers=HEADERS,
params={"name": ZONE} params={"name": CF_ZONE}
).json()["result"][0] ).json()
if resp["success"] and resp["result"]:
return resp["result"][0]["id"]
else:
raise Exception(f"Zona '{CF_ZONE}' non trovata o errore API.")
except Exception as e:
print(f"[ERROR] get_zone_id: {e}")
return None
for sub in SUBDOMAINS: def get_dns_records():
fqdn = f"{sub}.{ZONE}" """Recupera i record DNS dei sottodomini"""
dns = requests.get( zone_id = get_zone_id()
f"https://api.cloudflare.com/client/v4/zones/{zone['id']}/dns_records", if not zone_id:
return []
public_ip = get_public_ip()
records = []
for sub in CF_SUBDOMAINS:
fqdn = f"{sub}.{CF_ZONE}"
try:
resp = requests.get(
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records",
headers=HEADERS, headers=HEADERS,
params={"name": fqdn} params={"name": fqdn}
).json()["result"][0] ).json()
out.append({ if not resp["success"] or not resp["result"]:
# Record non trovato
records.append({
"name": fqdn,
"dns_ip": "N/A",
"public_ip": public_ip,
"proxied": False,
"status": "MISSING",
"last_updated": datetime.utcnow().isoformat()
})
continue
dns = resp["result"][0]
records.append({
"name": fqdn, "name": fqdn,
"dns_ip": dns["content"], "dns_ip": dns["content"],
"public_ip": ip_pubblico, "public_ip": public_ip,
"proxied": dns["proxied"], "proxied": dns["proxied"],
"status": "OK" if dns["content"] == ip_pubblico else "MISMATCH" "status": "OK" if dns["content"] == public_ip else "MISMATCH",
"last_updated": dns.get("modified_on", datetime.utcnow().isoformat())
}) })
return out except Exception as e:
print(f"[ERROR] get_dns_records ({fqdn}): {e}")
records.append({
"name": fqdn,
"dns_ip": "ERROR",
"public_ip": public_ip,
"proxied": False,
"status": "ERROR",
"last_updated": datetime.utcnow().isoformat()
})
return records
# ----------------------------
# Test rapido
# ----------------------------
if __name__ == "__main__":
from pprint import pprint
pprint(get_dns_records())

View File

@@ -1,42 +1,137 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="it">
<head> <head>
<meta charset="utf-8"> <meta charset="UTF-8">
<title>Cloudflare DDNS Status</title> <title>Cloudflare DDNS Status</title>
<meta http-equiv="refresh" content="{{ 60 }}"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<style> <style>
body { background:#0f1115; color:#eee; font-family:sans-serif; padding:20px } /* Stile generale */
table { width:100%; border-collapse:collapse } body {
th, td { padding:10px; border-bottom:1px solid #333 } font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
.ok { color:#4caf50 } background: #121212;
.bad { color:#ff5252 } color: #e0e0e0;
</style> margin: 0;
padding: 0;
}
header {
background: #1f1f1f;
padding: 20px;
text-align: center;
font-size: 1.7em;
font-weight: bold;
color: #00bcd4;
box-shadow: 0 2px 5px rgba(0,0,0,0.5);
}
main {
padding: 20px;
max-width: 1000px;
margin: auto;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0 10px; /* Spazi tra le righe */
}
th {
background: #1f1f1f;
color: #00bcd4;
font-weight: bold;
text-transform: uppercase;
font-size: 0.9em;
text-align: center;
padding: 12px;
border-radius: 8px 8px 0 0;
}
td {
background: #1a1a1a;
text-align: center;
padding: 12px;
color: #e0e0e0;
border-radius: 8px;
transition: all 0.3s ease;
}
tr:hover td {
background: #272727;
transform: scale(1.02);
}
.badge {
display: inline-block;
padding: 5px 12px;
border-radius: 20px;
font-weight: bold;
font-size: 0.85em;
}
.ok {
background: linear-gradient(45deg, #4caf50, #81c784);
color: #fff;
}
.bad {
background: linear-gradient(45deg, #ff5252, #ff8a65);
color: #fff;
}
.time {
color: #9e9e9e;
font-size: 0.85em;
}
footer {
text-align: center;
padding: 15px;
font-size: 0.85em;
color: #777;
}
</style>
</head> </head>
<body> <body>
<h2>Cloudflare DDNS Stato DNS</h2> <header>Cloudflare DDNS Stato DNS</header>
<table> <main>
<tr> <table>
<thead>
<tr>
<th>Record</th> <th>Record</th>
<th>DNS IP</th> <th>DNS IP</th>
<th>IP Pubblico</th> <th>IP Pubblico</th>
<th>Proxy</th> <th>Proxy</th>
<th>Stato</th> <th>Stato</th>
</tr> <th>Ultimo aggiornamento</th>
</tr>
</thead>
<tbody>
{% for r in records %}
<tr>
<td>{{ r.name }}</td>
<td>{{ r.dns_ip }}</td>
<td>{{ r.public_ip }}</td>
<td>{{ "ON" if r.proxied else "OFF" }}</td>
<td><span class="badge {{ 'ok' if r.status == 'OK' else 'bad' }}">{{ r.status }}</span></td>
<td class="time" data-timestamp="{{ r.last_updated }}">{{ r.last_updated_human }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
{% for r in records %} <footer>
<tr> Visualizzazione aggiornata ogni 60 secondi
<td align="center">{{ r.name }}</td> </footer>
<td align="center">{{ r.dns_ip }}</td>
<td align="center">{{ r.public_ip }}</td> <script>
<td align="center">{{ "ON" if r.proxied else "OFF" }}</td> function timeAgo(date) {
<td align="center" class="{{ 'ok' if r.status == 'OK' else 'bad' }}"> const seconds = Math.floor((new Date() - new Date(date)) / 1000);
{{ r.status }} let interval = Math.floor(seconds / 86400);
</td> if (interval >= 1) return interval + " giorni fa";
</tr> interval = Math.floor(seconds / 3600);
{% endfor %} if (interval >= 1) return interval + " ore fa";
</table> interval = Math.floor(seconds / 60);
if (interval >= 1) return interval + " minuti fa";
return "pochi secondi fa";
}
document.querySelectorAll('.time').forEach(td => {
td.textContent = timeAgo(td.dataset.timestamp);
});
</script>
</body> </body>
</html> </html>