#!/usr/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR

. /etc/os-release

VPROTECT_DIR='/opt/vprotect/server'

QUARKUS_PROPERTIES_FILE='quarkus.properties'

MYSQL_CONFIG_FILE='/etc/my.cnf'
if [[ "$ID" == "debian" || "$ID_LIKE" == *"debian"* ]]
then
    MYSQL_CONFIG_FILE="/etc/mysql/mariadb.conf.d/99-vprotect.cnf"
    touch "$MYSQL_CONFIG_FILE"
fi

MYSQL_ROOT_PASSWORD=''
MYSQL_DB_NAME='vprotect'
MYSQL_USER_NAME='vprotect'
MYSQL_VERSION=$(echo "$(mysql --version)" | awk '{print $5}' | awk -F'-' '{print $1}')
MYSQL_ROOT_PASSWORD_LENGTH=80
MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE=''
MYSQL_BASE_MIGRATION_PATH="$VPROTECT_DIR/base_migration.sql"

DB_SERVICE='mariadb'

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

ECHO () {
echo -e "\e[92m[$1]\e[0m"
}

ERROR () {
if [ $1 = 0 ]
 then
  echo "ok"
 else
  if [ $2 = 0 ]
   then
    echo -e "$1 [${YELLOW}WARNING${NC}]"
   else
    echo -e "$1 [${RED}ERROR${NC}]"
    echo The configuration process was interrupted.
    exit
   fi
fi
}

SUDO(){
  ECHO "Configuring sudo"
  grep LIBGUESTFS_BACKEND /etc/sudoers &>/dev/null || sed -Ei 's/(.*env_keep.*LC_ALL)/\1 LIBGUESTFS_BACKEND/' /etc/sudoers
  ERROR $? 1
}

FILE_ENDS_WITH_NEWLINE() {
	[[ $(tail -c1 "$1" | wc -l) -gt 0 ]]
}

ENSURE_PASSWORD() {
    stty -echo
	printf "Type password again: "
	IFS= read -rs pass; echo
	decoded_password=$(printf '%s' "$pass" | base64 -d 2>/dev/null)

	if [ "${decoded_password:0:8}" == "[BASE64]" ]; then
    pass="${decoded_password:8}"
	else
		pass=$(printf '%s' "$pass")
	fi

	stty echo
	if [[ "$MYSQL_ROOT_PASSWORD" != "$pass" ]]; then
		echo "Not the same password!"
		return 1;
	else
		MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE=$(echo $MYSQL_ROOT_PASSWORD | sed -e 's/\\/\\\\/g' -e "s/'/\\\'/g")
	fi
}

SECURE_INSTANCE() {
	ASK_FOR_ROOT_PASSWORD "Set MySQL root password: "
	until [[ $? == 0 ]]
	do
	    ASK_FOR_ROOT_PASSWORD "Set MySQL root password: "
	done
	ECHO "Removing anonymous users"
	mysql -uroot -e "DELETE FROM mysql.user WHERE User='';"
	ECHO "Removing remote root access"
	mysql -uroot -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
	ECHO "Removing test database"
	mysql -uroot -e "DROP DATABASE IF EXISTS test;"
	mysql -uroot -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
	mysql -uroot -e "FLUSH PRIVILEGES;"
	ECHO "Changing MySQL root user password"

	mysql -uroot -e "CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE'; FLUSH PRIVILEGES;"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "CREATE USER IF NOT EXISTS 'root'@'127.0.0.1' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE';"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "CREATE USER IF NOT EXISTS 'root'@'::1' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE'; FLUSH PRIVILEGES;"

	mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE'; FLUSH PRIVILEGES;"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE';"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "ALTER USER 'root'@'::1' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD_MARIADB_ESCAPE'; FLUSH PRIVILEGES;"


	if grep -q "disable_unix_socket" $MYSQL_CONFIG_FILE; then
	  ECHO "Unix socket settings OK!"
	else
    DISABLE_UNIX_SOCKET
	fi
}

ENSURE_CONFIG() {
	ECHO "Ensuring MySQL service is enabled"
	systemctl enable $DB_SERVICE
	ECHO "MySQL settings OK!"
}

