#!/bin/bash -e

#┌────────────────────────────────────────────────────────────────────────────┐
#│  Если вместо запуска установщика данный файл открывается в текстовом       │
#│    редакторе, откройте командную консоль и выполните команду               │
#│      chmod +x install_firesecnt.sh                                         │
#│  Или откройте в файловом менеджере свойства файла install_firesecnt.sh     │
#│    и установите право на выполнение файла (бит "x")                        │
#└────────────────────────────────────────────────────────────────────────────┘


me=$(basename "$0")

# Constants
SCRIPT_VERSION="2.0"
PKG_R3LN_NAME="firesecnt-r3ln"
PKG_2OP3_NAME="firesecnt-2op3"

GPG_ASTRA_KEY_FILE="/etc/digsig/keys/rubezh_pub.key"
GPG_ASTRA_KEY_CONTENT="-----BEGIN PGP ARMORED FILE-----
Comment: Use gpg --dearmor for unpacking

mN4EZGcyBCMBAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQxAAMHAP9f
v/SYqpOM5zm44CL7r+9AVj9uajRy/CpRTAzp2uI7fgACAgD8COKooOZRR9S9YxYD
DhbRnIXJfwqcomcSK5arvOp+j8gAAQEBAIAAAAAAAAAAAAAAAAAAAAFQ/ooYkpdh
VMWc/Bk6zPWzAP9LXLSix5LbV0qNBJU+zEyCzanKLKnP93vTmX/SM11oQAD8DayJ
RKnDL3i4elNZUO25oKKvQNWsHWMnsgesb3/AHJYAAQG0ONCe0J7QniAi0KDRg9Cx
0LXQtiIgKGtleSBmb3Igc2lnbmluZykgPHJ1YmV6aEBydWJlemgucnU+iJAEEyMM
ADgWIQRvMOxI1RXduorsk/ZKvgPl2VJJIAUCZGcyBAIbAwULCQgHAgYVCAkKCwIE
FgIDAQIeAQIXgAAKCRBKvgPl2VJJIM5GAP9e7p60q0Bw9P9N5vY7uSn/H53xjY/9
RvS0QSBcItUy9gD+KeT3SC76+UEmo/o8YKT6DTAYOH2TdhxzzORal9r8+w2IdQQQ
IwwAHRYhBKEte1uvzkDYf9Qdr8gtSfw2dbb6BQJkZzIEAAoJEMgtSfw2dbb6eL0A
/ir7pClgVwtWu8ZfpsCQ0p3gIxibGgbVHSOX4/e/i8tzAP42xOSVP1KeRW1F3QlJ
GqGGKFGIazywYjuKP7n7aaJtgA==
=j2zg
-----END PGP ARMORED FILE-----
"

function help() {
    echo " Запуск:"
    echo " sudo bash $me [опции]"
    echo
    echo " Опции:"
    echo "  -h вывести подсказку."
    echo "  -v отобразить версию скрипта."
    echo "  -q запуск в командном режиме, используются указанные опции"
    echo "     без ключа -q параметры установки будут запрошены в интерактивном режиме"
    echo "  -d [$PKG_R3LN_NAME, $PKG_2OP3_NAME] опция предназначена для указания пакета, который будет установлен. По умолчанию - $PKG_R3LN_NAME."
    echo "  -t [hu, hd, hr]                     опция предназначена для указания типа репозитория, который будет использован. По умолчанию hr - release (другие репозитории не доступны из сети интернет)."
    echo "  -r <version>                        опция предназначена для указания версии пакета. Допустимо указывать неполную версию со звездочкой в конце (например: 1.8*)."
    echo
    echo "Примеры:"
    echo
    echo "            sudo bash $me"
    echo "Будет установлен пакет с последней стабильной версией ПО FireSecNT с поддержкой оборудования линейки R3 с интерфейсом R3Link."
    echo
    echo "            sudo bash $me -d $PKG_R3LN_NAME"
    echo "Равносильно команде из предыдущего примера (пакет $PKG_R3LN_NAME выбирается по умолчанию, если не указан ключ -d)."
    echo
    echo "            sudo bash $me -d $PKG_2OP3_NAME"
    echo "Будет установлен пакет с последней стабильной версией ПО FireSecNT с поддержкой оборудования линейки R3 с интерфейсом 485."
    echo
    echo "            sudo bash $me -d $PKG_R3LN_NAME -r 1.8.14*"
    echo "Будет установлен пакет с 14-ой сборкой версии 1.8 ПО FireSecNT с поддержкой оборудования линейки R3 с интерфейсом R3Link."
    echo
    echo "            sudo bash $me -d $PKG_2OP3_NAME -r 1.8*"
    echo "Будет установлен пакет с последней стабильной сборкой версии 1.8 ПО FireSecNT с поддержкой оборудования линейки R3 с интерфейсом 485."
    echo
}

