diff --git a/gui/app.py b/gui/app.py index d8f840f..bdde0f0 100644 --- a/gui/app.py +++ b/gui/app.py @@ -4,6 +4,7 @@ import io import os import sqlite3 import subprocess +import time from datetime import datetime import qrcode @@ -38,9 +39,13 @@ def ensure_schema(): public_key TEXT UNIQUE NOT NULL, client_address TEXT, advertised_routes TEXT, + client_conf TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); """) + cols = {row[1] for row in cur.execute("PRAGMA table_info(peers)").fetchall()} + if "client_conf" not in cols: + cur.execute("ALTER TABLE peers ADD COLUMN client_conf TEXT") conn.commit() @@ -83,15 +88,18 @@ def wg_dump(): parts = line.split("\t") if len(parts) < 8: continue + latest_ts = 0 latest = "never" if parts[5].isdigit() and int(parts[5]) > 0: - latest = datetime.utcfromtimestamp(int(parts[5])).strftime("%Y-%m-%d %H:%M:%S UTC") + latest_ts = int(parts[5]) + latest = datetime.utcfromtimestamp(latest_ts).strftime("%Y-%m-%d %H:%M:%S UTC") peers.append( { "public_key": parts[0], "endpoint": parts[2] or "-", "allowed_ips": parts[3], "latest_handshake": latest, + "latest_handshake_ts": latest_ts, "rx_bytes": int(parts[6] or 0), "tx_bytes": int(parts[7] or 0), } @@ -160,11 +168,15 @@ def index(): items = [] seen = set() + now = int(time.time()) for row in db_peers: rt = runtime.get(row["public_key"], {}) + ts = int(rt.get("latest_handshake_ts", 0) or 0) + is_online = ts > 0 and (now - ts) <= 180 seen.add(row["public_key"]) items.append( { + "id": row["id"], "name": row["name"], "public_key": row["public_key"], "client_address": row.get("client_address") or "-", @@ -174,15 +186,18 @@ def index(): "latest_handshake": rt.get("latest_handshake", "offline"), "rx": bytes_h(rt.get("rx_bytes", 0)), "tx": bytes_h(rt.get("tx_bytes", 0)), - "status": "online" if rt else "offline", + "status": "online" if is_online else "offline", } ) for pk, rt in runtime.items(): if pk in seen: continue + ts = int(rt.get("latest_handshake_ts", 0) or 0) + is_online = ts > 0 and (now - ts) <= 180 items.append( { + "id": None, "name": "(external)", "public_key": pk, "client_address": rt.get("allowed_ips", "-").split(",", 1)[0], @@ -192,7 +207,7 @@ def index(): "latest_handshake": rt.get("latest_handshake", "offline"), "rx": bytes_h(rt.get("rx_bytes", 0)), "tx": bytes_h(rt.get("tx_bytes", 0)), - "status": "online", + "status": "online" if is_online else "offline", } ) @@ -267,13 +282,13 @@ def new_peer(): with db_conn() as conn: cur = conn.cursor() cur.execute( - "UPDATE peers SET name=?, client_address=?, advertised_routes=? WHERE public_key=?", - (name, client_addr, routes, client_pub), + "UPDATE peers SET name=?, client_address=?, advertised_routes=?, client_conf=? WHERE public_key=?", + (name, client_addr, routes, client_conf, client_pub), ) if cur.rowcount == 0: cur.execute( - "INSERT INTO peers(name, public_key, client_address, advertised_routes) VALUES (?,?,?,?)", - (name, client_pub, client_addr, routes), + "INSERT INTO peers(name, public_key, client_address, advertised_routes, client_conf) VALUES (?,?,?,?,?)", + (name, client_pub, client_addr, routes, client_conf), ) conn.commit() @@ -286,6 +301,32 @@ def new_peer(): ) +@app.route("/peers/") +def peer_view(peer_id: int): + with db_conn() as conn: + cur = conn.cursor() + cur.execute("SELECT * FROM peers WHERE id = ?", (peer_id,)) + row = cur.fetchone() + if not row: + flash("Клиент не найден", "error") + return redirect(url_for("index")) + item = dict(row) + + conf = item.get("client_conf") or "" + if not conf: + flash("Для этого клиента не найден сохраненный конфиг", "error") + return redirect(url_for("index")) + + qr_b64 = to_png_b64(conf) + return render_template( + "peer_created.html", + name=item.get("name", "peer"), + client_conf=conf, + qr_b64=qr_b64, + public_key=item.get("public_key", ""), + ) + + @app.route("/scripts") def scripts(): commands = { diff --git a/gui/templates/index.html b/gui/templates/index.html index 795f099..995ce0c 100644 --- a/gui/templates/index.html +++ b/gui/templates/index.html @@ -5,7 +5,7 @@ - + @@ -21,6 +21,13 @@ + {% endfor %}
ИмяСтатусIPРоутыAllowedIPsEndpointHandshakeRXTXPubKeyИмяСтатусIPРоутыAllowedIPsEndpointHandshakeRXTXPubKeyДействие
{{ p.rx }} {{ p.tx }} {{ p.public_key }} + {% if p.id %} + QR/Config + {% else %} + - + {% endif %} +