feat: route commands for peer clients (Linux/Windows) + footer signature

- scripts page: new card with Linux/macOS and Windows route commands
  per peer that has advertised_routes, with OS tab switcher and copy buttons
- Made by Galyaviev moved from sidebar to bottom-center page footer on all pages
- page-footer style: Dancing Script 20px, clickable mailto:ruslan@ipcom.su

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 10:54:57 +03:00
parent 530a260849
commit 3bfb650b80
4 changed files with 107 additions and 12 deletions
+31 -2
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import base64
import io
import ipaddress
import os
import secrets
import sqlite3
@@ -658,6 +659,15 @@ def peer_rename(peer_id: int):
return ("", 204)
def _cidr_parts(cidr: str):
"""Return (network_address, netmask) for a CIDR string."""
try:
net = ipaddress.ip_network(cidr.strip(), strict=False)
return str(net.network_address), str(net.netmask)
except Exception:
return cidr.strip(), ""
@app.route("/scripts")
def scripts():
commands = {
@@ -666,14 +676,33 @@ def scripts():
"apply_wg": "wg syncconf wg0 <(wg-quick strip /etc/wireguard/wg0.conf)",
}
paths = [
"sudo", "/usr/local/sbin/wg-peerctl",
"/usr/local/sbin/wg-peerctl",
"/etc/wireguard/wg0.conf",
"/etc/wireguard/wg-meta.env",
"/var/log/wireguard-server-install.log",
"/var/log/wireguard-client-install.log",
"/var/log/wireguard-peerctl.log",
]
return render_template("scripts.html", commands=commands, paths=paths)
route_peers = []
with db_conn() as conn:
cur = conn.cursor()
cur.execute(
"SELECT name, client_address, advertised_routes FROM peers "
"WHERE advertised_routes IS NOT NULL AND advertised_routes != '' ORDER BY name"
)
for row in cur.fetchall():
wg_ip = (row["client_address"] or "").split("/")[0]
routes = []
for r in (row["advertised_routes"] or "").split(","):
r = r.strip()
if r:
net, mask = _cidr_parts(r)
routes.append({"cidr": r, "net": net, "mask": mask})
if wg_ip and routes:
route_peers.append({"name": row["name"], "wg_ip": wg_ip, "routes": routes})
return render_template("scripts.html", commands=commands, paths=paths, route_peers=route_peers)
if __name__ == "__main__":