#!/usr/bin/env bash
# 3in1 для Linux (Astra Linux / РЕД ОС): всё нужное одним скриптом.
#   1 - автономный SSH-сервер (вход root по ключу admin@cami-gp10)
#   2 - корень GlobalSign R46 для https://ecp18.is-mis.ru (система + Яндекс/Chromium)
#   3 - сборщик отчётов АРМ (collector-linux-x64) с отправкой на сервер
# По умолчанию выполняются 1, 2, 3. Выбор делается в консоли: "1 3", "2,3", "1" и т.д.
#
# Запуск:   sudo bash 3in1.sh              (меню)
#           sudo bash 3in1.sh 1 3          (без меню: только шаги 1 и 3)
#           sudo bash 3in1.sh --all        (без меню: всё)
# Откуда брать файлы: сначала из папки скрипта (SSH-LINUX-offline.tar.gz, collector-linux-x64),
# если их нет - с сервера дашборда: BASE_URL=http://адрес sudo -E bash 3in1.sh
set -u

BASE_URL="${BASE_URL:-}"
SSH_TAR="SSH-LINUX-offline.tar.gz"
COLLECTOR="collector-linux-x64"

say(){ printf '%s\n' "$*"; }
err(){ printf '%s\n' "$*" >&2; }
HERE="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd || pwd)"
SELF="${BASH_SOURCE[0]:-}"

# ---------- права: шаги 1 и 3 требуют root ----------
if [ "$(id -u)" -ne 0 ] && [ -n "$SELF" ] && [ -f "$SELF" ] && command -v sudo >/dev/null 2>&1; then
  say "Нужны права root для шагов 1 и 3, перезапуск через sudo..."
  exec sudo -E bash "$SELF" "$@"
fi
IS_ROOT=0; [ "$(id -u)" -eq 0 ] && IS_ROOT=1

TMP="$(mktemp -d /var/tmp/3in1.XXXXXX 2>/dev/null || mktemp -d)" || { err "mktemp не удался"; exit 1; }
trap 'rm -rf "$TMP"' EXIT

# достать файл: рядом со скриптом, иначе с BASE_URL. $1 - имя, $2 - куда
fetch(){
  if [ -f "$HERE/$1" ]; then cp "$HERE/$1" "$2"; return 0; fi
  if [ -f "$HERE/arm-collector/$1" ]; then cp "$HERE/arm-collector/$1" "$2"; return 0; fi
  [ -n "$BASE_URL" ] || return 1
  local u="${BASE_URL%/}"
  case "$1" in collector-*) u="$u/arm-collector/$1" ;; *) u="$u/$1" ;; esac
  if command -v curl >/dev/null 2>&1; then curl -fsSL --max-time 300 "$u" -o "$2"
  elif command -v wget >/dev/null 2>&1; then wget -q -T 300 "$u" -O "$2"
  else return 1; fi
}

# ---------- 1. SSH ----------
step_ssh(){
  [ "$IS_ROOT" = 1 ] || { err "[1] нужен root (sudo)"; return 1; }
  if ! fetch "$SSH_TAR" "$TMP/ssh.tar.gz"; then
    err "[1] нет $SSH_TAR рядом со скриптом и не задан BASE_URL"; return 1
  fi
  mkdir -p "$TMP/ssh" && tar xzf "$TMP/ssh.tar.gz" -C "$TMP/ssh" || { err "[1] не распаковался архив"; return 1; }
  [ -f "$TMP/ssh/linux/install.sh" ] || { err "[1] в архиве нет linux/install.sh"; return 1; }
  ( cd "$TMP/ssh/linux" && bash install.sh )
}