version() {
    me=$(basename "$0")
    echo " Версия $me: $SCRIPT_VERSION"
}


# Default arg values
DEB_PACKAGE=$PKG_R3LN_NAME
FSNT_VERSION="*"
REPO_TYPE="hr"
VISUAL_MODE=true

while getopts "hvqd:t:r:" opt
do
    case $opt in
        h) help; exit ;;
        v) version; exit;;
        q) VISUAL_MODE=false;;
        d) DEB_PACKAGE=$OPTARG ;;
        t) REPO_TYPE=$OPTARG ;;
        r) FSNT_VERSION=$OPTARG ;;
        *) help; exit 1 ;;
    esac
done

if [[ $EUID -ne 0 ]]
    then echo "Перезапуск скрипта от имени суперпользователя..."
    exec sudo bash "$0" "$@"
    exit
fi

# Убьем авто-обновление, если оно запущено
# Сначала отправляем сигнал TERM для корректного завершения
pkill -f ".*unattended.*" 2>/dev/null
# Даем процессам время на корректное завершение
timeout=3
end_time=$(( $(date +%s) + timeout ))
while [ $(date +%s) -lt $end_time ]; do
    if ! pgrep -f ".*unattended.*" >/dev/null; then
        break
    fi
    sleep 0.2
done
# Если процессы еще остались, принудительно убиваем их
pkill -9 -f ".*unattended.*" 2>/dev/null
# Проверяем, есть ли пакеты, требующие настройки
if dpkg -l | grep -q "^iU"; then
    echo "Настраиваем пакеты..."
    DEBIAN_FRONTEND=noninteractive timeout 60 dpkg --configure -a 2>/dev/null
fi

# Trap non-normal exit signals:
trap err_handler ERR
function err_handler {
    local exit_status=${1:-$?}
    echo "ERROR: script '$0' error code $exit_status (line $BASH_LINENO: '$BASH_COMMAND')"
    exit "$exit_status"
}

# Check package name
# TODO: change for if-else construction
case "$DEB_PACKAGE" in
    "$PKG_R3LN_NAME" | "$PKG_2OP3_NAME") ;;
    *) echo "Ошибка: указан неизвестный для установки пакет $DEB_PACKAGE. Укажите $PKG_R3LN_NAME или $PKG_2OP3_NAME. Для вывода справки наберите bash ./$me -h"; exit 1 ;;
esac

# Check CPU compatibility with MongoDB 5.0 (https://www.mongodb.com/docs/manual/administration/production-notes/)
if ! lscpu | grep -q avx; then
  echo "Ошибка: процессор вашей системы не удовлетворяет требованиям совместимости. Для FireSecNT требуется поддержка инструкций avx (см. https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#CPUs_with_AVX).";
  exit 1;
fi

function AddRepository()
{
    local pubkey_url="$1"
    local repository_url="$2"
    local repository_distrib="$3"
    local repo_name="$4"

    local keyring_dir="/usr/share/keyrings"
    mkdir -p "${keyring_dir}"
    curl -fsSL "${pubkey_url}" | gpg --yes -o "${keyring_dir}/${repo_name}.gpg" --dearmor

    echo "deb [ signed-by=${keyring_dir}/${repo_name}.gpg ] ${repository_url} ${repository_distrib} main" | \
    tee "/etc/apt/sources.list.d/${repo_name}.list"
}

function AddUnsignedRepository()
{
    local repository_url="$1"
    local repository_distrib="$2"
    local repo_name="$3"

    echo "deb ${repository_url} ${repository_distrib} main contrib non-free" | \
    tee "/etc/apt/sources.list.d/${repo_name}.list"
}

function InstallDeb()
{
    local debPackage=$1
    if ! apt-get install "$debPackage" -y --allow-downgrades; then
        echo "Ошибка: не удалось установить пакет $debPackage. Проверьте соединение с интернетом."
        exit 1
    fi
}

