#!/usr/bin/env bash
set -euo pipefail

SOCKS5_PORT="${SOCKS5_PORT:-33210}"
SOCKS5_USER="${SOCKS5_USER:-}"
SOCKS5_PASSWORD="${SOCKS5_PASSWORD:-}"
SSH_PORT="${SSH_PORT:-}"

APP_TAG="app_install"

log_info() { logger -t "${APP_TAG}" -p user.info "$*"; }
log_error() { logger -t "${APP_TAG}" -p user.err "$*"; }

validate_env() {
  if [ -z "${SOCKS5_USER}" ] || [ -z "${SOCKS5_PASSWORD}" ]; then
    log_error "SOCKS5_USER and SOCKS5_PASSWORD must be provided"
    exit 1
  fi
}

require_root() {
  if [ "${EUID}" -ne 0 ]; then
    log_error "Must run as root"
    exit 1
  fi
}

ensure_ubuntu_24_04() {
  . /etc/os-release || true
  if [ "${ID:-}" != "ubuntu" ]; then
    log_error "Ubuntu required; current: ${ID:-unknown}"
    exit 1
  fi
  if [ "${VERSION_ID:-}" != "24.04" ]; then
    log_error "Ubuntu 24.04 required; current: ${VERSION_ID:-unknown}"
    exit 1
  fi
}

install_packages() {
  export DEBIAN_FRONTEND=noninteractive
  log_info "Installing packages"
  apt-get update -y
  apt-get install -y dante-server libpam-pwdfile
  log_info "Packages installed"
}

configure_pam_sockd() {
  log_info "Configuring PAM for sockd"
  cat >/etc/pam.d/sockd <<'EOF'
auth required pam_pwdfile.so pwdfile /etc/danted.passwd
account required pam_permit.so
EOF
  log_info "PAM configuration completed"
}

configure_default_sockd() {
  log_info "Configuring /etc/default/sockd"
  cat >/etc/default/sockd <<'EOF'
# Default Config for sockd
# -n :: not tcp-keep alive
Start_Process=1
Sockd_Opts="-n"
EOF
  log_info "Default sockd configuration completed"
}

discover_ips() {
  mapfile -t IPV4S < <(ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1)
  mapfile -t IPV6S < <(ip -o -6 addr show scope global | awk '{print $4}' | cut -d/ -f1)
}

generate_danted_conf() {
  discover_ips
  {
    echo "# Generate by sockd.info"
    echo "external.rotation: same-same"
    for ip in "${IPV4S[@]}"; do
      echo "# Generate interface ${ip}"
      echo "internal: ${ip}  port = ${SOCKS5_PORT}"
      echo "external: ${ip}"
      echo
    done
    for ip in "${IPV6S[@]}"; do
      echo "# Generate interface ${ip}"
      echo "internal: ${ip}  port = ${SOCKS5_PORT}"
      echo "external: ${ip}"
      echo
    done
    echo "clientmethod: none"
    echo "socksmethod: pam.username"
    echo
    echo "user.privileged: root"
    echo "user.unprivileged: nobody"
    echo
    # echo "logoutput: /var/log/sockd.log"
    echo "client pass {"
    echo "    from: 0/0  to: 0/0"
    echo "    log: connect disconnect error"
    echo "}"
    echo "socks pass {"
    echo "    from: 0/0 to: 0/0"
    echo "    command: bind connect udpassociate"
    echo "    log: connect disconnect error"
    echo "}"
    echo "socks pass {"
    echo "       from: 0.0.0.0/0 to: 0.0.0.0/0"
    echo "       command: bindreply udpreply"
    echo "       log: error"
    echo "}"
  } >/etc/danted.conf
  log_info "Generated /etc/danted.conf"
}

ensure_pam_passwd() {
  if [ -z "${SOCKS5_USER}" ] || [ -z "${SOCKS5_PASSWORD}" ]; then
    log_error "Environment variables SOCKS5_USER and SOCKS5_PASSWORD are required"
    exit 1
  fi
  SALT="$(openssl rand -hex 8)"
  HASH="$(openssl passwd -1 -salt "${SALT}" "${SOCKS5_PASSWORD}")"
  printf "%s:%s\n" "${SOCKS5_USER}" "${HASH}" >/etc/danted.passwd
  chmod 600 /etc/danted.passwd
  log_info "Generated /etc/danted.passwd"
}

update_ssh_port() {
  if [ -n "${SSH_PORT}" ]; then
    if grep -Eq '^\s*#?\s*Port\s+' /etc/ssh/sshd_config; then
      sed -E -i "s/^\s*#?\s*Port\s+.*/Port ${SSH_PORT}/" /etc/ssh/sshd_config
    else
      printf "\nPort %s\n" "${SSH_PORT}" >>/etc/ssh/sshd_config
    fi
    systemctl restart ssh || true
    log_info "Updated SSH port to ${SSH_PORT}"
  fi
}

restart_danted() {
  log_info "Enabling danted service"
  systemctl enable danted || true
  log_info "Restarting danted service"
  systemctl restart danted
}

main() {
  log_info "Starting installation"
  require_root
  validate_env
  ensure_ubuntu_24_04
  install_packages
  configure_pam_sockd
  configure_default_sockd
  generate_danted_conf
  ensure_pam_passwd
  update_ssh_port
  restart_danted
  log_info "Installation and configuration completed. Port: ${SOCKS5_PORT}"
}

main "$@"