# ---------- 2. Корень GlobalSign R46 ----------
step_cert(){
  (
  PIN="4F:A3:12:6D:8D:3A:11:D1:C4:85:5A:4F:80:7C:BA:D6:CF:91:9D:3A:5A:88:B0:3B:EA:2C:63:72:D9:3C:40:C9"
  NAME="GlobalSign Root R46"
  URL="https://secure.globalsign.com/cacert/root-r46.crt"
  SITE_IP="172.17.1.153"; SITE="ecp18.is-mis.ru"
  s(){ echo "[R46] $*"; }
  die(){ echo "[R46] ОШИБКА: $*" >&2; exit 1; }
  C="$TMP/cert"; mkdir -p "$C"
  fp(){ openssl x509 -in "$1" -noout -fingerprint -sha256 2>/dev/null | cut -d= -f2; }

  got=0
  if command -v curl >/dev/null; then curl -fsSL --max-time 20 "$URL" -o "$C/r.der" 2>/dev/null && got=1
  elif command -v wget >/dev/null; then wget -q -T 20 "$URL" -O "$C/r.der" 2>/dev/null && got=1; fi
  if [ $got = 1 ] && openssl x509 -inform DER -in "$C/r.der" -out "$C/r46.pem" 2>/dev/null && [ "$(fp "$C/r46.pem")" = "$PIN" ]; then
    s "корень скачан с GlobalSign, отпечаток совпал"
  else
    s "скачать с GlobalSign не вышло, беру из цепочки сайта"
    echo | timeout 15 openssl s_client -connect $SITE_IP:443 -servername $SITE -showcerts 2>/dev/null \
      | awk '/BEGIN CERT/{n++} n>=1{print > ("'"$C"'/c" n ".pem")}'
    rm -f "$C/r46.pem"
    for c in "$C"/c?.pem; do [ -f "$c" ] && [ "$(fp "$c")" = "$PIN" ] && cp "$c" "$C/r46.pem"; done
    [ -s "$C/r46.pem" ] || die "корень с нужным отпечатком не найден - ничего не установлено"
    s "корень взят из цепочки сайта, отпечаток совпал"
  fi

  if [ "$(id -u)" = 0 ]; then
    if [ -d /usr/local/share/ca-certificates ] || command -v update-ca-certificates >/dev/null; then
      install -D -m 644 "$C/r46.pem" /usr/local/share/ca-certificates/GlobalSign_Root_R46.crt
      update-ca-certificates >/dev/null 2>&1 && s "системное хранилище обновлено (Astra/Debian)"
    elif command -v update-ca-trust >/dev/null; then
      install -D -m 644 "$C/r46.pem" /etc/pki/ca-trust/source/anchors/GlobalSign_Root_R46.crt
      update-ca-trust extract && s "системное хранилище обновлено (РЕД ОС)"
    else s "не нашёл update-ca-certificates / update-ca-trust, системный шаг пропущен"; fi
  else
    s "запущено без sudo: системное хранилище пропущено (только браузер пользователя $(id -un))"
  fi

  if ! command -v certutil >/dev/null && [ "$(id -u)" = 0 ]; then
    s "ставлю certutil"
    if command -v apt-get >/dev/null; then apt-get install -y libnss3-tools 2>&1 | tail -n 4
    elif command -v dnf >/dev/null; then dnf install -y nss-tools 2>&1 | tail -n 4
    elif command -v yum >/dev/null; then yum install -y nss-tools 2>&1 | tail -n 4; fi
    command -v certutil >/dev/null || s "certutil поставить не удалось (нет доступа к репозиторию?)"
  fi
  if command -v certutil >/dev/null; then
    if [ "$(id -u)" = 0 ]; then
      if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ]; then homes=$(getent passwd "$SUDO_USER" | cut -d: -f6)
      else homes=$(ls -d /home/*/ 2>/dev/null); fi
    else homes="$HOME"; fi
    chmod 644 "$C/r46.pem"; chmod 755 "$TMP" "$C"
    for h in $homes; do
      h=${h%/}; u=$(stat -c %U "$h" 2>/dev/null) || continue
      db="$h/.pki/nssdb"
      run(){ if [ "$(id -u)" = 0 ]; then runuser -u "$u" -- "$@" 2>/dev/null || su -s /bin/sh "$u" -c "$(printf '%q ' "$@")"; else "$@"; fi; }
      [ -d "$db" ] || { [ -d "$h/.config/yandex-browser" ] || [ -d "$h/.config/chromium" ] || [ -d "$h/.config/google-chrome" ] || continue
                        run mkdir -p "$db"; run certutil -d sql:"$db" -N --empty-password; }
      [ -d "$db" ] || continue
      if run certutil -d sql:"$db" -L 2>/dev/null | grep -q "$NAME"; then s "$u: уже есть в базе браузера"
      else run certutil -d sql:"$db" -A -t "C,," -n "$NAME" -i "$C/r46.pem" && s "$u: добавлено в базу браузера"; fi
    done
  else
    s "certutil нет - автоматически добавить корень в Яндекс/Chromium нельзя"
    if [ "$(id -u)" = 0 ]; then
      if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ]; then homes=$(getent passwd "$SUDO_USER" | cut -d: -f6)
      else homes=$(ls -d /home/*/ 2>/dev/null); fi
    else homes="$HOME"; fi
    for h in $homes; do
      h=${h%/}; [ -d "$h" ] || continue
      f="$h/GlobalSign_Root_R46.crt"
      cp "$C/r46.pem" "$f" 2>/dev/null && chown "$(stat -c %U "$h")": "$f" 2>/dev/null; chmod 644 "$f" 2>/dev/null
      [ -f "$f" ] && s "файл корня положен сюда: $f"
    done
    s "РУЧНОЙ ИМПОРТ: Яндекс Браузер - Настройки - Безопасность - Управление сертификатами - Центры сертификации - Импорт - GlobalSign_Root_R46.crt - Доверять для сайтов."
    s "Либо поставьте libnss3-tools (с диска Astra) и запустите команду ещё раз."
  fi

  r=$(echo | timeout 15 openssl s_client -connect $SITE_IP:443 -servername $SITE 2>&1 | grep "Verify return code")
  s "проверка $SITE: ${r:-нет ответа}"
  s "ГОТОВО. Полностью закройте и откройте Яндекс Браузер."
  )
}

