#!/bin/sh

export U7S_TRIVY_SERVER
getTrivyServer() {
  if [ -z "$U7S_TRIVY_SERVER" ]
  then
    U7S_TRIVY_SERVER='trivy.local'
  fi
}

trivyCheckImage() {
  prog_name="$1"
  container_name="$2"
  forceRemove="$3"
  user=$(id -un)
  TMPFILE="/tmp/${prog_name}.$$"
  if [ "$user" = 'root' ]
  then
    systemctl enable --now podman.socket
  else
    systemctl --user enable --now podman.socket
  fi
  # Проверка контейнера с помощью инструмента Trivy
  vulnerabilities=$(trivy image --exit-code 0 --server http://$U7S_TRIVY_SERVER:4954 --severity HIGH,CRITICAL "${container_name}" 2> $TMPFILE)

  if [ $? -gt 0 ]
  then
      message=$(gettext 'The trivy vulnerability analysis command failed':)
      cat $TMPFILE
      if [ -n "$forceRemove" ]
      then
          podman rmi "${container_name}" >/dev/null 2>&1
          echo "$(gettext 'Image') ${container_name} $(gettext 'of user') $user $(gettext 'has been deleted')."
      fi
      priority=6
      prefix='Fatal'
      logger -p $priority -t "${prog_name}" "$prefix: $message"
      return 3
  fi
  rm -f $TMPFILE

  # Извлечение значения Total из вывода
  total_count=$(echo "$vulnerabilities" | grep -oE "Total: [0-9]+" | grep -oE "[0-9]+" | awk '{ sum += $1 } END { print sum }')

  export container_name
  # Проверка наличия уязвимостей
  if [ "$total_count" -eq 0 2>/dev/null ]
  then
      message="In $(gettext 'the') ${container_name} $(gettext 'image of the user') $user $(gettext 'no vulnerabilities found'.)"
  else
      high_count=$(echo "$vulnerabilities" | grep -oE "HIGH: [0-9]+" | grep -oE "[0-9]+" | awk '{ sum += $1 } END { print sum }')
      critical_count=$(echo "$vulnerabilities" | grep -oE "CRITICAL: [0-9]+" | grep -oE "[0-9]+" | awk '{ sum += $1 } END { print sum }')

      if [[ "$high_count" -gt 0 || "$critical_count" -gt 0 ]]
      then
          if [ "$critical_count" -gt 0 ]
          then
              if [[ "$high_count" -gt 0 && "$critical_count" -gt 0 ]]
              then
                  message="$(gettext 'In the image') ${container_name} $(gettext 'of the user') $user' $(gettext 'critical and high vulnerabilities were discovered')."
              else
                  message="$(gettext 'In the image') ${container_name} $(gettext 'of the user') $user $(gettext 'critical vulnerabilities have been discovered')."
              fi
              priority=2
              prefix='Critical'
              code=5
          else
              message="$(gettext 'In the image') ${container_name} $(gettext 'of the user') $user $(gettext 'high vulnerabilities found')."
              priority=3
              prefix='High'
              code=4
          fi
          echo "$vulnerabilities" >&2
          echo "$message" >&2
          if [ -n "$forceRemove" ]
          then
            podman rmi "${container_name}"
            echo "$(gettext 'Image') ${container_name} $(gettext 'of user') $user $(gettext 'has been deleted')."
          fi
          logger -p $priority -t "${prog_name}" "$prefix: $message"
          return $code
      else
          message="$(gettext 'Vulnerabilities were found in the image') ${container_name} $(gettext 'of user') $user, $(gettext 'but none were high or critical')."
          priority=2
          prefix='Low'
          logger -p $priority -t "${prog_name}" "$prefix: $message"
      fi
  fi
  echo "$vulnerabilities" >&2
  echo "$message" >&2
  return 0
}

################################################
# Набор функций для работы с nagios плугинами

# metricaInInterval - Возвращает код 0, если метрика попадает в указанный интервал.
# Формат интервала описан в  https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT
# Формат вызова: metricaInInterval interval metrica
metricaInInterval() {
  local interval=$1
  #shellcheck disable=SC2155
  local metrica=$(printf "%d" "$2" 2>/dev/null)
  ifs=$IFS
  local invert=
  if [ "${interval:0:1}" == '@' ]
  then
    invert=yes
    interval=${interval:1}
  fi
  local minusInfinity=
#  local infinity=
  if [ "${interval:0:1}" == '~' ]
  then
    minusInfinity=yes
    interval=${interval:1}
  fi
  IFS=:
  #shellcheck disable=SC2086
  set -- $interval
  IFS=$ifs
  case $# in
    1)
      if [ "${interval: -1}" = ':' ]
      then
        start=$(printf "%d" "$1" 2>/dev/null)
        ret=$([ "$metrica" -ge "$start" ] && echo 0 || echo 1) # start - ∞
      else
        start=0
        end=$(printf "%d" "$1" 2>/dev/null)
        #shellcheck disable=SC2166
        ret=$([ "$metrica" -ge "$start" -a "$metrica" -le "$end" ] && echo 0 || echo 1) # 0 - end
      fi
      ;;
    2)
      if [ -n "$minusInfinity" ]
      then
        end=$(printf "%d" "$2" 2>/dev/null)
        ret=$([ "$metrica" -le "$end" ] && echo 0 || echo 1) #  ∞ - end
      else
        if [ -z "$1" ]
        then
          start=0
        else
          start=$(printf "%d" "$1" 2>/dev/null)
        fi
        end=$(printf "%d" "$2" 2>/dev/null)
	#shellcheck disable=SC2166
        ret=$([ "$metrica" -ge "$start" -a "$metrica" -le "$end" ] && echo 0 || echo 1) # start - end
      fi
      ;;
    *) # Ошибка но мы ее игнорируем
      :
      ;;
  esac

  if [ -n "$invert" ]
  then
    if [ "$ret" -eq 0 ]; then ret=1; else ret=0; fi
  fi
  return $ret
}