function CheckAstraGPGKey()
{
    if astra-digsig-control is-enabled > /dev/null && [ ! -e $GPG_ASTRA_KEY_FILE ]; then
        echo -e "\033[1;31m"
        echo "┌──────────────────────────────────────────────────────────────────────────────────────────────┐"
        echo "│                                     Включен резим ЗПС!                                       │"
        echo "│     Программа установки добавит ключ FireSecNT в ОС, после этого требуется перезагрузка!     │"
        echo "│     После перезагрузки запустите установку FireSecNT еще раз, установка будет продолжена     │"
        echo "│                      ─────────────────────────────────────────────────                       │"
        echo "│                       Дождитесь завершения процесса пересборки initrd                        │"
        echo "└──────────────────────────────────────────────────────────────────────────────────────────────┘"
        echo -e "\033[0m"
        echo "${GPG_ASTRA_KEY_CONTENT}" | gpg --dearmor > "${GPG_ASTRA_KEY_FILE}"
        update-initramfs -uk all
        echo -e "\033[1;33m"
        echo "┌──────────────────────────────────────────────────────────────────────────────────────────────┐"
        echo "│                                 Пересборка initrd завершена.                                 │"
        echo "│                                  Требуется перезагрузка ОС.                                  │"
        echo "└──────────────────────────────────────────────────────────────────────────────────────────────┘"
        echo -e "\033[0m"
        exit 2
    fi
}

#supported OS identifiers
declare -A OS_IDS
OS_IDS[astraSE17]="astra_1.7_x86-64"
OS_IDS[astraSE18]="astra_1.8_x86-64"
OS_IDS[deb10]="debian_10"
OS_IDS[deb9]="debian_9"
OS_IDS[astraCE]="astra_2.12.*"
OS_IDS[ub18]="ubuntu_18.04"

# import OS information
. /etc/os-release

CURRENT_OS_ID="${ID}_${VERSION_ID}"

# Remove previously used custom repositories
rm -f /etc/apt/sources.list.d/bellsoft*
rm -f /etc/apt/sources.list.d/mongodb*
rm -f /etc/apt/sources.list.d/firesecnt*
rm -f /etc/apt/sources.list.d/jre*

# Add Astra SE 1.7 internet repositories and remove CDROM
if [ "${CURRENT_OS_ID}" = "${OS_IDS[astraSE17]}" ]; then
    sed -i "s/deb cdrom/#deb cdrom/" /etc/apt/sources.list
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-main/" \
                              "1.7_x86-64" "astra_main"
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-update/" \
                              "1.7_x86-64" "astra_update"
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-base/" \
                              "1.7_x86-64" "astra_base"
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-extended/" \
                              "1.7_x86-64" "astra_extended"
    CheckAstraGPGKey
elif [ "${CURRENT_OS_ID}" = "${OS_IDS[astraSE18]}" ]; then
    sed -i "s/deb cdrom/#deb cdrom/" /etc/apt/sources.list
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.8_x86-64/repository-main/" \
                              "1.8_x86-64" "astra_main"
    AddUnsignedRepository "https://download.astralinux.ru/astra/stable/1.8_x86-64/repository-extended/" \
                              "1.8_x86-64" "astra_extended"
    CheckAstraGPGKey
fi

apt-get update || echo "Предупреждение: не удалось произвести обновление списков пакетов"
InstallDeb apt-transport-https
InstallDeb curl
InstallDeb wget
if $VISUAL_MODE; then InstallDeb whiptail; fi

INNER_NEXUS_URL="http://nexus.rubezh.local:8081"
OUTER_NEXUS_URL="https://kb-nexus.rubezh.ru"

# Outer nexus is accessible on the port 7443 from the outside and from the default port from the inside
if ! wget -q -O /dev/null --spider "${OUTER_NEXUS_URL}"; then
    OUTER_NEXUS_URL="${OUTER_NEXUS_URL}:7443"
    echo "Информация: используется репозиторий ${OUTER_NEXUS_URL}"
fi

declare -A REPOSITORY_URLS
REPOSITORY_URLS[apt-firesecnt-hr]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-hd]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-hu]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb12-hr]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb12-hd]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb12-hu]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb9-hr]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb9-hd]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-firesecnt-deb9-hu]=${INNER_NEXUS_URL}
REPOSITORY_URLS[apt-liberica-jre-17-signed]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-liberica-jre-17]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-mongodb-5-deb10-signed]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-mongodb-7-deb12-signed]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-mongodb-5-deb10]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-mongodb-5-deb9]=${OUTER_NEXUS_URL}
REPOSITORY_URLS[apt-mongodb-5-ub18]=${OUTER_NEXUS_URL}

