From 01778bde800086f9f5ebb125100e289b3d2624a1 Mon Sep 17 00:00:00 2001 From: boban Date: Sun, 21 Jun 2026 08:06:00 +0200 Subject: [PATCH] feat(wg): non-interactive setup action for the dashboard write-bridge Co-Authored-By: Claude Sonnet 4.6 --- docker/wg/clusev-wg.sh | 56 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/docker/wg/clusev-wg.sh b/docker/wg/clusev-wg.sh index 49b387a..5a975f9 100755 --- a/docker/wg/clusev-wg.sh +++ b/docker/wg/clusev-wg.sh @@ -215,6 +215,44 @@ cmd_status() { systemctl is-active "wg-quick@${WG_IF}" 2>/dev/null || true } +# Non-interactive setup for the dashboard write-bridge. Args are re-validated here (defence in +# depth). Refuses to clobber an existing wg0.conf. Does NOT enable the gate. On success prints the +# first peer's client config to stdout (for the show-once modal). Errors to stderr, non-zero on fail. +_setup_noninteractive() { + local subnet="$1" server_ip="$2" port="$3" endpoint="$4" peer1="$5" + have wg || { echo "wireguard-tools fehlt" >&2; return 1; } + [ -f "$WG_CONF" ] && { echo "WireGuard ist bereits eingerichtet" >&2; return 1; } + printf '%s' "$subnet" | grep -qE '^[0-9]{1,3}(\.[0-9]{1,3}){3}/[0-9]{1,2}$' || { echo "Ungueltiges Subnetz" >&2; return 1; } + case "$server_ip" in ''|*[!0-9.]*) echo "Ungueltige Server-IP" >&2; return 1 ;; esac + case "$port" in ''|*[!0-9]*) echo "Ungueltiger Port" >&2; return 1 ;; esac + [ "$port" -ge 1 ] && [ "$port" -le 65535 ] || { echo "Port ausserhalb 1-65535" >&2; return 1; } + case "$endpoint" in ''|*[!A-Za-z0-9.:_-]*) echo "Ungueltiger Endpoint" >&2; return 1 ;; esac + valid_name "$peer1" || { echo "Ungueltiger Peer-Name" >&2; return 1; } + subnet_collides "$subnet" && { echo "Subnetz kollidiert mit einer bestehenden Route/Adresse" >&2; return 1; } + + umask 077; mkdir -p "$WG_DIR" "$STATE_DIR" + local srv_priv srv_pub prefix + srv_priv="$(wg genkey)"; srv_pub="$(printf '%s' "$srv_priv" | wg pubkey)" + prefix="${subnet##*/}" + cat > "$WG_CONF" < "$WG_ENV" <&2; return 1; } + _peer_add "$peer1" +} + cmd_setup() { need_root setup have wg || die "wireguard-tools nicht installiert (erwartet via install.sh)." @@ -342,11 +380,27 @@ cmd_serve_request() { set-endpoint) if [ -n "$endpoint" ] && _set_endpoint "$endpoint" >/dev/null 2>&1; then ok=true; else msg='set-endpoint-failed'; fi ;; set-port) if [ -n "$port" ] && _set_port "$port" >/dev/null 2>&1; then ok=true; else msg='set-port-failed'; fi ;; set-subnet) if [ -n "$subnet" ] && _set_subnet "$subnet" >/dev/null 2>&1; then ok=true; else msg='set-subnet-failed'; fi ;; + setup) + local sip ep pn + sip="$(subnet_first_ip "$subnet" 2>/dev/null || true)" + ep="$endpoint"; [ -n "$ep" ] || ep="$(detect_endpoint_ip):${port}" + pn="$name"; [ -n "$pn" ] || pn='client-1' + if [ -n "$subnet" ] && [ -n "$port" ]; then + local tmperr; tmperr="$(mktemp 2>/dev/null || echo /tmp/wgsetup.err)" + if config="$(_setup_noninteractive "$subnet" "$sip" "$port" "$ep" "$pn" 2>"$tmperr")"; then + ok=true + else + ok=false; config=''; msg="$(tr '\n' ' ' < "$tmperr" 2>/dev/null | head -c 120)"; [ -n "$msg" ] || msg='setup-failed' + fi + rm -f "$tmperr" + else + msg='setup-bad-args' + fi ;; *) msg='unknown-action' ;; esac _write_result "$id" "$ok" "$msg" "$config" - if [ "$ok" = true ] && [ "$action" = add-peer ] && [ -n "$config" ] && have qrencode; then + if [ "$ok" = true ] && { [ "$action" = add-peer ] || [ "$action" = setup ]; } && [ -n "$config" ] && have qrencode; then local qr="${RUN_DIR}/wg-qr-${id}.svg" if printf '%s\n' "$config" | qrencode -t SVG -o "$qr" 2>/dev/null; then chown "$(stat -c %u:%g "$RUN_DIR" 2>/dev/null || echo 0:0)" "$qr" 2>/dev/null || true