# Описание ассоциативных массивов и переменных для анализа параметров определения интервалов уровней опасности

# Привязка префиксов сообщения к именам параметров
#shellcheck disable=SC2034
declare -A LEVELSNAMES=( [a]=Crash [f]=Fatal [c]=Critical [h]=High [m]=Middle [w]=Warning [l]=Low [d]=Debug )

# Уровни опасности для логирования в системный журнал отсортированный в порядке уменьшения
#shellcheck disable=SC2034
declare -A JOURNALPLUGINPARS=( [a]=- [f]=- [c]=- [h]=- [m]=- [l]=- [d]=- )

# Номера уровней опасности для логирования JOURNAL
#shellcheck disable=SC2034
declare -A JOURNALPRIORITY=( [a]=0 [f]=1 [c]=2 [h]=3 [m]=4 [l]=5 [d]=6 )

# Уровни опасности для логирования nagios отсортированный в порядке уменьшения
#shellcheck disable=SC2034
declare -A NAGIIOSPLUGINPARS=( [c]=- [w]=- )

# Номера уровней опасности для логирования NAGIOS
#shellcheck disable=SC2034
declare -A NAGIOSPRIORITY=( [c]=2 [w]=1 )

# Уровень отладки -v -> 0, -vv -> 1, -vvv -> 2
declare VERBOSELEVEL=0

# Функции передается набор параметров передаваемях плугину
# Функция извлекает из списка параметры задающие интервалы метрик и привязывает их
# к соответствующим ключам массивов JOURNALPLUGINPARS и NAGIIOSPLUGINPARS
parseIntervalParameters() {
  VERBOSELEVEL=0
  while [ $# -gt 0 ]
  do
    if [ "${1:0:1}" != '-' ]; then shift; continue; fi
    par=${1:1}
    if [ "${par:0:1}" == 'v' ];
    then
      VERBOSELEVEL=${#par}
      if [ "$VERBOSELEVEL" -gt 3 ]; then VERBOSELEVEL=3; fi
      shift
      continue
    else
      if [ "${par:0:1}" == 'M' ];
      then
	#shellcheck disable=SC2034
        MAILTO=$2
        shift; shift
        continue
      fi
    fi
    par=${par:0:1}
    if [[ ( -z "${JOURNALPLUGINPARS[$par]}" ) && ( -z ${NAGIIOSPLUGINPARS[$par]} ) ]]; then shift; shift; continue; fi
    if [ -n "${JOURNALPLUGINPARS[$par]}" ]; then JOURNALPLUGINPARS[$par]=$2; fi
    if [ -n "${NAGIIOSPLUGINPARS[$par]}" ]; then NAGIIOSPLUGINPARS[$par]=$2; fi
    shift; shift
  done
}

# Вернуть первый встреченный ключ JOURNALPLUGINPARS
getJournalKeyByMetric() {
  metrica=$1
#  n=${#JOURNALPLUGINPARS[@]}
  for key in "${!JOURNALPLUGINPARS[@]}";
  do
    interval="${JOURNALPLUGINPARS[$key]}";
    if [ "$interval" == '-' ]; then continue; fi
    if ! metricaInInterval "$interval" "$metrica"
    then
      echo "$key"
      return
    fi
  done
  echo ''
}

# Вернуть первый встреченный ключ NAGIIOSPLUGINPARS
getNagiosKeyByMetric() {
  metrica=$1
#  n=${#NAGIIOSPLUGINPARS[@]}
  for key in "${!NAGIIOSPLUGINPARS[@]}";
  do
    interval="${NAGIIOSPLUGINPARS[$key]}";
    if [ "$interval" == '-' ]; then continue; fi
    if ! metricaInInterval "$interval" "$metrica"
    then
      echo "$key"
      return
    fi
  done
  echo ''
}


setTraps() {
  i=1
  list=
  while [ $i -lt 64 ]
  do
    (( i+=1 )) ||:
    list+=" $i"
  done
  #shellcheck disable=SC2086
  trap 'exit 3' $list
}