# Set variables depending on the OS version
# shellcheck disable=SC2254
FSNT_FILTER="!/signed/"
case "${CURRENT_OS_ID}" in
    ${OS_IDS[astraSE17]}) FS_REPO_NAME="apt-firesecnt"; JRE_REPO_NAME="apt-liberica-jre-17-signed"; MONGO_REPO_NAME="apt-mongodb-5-deb10-signed";
        FSNT_VERSION="${FSNT_VERSION}~signed"; FSNT_FILTER="/signed/" ;;
    ${OS_IDS[astraSE18]}) FS_REPO_NAME="apt-firesecnt-deb12"; JRE_REPO_NAME="apt-liberica-jre-17-signed"; MONGO_REPO_NAME="apt-mongodb-7-deb12-signed";
        FSNT_VERSION="${FSNT_VERSION}~signed"; FSNT_FILTER="/signed/" ;;
    ${OS_IDS[deb10]}) FS_REPO_NAME="apt-firesecnt"; JRE_REPO_NAME="apt-liberica-jre-17"; MONGO_REPO_NAME="apt-mongodb-5-deb10" ;;
    ${OS_IDS[deb9]}) FS_REPO_NAME="apt-firesecnt-deb9"; JRE_REPO_NAME="apt-liberica-jre-17"; MONGO_REPO_NAME="apt-mongodb-5-deb9" ;;
    ${OS_IDS[astraCE]}) FS_REPO_NAME="apt-firesecnt-deb9"; JRE_REPO_NAME="apt-liberica-jre-17"; MONGO_REPO_NAME="apt-mongodb-5-deb9" ;;
    ${OS_IDS[ub18]}) FS_REPO_NAME="apt-firesecnt-deb9"; JRE_REPO_NAME="apt-liberica-jre-17"; MONGO_REPO_NAME="apt-mongodb-5-ub18";
        # For tomcat8. Remove on FSNT-22283.
        cat << EOF | tee /etc/default/tomcat8
JAVA_HOME=/usr/lib/jvm/bellsoft-java17-runtime-amd64
EOF
        ;;
    *) echo "Операционная система ${ID} ${VERSION_ID} не поддерживается"; exit 1;;
esac

if $VISUAL_MODE; then
    whiptail --title "Установщик FireSecNT" \
        --backtitle "Добро пожаловать в установщик FireSecNT" \
        --msgbox "Этот установщик поможет вам установить FireSecNT на вашу систему." 12 60
    options=("$PKG_R3LN_NAME" "Пакет $PKG_R3LN_NAME" "$PKG_2OP3_NAME" "Пакет $PKG_2OP3_NAME")
    DEB_PACKAGE=$(whiptail --title "Выбор пакета" \
                     --backtitle "Установщик FireSecNT - Выбор пакета" \
                     --notags \
                     --default-item "$DEB_PACKAGE" \
                     --menu "Выберите пакет для установки:" 12 60 2 \
                     "${options[@]}" 3>&1 1>&2 2>&3)
    if wget -q -O /dev/null --spider "${INNER_NEXUS_URL}"; then
        options=("hr" "Стабильная версия" "hd" "Версия разработчиков" "hu" "Пользовательская сборка")
        REPO_TYPE=$(whiptail --title "Выбор канала поставки" \
                        --backtitle "Установщик FireSecNT - Выбор канала" \
                        --default-item "$REPO_TYPE" \
                        --menu "Выберите канал поставки:" 12 60 3 \
                        "${options[@]}" 3>&1 1>&2 2>&3)
    fi
fi

case "$REPO_TYPE" in
    hu) $VISUAL_MODE || echo "Информация: выбран user репозиторий";
        KEYPUB_NAME="public.apt-hu.key"; KEYPUB_REPO_NAME="raw_hu"; KEYPUB_REPO_URL="${INNER_NEXUS_URL}";
        REPO_DISTRIB="user"; FS_REPO_NAME="${FS_REPO_NAME}-hu" ;;
    hd) $VISUAL_MODE || echo "Информация: выбран develop репозиторий";
        KEYPUB_NAME="public.apt-hd.key"; KEYPUB_REPO_NAME="raw_hd"; KEYPUB_REPO_URL="${INNER_NEXUS_URL}";
        REPO_DISTRIB="develop"; FS_REPO_NAME="${FS_REPO_NAME}-hd" ;;
    hr) $VISUAL_MODE || echo "Информация: выбран release репозиторий";
        KEYPUB_NAME="public.apt-hr.key"; KEYPUB_REPO_NAME="raw_hr"; KEYPUB_REPO_URL="${OUTER_NEXUS_URL}";
        REPO_DISTRIB="release"; FS_REPO_NAME="${FS_REPO_NAME}-hr" ;;
    *) echo "Ошибка: не поддерживаемый тип репозитория $REPO_TYPE"; exit 1 ;;
