#!/usr/bin/env sh

HELP="
GoodAccess connections manager. Usage:

-s --setup - set up new GoodAccess gateway connection
-r --run [conn_name] - establish connection to GoodAccess gateway
-l --list - list installed GoodAccess gateway connections
-d --delete [conn_name] - remove GoodAccess gateway connection from system

"

OVPN_PATH=$(command -v openvpn)
OCL_PATH=/etc/openvpn/client/ga
GW_LIST_PATH="/tmp/gw_list"

# Default values. The real ones are set in this scipt later.
GWU_FN=common_gw
GWU_PATH="${OCL_PATH}/${GWU_FN}.creds"

introduction() {
  echo "$HELP"
  if [ -n "$1" ] && [ "$1" != "-h" ] && [ "$1" != "--help" ]; then
    printf "Do you want to continue? [y/N] "
    read -r RESP
    if [ "$RESP" != "y" ] && [ "$RESP" != "Y" ]; then
      exit 0
    fi
  fi
}

initial_cheks() {
  # Is user root?"
  if [ "$(whoami)" != "root" ]; then
    echo You must be root or use sudo to run this script.
    exit 1
  fi

  # Is openvpn installed?
  if [ -z "$OVPN_PATH" ]; then
    printf "\nOpenVPN is not installed in your system. Do you want to install it now? [y/N] "
    read -r RESP
    if [ "$RESP" = "y" ] || [ "$RESP" = "Y" ]; then
      install_ovpn
    else
      printf "\nOpenVPN is mandatory to connect to GoodAccess gateway. Exiting.\n\n"
      exit 1
    fi
  fi

  # Path to our configs
  mkdir -p "$OCL_PATH"
}

install_ovpn() {
  # This is called from initial_chesks
  # get installator name
  INST_U=$(command -v apt) || INST_U=$(command -v yum)
  if [ -z "$INST_U" ]; then
    printf "\nThere isn't any known installation program present (apt, yum).\n"
    printf "Please install OpenVPN by yourself and run this script again.\n\n"
    exit 1
  fi
  CMD_NAME=$(basename "$INST_U")
  case "$CMD_NAME" in
  "apt")
    apt update
    apt install openvpn
    ;;
  "yum")
    yum update -y
    yum install epel-release -y
    yum update -y
    yum install openvpn
    ;;
  *)
    echo "Installation of OpenVPN was unsuccessfull. Exiting."
    exit 2
    ;;
  esac
  OVPN_PATH=$(command -v openvpn)
  printf "\nInstallation of OpenVPN successfully completed.\n\n"
}

create_creds_file() {
  # Ask user for username and password and save them to creds file
  # used in ovpn configuration file.
  # Ask in loop - give a chance to fix typo
  OK="NO"
  until [ "$OK" = "YES" ]; do
    printf "\nEnter your VPN credentials:\n\n"
    printf "username: "
    read -r UNAME
    printf "password: "
    read -r UPASS
    printf "\nAre provided credentials correct? [y/N] "
    read -r RESP
    if [ "$RESP" = "y" ] || [ "$RESP" = "Y" ]; then
      # GWU_FN value comes from create_gw()
      GWU_PATH="${OCL_PATH}/${GWU_FN}.creds"
      echo "$UNAME" >"$GWU_PATH"
      echo "$UPASS" >>"$GWU_PATH"
      chmod 0400 "$GWU_PATH"
      OK="YES"
    fi
  done
}

create_gw() {
  # Need params CONF_INPUT - config file downloaded form GoodAccess.
  OK="NO"
  until [ "$OK" = "YES" ]; do
    printf "\nName your connection [without spaces]: "
    read -r RESP
    GWU_FN=$(echo "$RESP" | tr "[:blank:]" "_")
    printf "\nAre you OK with name \"%s\"? [y/N] " "$GWU_FN"
    read -r RESP
    if [ "$RESP" = "y" ] || [ "$RESP" = "Y" ]; then
      OK="YES"
    fi
  done
  create_creds_file
  GWC_PATH="${OCL_PATH}/${GWU_FN}.ovpn"
  # Put ovpn config file from user to correct location
  cp "$CONF_INPUT" "$GWC_PATH"
  # Add path to credentials file into ovpn config auth-user-pass parameter
  sed -i -e "s|^auth-user-pass.*$|auth-user-pass ${GWU_PATH}|g" "$GWC_PATH"
  printf "\nConfiguration of GoodAccess gateway connection %s has been finished. Start it by running command:\n\n" "${GWU_FN}"
  printf "      %s -r %s \n\n" "$0" "${GWU_FN}"
}

get_count_of_gws() {
  GW_COUNT=$(find "$OCL_PATH" -name "*.ovpn" | wc -l)
}

