#!/usr/bin/env bash
# Privileged helper for Quixure VPN (wg-quick + safe teardown).
# Installed to /usr/lib/quixure/quixure-vpn-helper — invoked via pkexec.

set -euo pipefail

QUIXURE_LIB="${QUIXURE_LIB:-/usr/lib/quixure}"
TUNNEL_IFACE="${TUNNEL_IFACE:-quixure0}"
NFT="${NFT:-/usr/sbin/nft}"

log() {
  echo "[quixure-vpn-helper] $*" >&2
}

resolve_binary() {
  local candidate
  for candidate in "$@"; do
    if [[ -n "$candidate" && -x "$candidate" ]]; then
      echo "$candidate"
      return 0
    fi
  done
  return 1
}

WG_QUICK="$(resolve_binary \
  "${QUIXURE_LIB}/wireguard/wg-quick" \
  /usr/bin/wg-quick \
  /bin/wg-quick \
  "$(command -v wg-quick 2>/dev/null || true)")" || {
  log "wg-quick not found. Install: sudo apt install wireguard-tools"
  exit 127
}

WG="$(resolve_binary \
  "${QUIXURE_LIB}/wireguard/wg" \
  /usr/bin/wg \
  /bin/wg \
  "$(command -v wg 2>/dev/null || true)")" || {
  log "wg not found. Install: sudo apt install wireguard-tools"
  exit 127
}

ALLOWED_ROOTS=(
  "/var/lib/quixure/configs"
)

add_allowed_home_configs() {
  local u home
  for u in /home/*; do
    [[ -d "$u" ]] || continue
    home="$(getent passwd "$(basename "$u")" 2>/dev/null | cut -d: -f6 || true)"
    [[ -n "$home" && -d "$home" ]] || home="$u"
    ALLOWED_ROOTS+=("${home}/.local/share/quixure/vpn-configs")
    ALLOWED_ROOTS+=("${home}/.local/share/com.quixure.vpn/vpn-configs")
  done
  if [[ -n "${SUDO_USER:-}" ]]; then
    home="$(getent passwd "$SUDO_USER" | cut -d: -f6 || true)"
    [[ -n "$home" ]] && ALLOWED_ROOTS+=("${home}/.local/share/quixure/vpn-configs")
    [[ -n "$home" ]] && ALLOWED_ROOTS+=("${home}/.local/share/com.quixure.vpn/vpn-configs")
  fi
  if [[ -n "${PKEXEC_UID:-}" ]]; then
    home="$(getent passwd "$(id -un "$PKEXEC_UID" 2>/dev/null || echo "")" 2>/dev/null | cut -d: -f6 || true)"
    [[ -n "$home" ]] && ALLOWED_ROOTS+=("${home}/.local/share/quixure/vpn-configs")
    [[ -n "$home" ]] && ALLOWED_ROOTS+=("${home}/.local/share/com.quixure.vpn/vpn-configs")
  fi
}

validate_config_path() {
  local cfg="$1"
  local real
  if [[ ! -f "$cfg" ]]; then
    log "config not found: $cfg"
    exit 1
  fi
  real="$(readlink -f "$cfg")"
  add_allowed_home_configs
  local root
  for root in "${ALLOWED_ROOTS[@]}"; do
    [[ -d "$root" ]] || continue
    case "$real" in
      "$(readlink -f "$root")"/*)
        return 0
        ;;
    esac
  done
  log "config path not allowed: $real"
  exit 1
}

iface_from_config() {
  local cfg="$1"
  basename "$cfg" .conf
}

# Remove legacy firewall rules from older builds (they blocked all traffic if left behind).
remove_legacy_firewall() {
  if [[ -x "$NFT" ]]; then
    "$NFT" delete table inet quixure_vpn 2>/dev/null || true
  fi
  if [[ -x /sbin/sysctl ]]; then
    /sbin/sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1 || true
  fi
}

cmd_cleanup() {
  remove_legacy_firewall
  if "$WG" show "$TUNNEL_IFACE" &>/dev/null; then
    log "wg-quick down $TUNNEL_IFACE (cleanup)"
    "$WG_QUICK" down "$TUNNEL_IFACE" 2>/dev/null || true
  fi
  rm -f "/etc/wireguard/${TUNNEL_IFACE}.conf"
  log "cleanup complete"
}

cmd_up() {
  local cfg="$1"
  local iface
  validate_config_path "$cfg"
  iface="$(iface_from_config "$cfg")"
  if [[ ${#iface} -gt 15 ]]; then
    log "interface name too long (${#iface} > 15): $iface"
    exit 1
  fi
  remove_legacy_firewall
  install -d /etc/wireguard
  install -m600 "$cfg" "/etc/wireguard/${iface}.conf"
  log "wg-quick up $iface"
  "$WG_QUICK" up "$iface"
}

cmd_down() {
  local cfg="$1"
  local iface
  validate_config_path "$cfg"
  iface="$(iface_from_config "$cfg")"
  remove_legacy_firewall
  log "wg-quick down $iface"
  "$WG_QUICK" down "$iface" 2>/dev/null || true
  rm -f "/etc/wireguard/${iface}.conf"
  remove_legacy_firewall
}

cmd_status() {
  local iface="$1"
  "$WG" show "$iface" 2>/dev/null | grep -q .
}

usage() {
  echo "Usage: $0 up|down|cleanup|status <config-or-iface>" >&2
  exit 1
}

[[ $# -ge 1 ]] || usage

action="$1"
target="${2:-}"

case "$action" in
  up)
    [[ -n "$target" ]] || usage
    cmd_up "$target"
    ;;
  down)
    [[ -n "$target" ]] || usage
    cmd_down "$target"
    ;;
  cleanup)
    cmd_cleanup
    ;;
  status)
    if [[ -f "$target" ]]; then
      iface="$(iface_from_config "$target")"
    else
      iface="${target:-$TUNNEL_IFACE}"
    fi
    if cmd_status "$iface"; then
      exit 0
    fi
    exit 1
    ;;
  *)
    usage
    ;;
esac