esac

# Add firesecnt repository
AddRepository "${KEYPUB_REPO_URL}/repository/${KEYPUB_REPO_NAME}/kb1/firesecnt/distrib/dpkg/apt_repo_keys/${KEYPUB_NAME}" \
                    "${REPOSITORY_URLS[$FS_REPO_NAME]}/repository/${FS_REPO_NAME}/" \
                    "${REPO_DISTRIB}" \
                    "firesecnt-repository"
# Add JRE repository
AddRepository "${OUTER_NEXUS_URL}/repository/raw_hr/kb1/firesecnt/distrib/dpkg/apt_repo_keys/public.apt-hr.key" \
                    "${REPOSITORY_URLS[$JRE_REPO_NAME]}/repository/${JRE_REPO_NAME}/" \
                    "release" \
                    "jre-repository"

# Add MongoDB repository
AddRepository "${OUTER_NEXUS_URL}/repository/raw_hr/kb1/firesecnt/distrib/dpkg/apt_repo_keys/public.apt-hr.key" \
                    "${REPOSITORY_URLS[$MONGO_REPO_NAME]}/repository/${MONGO_REPO_NAME}/" \
                    "release" \
                    "mongodb-repository"

apt-get update || echo "Предупреждение: не удалось произвести обновление списков пакетов"
if $VISUAL_MODE; then
    menu_options=()
    for version in $(apt-cache madison "$DEB_PACKAGE" | awk "$FSNT_FILTER { print \$3 }"); do
        menu_options+=("$version" "$version")
    done
    FSNT_VERSION=$(whiptail --title "Выбор версии" \
                     --backtitle "Установщик FireSecNT - Выбор версии" \
                     --noitem \
                     --menu "Выберите версию для установки:" 20 60 10 \
                     "${menu_options[@]}" 3>&1 1>&2 2>&3)
fi
echo "                                                                      ";
echo "███████╗██╗██████╗ ███████╗███████╗███████╗ ██████╗███╗   ██╗████████╗";
echo "██╔════╝██║██╔══██╗██╔════╝██╔════╝██╔════╝██╔════╝████╗  ██║╚══██╔══╝";
echo "█████╗  ██║██████╔╝█████╗  ███████╗█████╗  ██║     ██╔██╗ ██║   ██║   ";
echo "██╔══╝  ██║██╔══██╗██╔══╝  ╚════██║██╔══╝  ██║     ██║╚██╗██║   ██║   ";
echo "██║     ██║██║  ██║███████╗███████║███████╗╚██████╗██║ ╚████║   ██║   ";
echo "╚═╝     ╚═╝╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝╚═╝  ╚═══╝   ╚═╝   ";
echo "                                                                      ";
echo "Setting up FireSecNT. Please, wait for a while."

InstallDeb "${DEB_PACKAGE}=${FSNT_VERSION}"

if $VISUAL_MODE; then
    whiptail --title "Установка завершена" \
        --msgbox "Установка FireSecNT завершена.\nПараметры установки:\n\nПакет:    $DEB_PACKAGE\nПоставка: $REPO_TYPE\nВерсия:   $FSNT_VERSION" \
        15 40
fi
apt-cache policy "${DEB_PACKAGE}"
echo "                                                             ";
echo "███████╗██╗███╗   ██╗██╗███████╗██╗  ██╗███████╗██████╗ ██╗  ";
echo "██╔════╝██║████╗  ██║██║██╔════╝██║  ██║██╔════╝██╔══██╗██║  ";
echo "█████╗  ██║██╔██╗ ██║██║███████╗███████║█████╗  ██║  ██║██║  ";
echo "██╔══╝  ██║██║╚██╗██║██║╚════██║██╔══██║██╔══╝  ██║  ██║╚═╝  ";
echo "██║     ██║██║ ╚████║██║███████║██║  ██║███████╗██████╔╝██╗  ";
echo "╚═╝     ╚═╝╚═╝  ╚═══╝╚═╝╚══════╝╚═╝  ╚═╝╚══════╝╚═════╝ ╚═╝  ";
echo "                                                             ";