mk_gw_list() {
  GW_LIST=$(ls "$OCL_PATH"/*ovpn) 2>/dev/null
  if [ -z "$GW_LIST" ]; then
    printf "\n\nThere is no GoodAccess gateway connection installed.\n"
    printf "Install some first by command:\n\n"
    printf "    %s -s downloaded_openvpn_confg_file.ovpn\n\n" "$0"
    exit 1
  fi
  # Get list of installed gateways and save it to /tmp/gw_list file
  truncate --size=0 "$GW_LIST_PATH"
  NUM=0
  for GW in $GW_LIST; do
    NUM=$((NUM + 1))
    GW_NAME=$(echo "$GW" | rev | cut -f2 -d"." | cut -f1 -d"/" | rev)
    printf "%3s) %s\n" "$NUM" "$GW_NAME" >>"$GW_LIST_PATH"
  done
}

run_gw() {
  # If GW name parameter is not provided, get list of names of existing GWs.
  if [ -n "$2" ]; then
    GW_NAME="$2"
    if [ ! -e "${OCL_PATH}/$GW_NAME.ovpn" ]; then
      printf "\nError: Provided GoodAccess gateway connection name doesn't exist. Exiting.\n\n"
      printf "You can list GoodAccess gateways connections using --list parameter.\n\n"
      exit 1
    fi
  else
    mk_gw_list
    LINES=$(cat "$GW_LIST_PATH" | wc -l)
    # If one line we don't need to list them to user and we can run the one GW automatically.
    # Warning: Do not put quotation marks around $LINES - it must be a nubmer, not a string.
    if [ $LINES -gt 1 ]; then
      printf "\nThere are several GoodAccess gateways.\n\n"
      cat "$GW_LIST_PATH"
      printf "\n Which one do you want to connect to? [num]: "
      read -r SELECTED
      LINE=$(grep "^\s*${SELECTED}) " "$GW_LIST_PATH")
      if [ -z "$LINE" ]; then
        printf "\n\nThere is no such connection. Exiting.\n\n"
        exit 1
      fi
      # cut number from beginnig of the line
      GW_NAME=$(echo "$LINE" | cut -f2 -d")" | cut -f2 -d" ")
    fi
  fi
  "$OVPN_PATH" --config "${OCL_PATH}/$GW_NAME.ovpn"
}

delete_gw() {
  if [ -n "$2" ]; then
    GW_TO_DELETE="$2"
  else
    mk_gw_list
    printf "\nThere are several GoodAccess gateways.\n\n"
    cat "$GW_LIST_PATH"
    printf "\n Which one do you want to delete? [num]: "
    read -r SELECTED
    LINE=$(grep "^\s*${SELECTED}) " "$GW_LIST_PATH")
    if [ -z "$LINE" ]; then
      printf "\n\nThere is no such connection. Exiting.\n\n"
      exit 1
    fi
    # cut number from beginnig of the line
    GW_TO_DELETE=$(echo "$LINE" | cut -f2 -d")" | cut -f2 -d" ")
  fi
  if [ ! -e "$OCL_PATH/$GW_TO_DELETE.ovpn" ]; then
    printf "\n\n Gateway connection name \"%s.ovpn\" doesn't exist.\n\n" "$GW_TO_DELETE"
    printf "If you don't know the name of the connection exactly, run this script without any name:\n\n"
    printf "%s -d \n\n" "$0"
    printf "You'll be provided with list of installed GoodAccess connections which you can choose from.\n\n"
    exit 1
  fi
  printf "\n\nAre you sure you want to delete this gateway connection: \"%s\"? [y/N] " "$GW_TO_DELETE"
  read -r RESP
  if [ "$RESP" = "y" ] || [ "$RESP" = "Y" ]; then
    rm "$OCL_PATH"/"$GW_TO_DELETE".*
    printf "\nGateway connection %s deleted.\n\n" "$GW_TO_DELETE"
  else
    printf "\nNothing deleted. Exiting.\n\n"
  fi
}

debug() {
  while echo ""; do
    printf "action: "
    read -r ACTION
    if [ -z "$ACTION" ]; then exit 99; fi
    $ACTION
  done
}

# ====================================================== run part ======

initial_cheks

case $1 in

"-h" | "--help")
  introduction "$@"
  exit 0
  ;;

"-s" | "--setup")
  if [ -z "$2" ]; then
    printf "\nTo setup new GoodAccess gateway connection, you have to provide OpenVPN configuration file name as a second parameter.\n\n"
    printf "Example:\n\n"
    printf "%s %s confg_file.ovpn\n\n" "$0" "$1"
    exit 1
  fi
  CONF_INPUT="$2"
  create_gw "$@"
  ;;

"-r" | "--run")
  run_gw "$@"
  ;;

"-l" | "--list")
  mk_gw_list
  printf "\nList of existing GoodAccess gateway connections:\n\n"
  cat "$GW_LIST_PATH"
  echo
  ;;

"-d" | "--delete")
  delete_gw "$@"
  ;;

"-D" | "--debug")
  debug
  ;;
*)
  # Default run single GW else print help and exit.
  get_count_of_gws
  if [ $GW_COUNT -eq 1 ]; then
    run_gw
  else
    echo "$HELP"
    exit 1
  fi
  ;;

esac