set_mysql_param() {
  local file="${MYSQL_CONFIG_FILE:-/etc/mysql/my.cnf}"
  local key value kv

  if [[ $# -eq 1 && "$1" == *"="* ]]; then
    kv="$1"
    key="${kv%%=*}"
    value="${kv#*=}"
  elif [[ $# -ge 2 ]]; then
    key="$1"; value="$2"; kv="$key=$value"
    [[ -n "$3" ]] && file="$3"
  else
    echo "Usage: set_mysql_param KEY=VALUE | set_mysql_param KEY VALUE [FILE]" >&2
    return 2
  fi

  [[ -f "$file" ]] || touch "$file"
  cp "$file" "${file}.bak.$(date +%Y%m%d%H%M%S)"

  awk -v key="$key" -v value="$value" '
    BEGIN {
      kv = key "=" value
      mysqld = 0
      found = 0
      seen_mysqld = 0
    }
    function print_kv(){ print kv; found=1 }
    {
      # On section headers, inject kv before leaving [mysqld] if not found yet
      if ($0 ~ /^[[:space:]]*\[[^]]+\][[:space:]]*$/) {
        if (mysqld && !found) { print_kv() }
        mysqld = ($0 ~ /^[[:space:]]*\[mysqld\][[:space:]]*$/)
        if (mysqld) seen_mysqld = 1
        print $0
        next
      }

      if (mysqld) {
        # Keep comments/blank lines as-is
        if ($0 ~ /^[[:space:]]*[#;]/ || $0 ~ /^[[:space:]]*$/) { print $0; next }
        # Replace first occurrence of the key in [mysqld]
        if ($0 ~ "^[[:space:]]*" key "[[:space:]]*=") {
          if (!found) print kv
          found = 1
          next
        }
      }
      print $0
    }
    END {
      # If there was no [mysqld], create it, then add kv.
      if (!seen_mysqld) {
        print ""
        print "[mysqld]"
      }
      if (!found) print kv
    }
  ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
}

DISABLE_UNIX_SOCKET() {
  ECHO "Disabling unix socket"
	if grep -q "unix_socket=OFF" $MYSQL_CONFIG_FILE; then
	  sed -i "s/unix_socket=OFF/disable_unix_socket/g" $MYSQL_CONFIG_FILE
	elif grep -q "unix_socket=ON" $MYSQL_CONFIG_FILE; then
	  sed -i "s/unix_socket=ON/disable_unix_socket/g" $MYSQL_CONFIG_FILE
	else
	  if grep -q "\[mysqld\]" $MYSQL_CONFIG_FILE; then
      	sed -i "s/\[mysqld\]/\[mysqld\]\ndisable_unix_socket/g" $MYSQL_CONFIG_FILE
    else
      	echo "" >> $MYSQL_CONFIG_FILE
      	echo "[mysqld]" >> $MYSQL_CONFIG_FILE
      	echo "disable_unix_socket" >> $MYSQL_CONFIG_FILE
    fi
	fi
}

ASK_FOR_ROOT_PASSWORD() {
	stty -echo
	printf "$1"
	IFS= read -rs MYSQL_ROOT_PASSWORD; echo
	decoded_password=$(printf '%s' "$MYSQL_ROOT_PASSWORD" | base64 -d 2>/dev/null)

	if [ "${decoded_password:0:8}" == "[BASE64]" ]; then
    MYSQL_ROOT_PASSWORD="${decoded_password:8}"
	else
		MYSQL_ROOT_PASSWORD=$(printf '%s' "$MYSQL_ROOT_PASSWORD")
	fi

	stty echo
	until [ $(expr "$MYSQL_ROOT_PASSWORD" : '.*') -lt "$MYSQL_ROOT_PASSWORD_LENGTH" ]
    do
      echo "Password too long. Max length is 79 characters."
      printf "$1"
      IFS= read -rs MYSQL_ROOT_PASSWORD; echo
    done

	ENSURE_PASSWORD
}

CHECK_ROOT_ACCESS() {
	if mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "exit" &>/dev/null; then
		ECHO "Setting up MySQL for vProtect"
	else
		ECHO "Couldn't gain root access in MySQL for creating vProtect database"
		exit 1
	fi
	return 0
}

ENSURE_DATABASE_EXISTS() {
	if mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' $MYSQL_DB_NAME -e "exit" &>/dev/null; then
		ECHO "vProtect database already exists"
	else
		mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "CREATE DATABASE vprotect CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
		ERROR $? 1
		ECHO "vProtect database created"
	fi
}

ENSURE_VPROTECT_USER_EXISTS() {
	if [ "a$(mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -s -r -N -e "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user='$MYSQL_USER_NAME')")" == "a1" ]; then
		MYSQL_USER_PASSWORD=$(grep "eu\.storware\.vprotect\.db\.password" $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE | cut -d'=' -f2-)
		if [ ! -z $MYSQL_USER_PASSWORD ]; then
			if mysql -u$MYSQL_USER_NAME -p$MYSQL_USER_PASSWORD -e "exit" &>/dev/null; then
				ECHO "vProtect database user already exists"
				return 0
			else
				mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "DROP USER '$MYSQL_USER_NAME'"
				mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "DROP USER '$MYSQL_USER_NAME'@'localhost'"
			fi
		else
			mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "DROP USER '$MYSQL_USER_NAME'"
			mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "DROP USER '$MYSQL_USER_NAME'@'localhost'"
		fi
	fi
	MYSQL_USER_PASSWORD=$(< /dev/urandom tr -dc  A-Za-z0-9 | head -c32)
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "CREATE USER '$MYSQL_USER_NAME'@'localhost' IDENTIFIED BY '$MYSQL_USER_PASSWORD'"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "GRANT ALL PRIVILEGES ON $MYSQL_DB_NAME.* TO '$MYSQL_USER_NAME'@'localhost' WITH GRANT OPTION"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "CREATE USER '$MYSQL_USER_NAME'@'%' IDENTIFIED BY '$MYSQL_USER_PASSWORD'"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "GRANT ALL PRIVILEGES ON $MYSQL_DB_NAME.* TO '$MYSQL_USER_NAME'@'%' WITH GRANT OPTION"
	mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "FLUSH PRIVILEGES"
	ECHO "vProtect database user created"
	PUT_PASSWORD_IN_PAYARA_PROPERTIES
}

PUT_PASSWORD_IN_PAYARA_PROPERTIES() {
	sed -i "/quarkus.datasource.password=/d" $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE
	sed -i "/quarkus.datasource.username=/d" $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE
	if ! FILE_ENDS_WITH_NEWLINE $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE; then
		echo "" >> $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE
	fi
	echo "quarkus.datasource.username=$MYSQL_USER_NAME" >> $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE
	echo "quarkus.datasource.password=$MYSQL_USER_PASSWORD" >> $VPROTECT_DIR/$QUARKUS_PROPERTIES_FILE
	ECHO "Randomly generated password for vProtect database user saved"
}

INSERT_BASE_MIGRATION() {
  mysql -uroot -p''"$MYSQL_ROOT_PASSWORD"'' -e "source $MYSQL_BASE_MIGRATION_PATH" "$MYSQL_DB_NAME"
}

if [ "$EUID" -ne 0 ]; then
	echo "Root permissions required!"
	exit 1
fi

SUDO

ENSURE_CONFIG

ECHO "Restarting MySQL"
systemctl restart $DB_SERVICE

if mysql -uroot -e "exit" &>/dev/null; then
	SECURE_INSTANCE
else
	ASK_FOR_ROOT_PASSWORD "Please provide MySQL root password: "
	until [[ $? == 0 ]]
	do
	    ASK_FOR_ROOT_PASSWORD "Please provide MySQL root password: "
	done
fi

CHECK_ROOT_ACCESS
ENSURE_DATABASE_EXISTS
ENSURE_VPROTECT_USER_EXISTS

set_mysql_param "lower_case_table_names=1"
set_mysql_param "innodb_lock_wait_timeout=120"
set_mysql_param "innodb_buffer_pool_size=2G"
set_mysql_param "innodb_log_file_size=512M"
set_mysql_param "max_connections=320"
set_mysql_param "innodb_flush_log_at_trx_commit=2"
set_mysql_param "query_cache_type=0"
set_mysql_param "query_cache_size=0"
set_mysql_param "thread_cache_size=64"
set_mysql_param "join_buffer_size=1M"
set_mysql_param "sort_buffer_size=1M"
set_mysql_param "read_buffer_size=1M"
set_mysql_param "read_rnd_buffer_size=2M"
set_mysql_param "innodb_file_per_table=1"
set_mysql_param "innodb_buffer_pool_instances=2"
set_mysql_param "tmp_table_size=256M"
set_mysql_param "max_heap_table_size=256M"
set_mysql_param "innodb_flush_method=O_DIRECT"


ECHO "Restarting MySQL"
systemctl restart $DB_SERVICE
ECHO "Processing base migration"
INSERT_BASE_MIGRATION
ECHO "MySQL prepared successfully."