#!/bin/sh
# ============================================================================
#  Helper privilegiado de MiVPN. Lo invoca la app con `pkexec`, autorizado por
#  /usr/share/polkit-1/actions/net.mivpn.app.policy.
#
#  Superficie deliberadamente mínima: solo `up` y `down` de UNA interfaz fija.
#  No acepta rutas ni nombres de interfaz desde la app, y del .conf solo admite
#  las claves normales de WireGuard (nada de PreUp/PostUp/...), para que un
#  fallo en el lado no privilegiado no pueda convertirse en ejecución
#  arbitraria como root.
#
#    up    lee el .conf por la entrada estándar y levanta el túnel
#    down  baja el túnel (no falla si ya estaba bajado)
#    status  imprime `up` o `down`
# ============================================================================
set -eu

IFACE=mivpn
CONF="/etc/wireguard/${IFACE}.conf"

die() { echo "mivpn-helper: $*" >&2; exit 1; }

command -v wg-quick >/dev/null 2>&1 || die "falta wg-quick (instala wireguard-tools)"

case "${1:-}" in
  up)
    umask 077
    mkdir -p /etc/wireguard
    # El .conf llega por stdin: la clave privada nunca toca un fichero
    # temporal legible por otros procesos del usuario.
    tmp="$(mktemp /etc/wireguard/.${IFACE}.XXXXXX)"
    trap 'rm -f "$tmp"' EXIT INT TERM
    cat > "$tmp"
    [ -s "$tmp" ] || die "configuración vacía"
    # Solo claves normales de WireGuard, cada una en su sección, y valores con
    # caracteres seguros. wg-quick ejecuta como root lo que vaya en PreUp,
    # PostUp, PreDown y PostDown: sin este filtro, cualquier programa del
    # usuario (o un servidor comprometido) podía hacerse root mandando un
    # PostUp. También fuera SaveConfig, Table, FwMark y cualquier otra.
    LC_ALL=C awk '
      { linea = $0
        sub(/\r$/, "", linea); sub(/^[ \t]+/, "", linea); sub(/[ \t]+$/, "", linea)
        if (linea == "" || linea ~ /^[#;]/) next
        if (linea ~ /^\[/) {
          s = tolower(linea)
          if (s == "[interface]") { seccion = "i"; interfaces++ }
          else if (s == "[peer]") { seccion = "p"; peers++ }
          else malo = 1
          next
        }
        igual = index(linea, "=")
        if (igual == 0) { malo = 1; next }
        clave = tolower(substr(linea, 1, igual - 1)); gsub(/[ \t]/, "", clave)
        valor = substr(linea, igual + 1)
        if (valor !~ /^[][A-Za-z0-9+\/=.:,%_ 	-]*$/) { malo = 1; next }
        if (seccion == "i" && clave ~ /^(privatekey|address|dns|mtu|listenport)$/) next
        if (seccion == "p" && clave ~ /^(publickey|presharedkey|endpoint|allowedips|persistentkeepalive)$/) next
        malo = 1
      }
      END { exit (malo || interfaces != 1 || peers < 1) ? 1 : 0 }
    ' "$tmp" || die "configuración no permitida"

    # Baja un túnel previo antes de reemplazar el fichero, o `wg-quick down`
    # posterior usaría la configuración nueva para deshacer la vieja.
    if ip link show "$IFACE" >/dev/null 2>&1; then
      wg-quick down "$IFACE" >/dev/null 2>&1 || true
    fi

    chmod 600 "$tmp"
    mv -f "$tmp" "$CONF"
    trap - EXIT INT TERM
    exec wg-quick up "$IFACE"
    ;;

  down)
    if ip link show "$IFACE" >/dev/null 2>&1; then
      exec wg-quick down "$IFACE"
    fi
    exit 0
    ;;

  status)
    if ip link show "$IFACE" >/dev/null 2>&1; then echo up; else echo down; fi
    ;;

  *)
    die "uso: mivpn-helper {up|down|status}"
    ;;
esac