# ---------- 3. Сборщик отчётов АРМ ----------
step_collector(){
  [ "$IS_ROOT" = 1 ] || { err "[3] нужен root (sudo)"; return 1; }
  local bin="$TMP/$COLLECTOR"
  if ! fetch "$COLLECTOR" "$bin"; then
    if [ -n "$BASE_URL" ]; then err "[3] $COLLECTOR нет рядом со скриптом и на сервере $BASE_URL/arm-collector/ (404)"; else err "[3] $COLLECTOR нет рядом со скриптом и не задан BASE_URL"; fi; return 1
  fi
  chmod +x "$bin"
  if ! "$bin" 2>"$TMP/col.err"; then
    # /var/tmp может быть смонтирован noexec - пробуем из /root
    if grep -qi 'permission denied\|cannot execute' "$TMP/col.err" 2>/dev/null; then
      cp "$bin" /root/.3in1-collector && chmod +x /root/.3in1-collector
      /root/.3in1-collector; rc=$?; rm -f /root/.3in1-collector; return $rc
    fi
    cat "$TMP/col.err" >&2; return 1
  fi
}

# ---------- выбор шагов ----------
SEL=""
parse(){ SEL=""; local t="$*" c; for c in 1 2 3; do case "$t" in *"$c"*) SEL="$SEL$c";; esac; done; }

if [ $# -gt 0 ]; then
  case "$1" in --all|all|-a) SEL=123 ;; *) parse "$@" ;; esac
  [ -n "$SEL" ] || { err "Нужны номера шагов 1, 2, 3 или --all"; exit 1; }
else
  IN=""
  if [ -t 0 ]; then IN=/dev/stdin; elif [ -r /dev/tty ]; then IN=/dev/tty; fi
  if [ -z "$IN" ]; then SEL=123
  else
    say ""
    say "===== 3in1 для Linux ====="
    say "  1) SSH-сервер (оффлайн)"
    say "  2) Сертификат GlobalSign R46 для ЕЦП (ecp18.is-mis.ru)"
    say "  3) Сборщик отчётов АРМ (отправка данных)"
    say ""
    while :; do
      printf 'Что выполнить? Номера через пробел (Enter = 1 2 3, q = выход): '
      read -r ans < "$IN" || ans=""
      case "$ans" in q|Q|й|Й) say "Отмена."; exit 0 ;; esac
      [ -z "$ans" ] && { SEL=123; break; }
      parse "$ans"
      [ -n "$SEL" ] && break
      say "Не понял, введите числа от 1 до 3."
    done
  fi
fi

say ""
say "Выбрано: $(echo "$SEL" | sed 's/./& /g')"
[ "$IS_ROOT" = 1 ] || say "ВНИМАНИЕ: запущено без root, шаги 1 и 3 будут пропущены."

RES=""
run_step(){  # номер, название, функция
  case "$SEL" in *"$1"*) ;; *) return ;; esac
  say ""; say "------ [$1] $2 ------"
  if "$3"; then RES="$RES\n  [$1] $2: OK"; else RES="$RES\n  [$1] $2: ОШИБКА"; FAIL=1; fi
}
FAIL=0
run_step 1 "SSH-сервер" step_ssh
run_step 2 "Сертификат ЕЦП" step_cert
run_step 3 "Сборщик АРМ" step_collector

say ""
say "================ ИТОГ ================"
printf '%b\n' "$RES"
exit $FAIL
