Complete Python/NiceGUI rewrite of the Wirezone (Elixir/Phoenix) VPN management platform. All 10 implementation phases delivered. Core stack: - NiceGUI reactive UI with SQLModel ORM on PostgreSQL (asyncpg) - Alembic migrations, Valkey/Redis cache, pydantic-settings config - WireGuard management via subprocess (wg/ip/nft CLIs) - 164 tests passing, 35% code coverage Features: - User/device/rule CRUD with admin and unprivileged roles - Full device config form with per-device WG overrides - WireGuard client config generation with QR codes - REST API (v0) with Bearer token auth for all resources - TOTP MFA with QR registration and challenge flow - OIDC SSO with authlib (provider registry, auto-create users) - Magic link passwordless sign-in via email - SAML SP-initiated SSO with IdP metadata parsing - WebAuthn/FIDO2 security key registration - nftables firewall with per-user chains and masquerade - Background tasks: WG stats polling, VPN session expiry, OIDC token refresh, WAN connectivity checks - Startup reconciliation (DB ↔ WireGuard state sync) - In-memory notification system with header badge - Admin UI: users, devices, rules, settings (3 tabs), diagnostics - Loguru logging with optional timestamped file output Deployment: - Multi-stage Dockerfile (python:3.13-slim) - Docker Compose prod stack (bridge networking, NET_ADMIN, nftables) - Forgejo CI: tests → semantic versioning → Docker registry push - Health endpoint at /api/health
54 lines
1.9 KiB
Python
54 lines
1.9 KiB
Python
"""Build WireGuard client configuration files."""
|
|
|
|
from wiregui.config import get_settings
|
|
from wiregui.models.device import Device
|
|
|
|
|
|
def build_client_config(
|
|
device: Device,
|
|
private_key: str,
|
|
server_public_key: str,
|
|
) -> str:
|
|
"""Build a WireGuard [Interface]+[Peer] config string for a device."""
|
|
settings = get_settings()
|
|
|
|
# Resolve per-device or default values
|
|
dns = device.dns if not device.use_default_dns else settings.wg_dns
|
|
endpoint_host = device.endpoint if not device.use_default_endpoint else settings.wg_endpoint_host
|
|
mtu = device.mtu if not device.use_default_mtu else settings.wg_mtu
|
|
keepalive = device.persistent_keepalive if not device.use_default_persistent_keepalive else settings.wg_persistent_keepalive
|
|
allowed_ips = device.allowed_ips if not device.use_default_allowed_ips else settings.wg_allowed_ips
|
|
|
|
# Build address list
|
|
addresses = []
|
|
if device.ipv4:
|
|
addresses.append(f"{device.ipv4}/32")
|
|
if device.ipv6:
|
|
addresses.append(f"{device.ipv6}/128")
|
|
|
|
# Build endpoint
|
|
endpoint_port = settings.wg_endpoint_port
|
|
endpoint = f"{endpoint_host}:{endpoint_port}"
|
|
|
|
lines = ["[Interface]", f"PrivateKey = {private_key}"]
|
|
if addresses:
|
|
lines.append(f"Address = {', '.join(addresses)}")
|
|
if dns:
|
|
dns_str = dns if isinstance(dns, str) else ", ".join(dns)
|
|
lines.append(f"DNS = {dns_str}")
|
|
if mtu:
|
|
lines.append(f"MTU = {mtu}")
|
|
|
|
lines.append("")
|
|
lines.append("[Peer]")
|
|
lines.append(f"PublicKey = {server_public_key}")
|
|
if device.preshared_key:
|
|
lines.append(f"PresharedKey = {device.preshared_key}")
|
|
if allowed_ips:
|
|
ips_str = allowed_ips if isinstance(allowed_ips, str) else ", ".join(allowed_ips)
|
|
lines.append(f"AllowedIPs = {ips_str}")
|
|
lines.append(f"Endpoint = {endpoint}")
|
|
if keepalive:
|
|
lines.append(f"PersistentKeepalive = {keepalive}")
|
|
|
|
return "\n".join(lines) + "\n"
|