#!/bin/sh
set -eu

if [ "$(id -u)" -ne 0 ]; then
  echo "Run this installer as root on the VPN hub VPS." >&2
  exit 1
fi

interface_name="wg-vimify"
hub_address="${VIMIFY_VPN_HUB_ADDRESS:-10.77.0.1/24}"
listen_port="${VIMIFY_VPN_LISTEN_PORT:-51820}"
case "$hub_address" in *[!0-9./]*|'') echo "VIMIFY_VPN_HUB_ADDRESS is invalid." >&2; exit 1 ;; esac
case "$hub_address" in *.*.*.*'/'*) ;; *) echo "VIMIFY_VPN_HUB_ADDRESS must be an IPv4 CIDR." >&2; exit 1 ;; esac
case "$listen_port" in *[!0-9]*|'') echo "VIMIFY_VPN_LISTEN_PORT must be numeric." >&2; exit 1 ;; esac
if [ "$listen_port" -lt 1 ] || [ "$listen_port" -gt 65535 ]; then
  echo "VIMIFY_VPN_LISTEN_PORT must be between 1 and 65535." >&2
  exit 1
fi

if ! command -v wg >/dev/null 2>&1 || ! command -v iptables >/dev/null 2>&1; then
  if ! command -v apt-get >/dev/null 2>&1; then
    echo "Install wireguard-tools, then run this installer again." >&2
    exit 1
  fi
  apt-get update
  DEBIAN_FRONTEND=noninteractive apt-get install -y wireguard-tools iptables
fi

install -d -m 0700 /etc/wireguard
private_key_file="/etc/wireguard/$interface_name.key"
if [ ! -f "$private_key_file" ]; then
  umask 077
  wg genkey > "$private_key_file"
fi
chmod 0600 "$private_key_file"
private_key="$(sed -n '1p' "$private_key_file")"
public_key="$(printf '%s' "$private_key" | wg pubkey)"

configuration_file="/etc/wireguard/$interface_name.conf"
if [ ! -f "$configuration_file" ]; then
  temporary_file="$(mktemp /etc/wireguard/.wg-vimify.XXXXXX)"
  {
    printf '[Interface]\n'
    printf 'PrivateKey = %s\n' "$private_key"
    printf 'Address = %s\n' "$hub_address"
    printf 'ListenPort = %s\n' "$listen_port"
    printf 'PostUp = iptables -I FORWARD 1 -i %%i -o %%i -j DROP\n'
    printf 'PostDown = iptables -D FORWARD -i %%i -o %%i -j DROP\n'
    printf 'SaveConfig = true\n'
  } > "$temporary_file"
  chmod 0600 "$temporary_file"
  mv -f "$temporary_file" "$configuration_file"
fi

systemctl enable --now "wg-quick@$interface_name"

# Keep peer isolation in place when a hosting panel reloads iptables. HestiaCP
# runs its custom firewall hook after every rules rebuild, so install an
# idempotent helper and register it when Hestia is present.
firewall_helper="/usr/local/sbin/vimify-vpn-firewall"
temporary_helper="$(mktemp /usr/local/sbin/.vimify-vpn-firewall.XXXXXX)"
cat > "$temporary_helper" <<'EOF'
#!/bin/sh
set -eu

interface_name="wg-vimify"
if ! ip link show "$interface_name" >/dev/null 2>&1; then
  exit 0
fi

while iptables -C FORWARD -i "$interface_name" -o "$interface_name" -j DROP >/dev/null 2>&1; do
  iptables -D FORWARD -i "$interface_name" -o "$interface_name" -j DROP
done
iptables -I FORWARD 1 -i "$interface_name" -o "$interface_name" -j DROP
EOF
chmod 0755 "$temporary_helper"
mv -f "$temporary_helper" "$firewall_helper"

hestia_root="/usr/local/hestia"
hestia_firewall="$hestia_root/data/firewall"
if [ -x "$hestia_root/bin/v-add-firewall-rule" ] && [ -d "$hestia_firewall" ]; then
  custom_firewall="$hestia_firewall/custom.sh"
  if [ ! -f "$custom_firewall" ]; then
    printf '#!/bin/sh\n' > "$custom_firewall"
  fi
  if ! grep -Fq '# VIMIFY_VPN_FIREWALL' "$custom_firewall"; then
    {
      printf '\n# VIMIFY_VPN_FIREWALL\n'
      printf '%s || true\n' "$firewall_helper"
    } >> "$custom_firewall"
  fi
  chmod 0755 "$custom_firewall"

  rules_file="$hestia_firewall/rules.conf"
  if ! grep -Eq "ACTION='ACCEPT'.*PROTOCOL='UDP'.*PORT='$listen_port'.*IP='0.0.0.0/0'" "$rules_file" 2>/dev/null; then
    "$hestia_root/bin/v-add-firewall-rule" ACCEPT 0.0.0.0/0 "$listen_port" UDP VIMIFY-VPN
  fi
fi

"$firewall_helper"

printf 'Vimify VPN hub is active on UDP %s.\n' "$listen_port"
if [ -x "$hestia_root/bin/v-add-firewall-rule" ]; then
  printf 'HestiaCP firewall access is configured for UDP %s.\n' "$listen_port"
else
  printf 'Open that UDP port in the VPS firewall.\n'
fi
printf 'Hub public key:\n%s\n' "$public_key"
printf 'Hub tunnel address: %s\n' "$hub_address"
