#!/usr/bin/env bash

# shellcheck shell=bash

# ``````````````````````````````````````````````````````````````````````````````
# Function name: DomainCertCheck()
#
# Description:
#   Check domain certificate.
#
# Usage:
#   DomainCertCheck domain
#
# Examples:
#   DomainCertCheck example.com
#

function DomainCertCheck() {

  # shellcheck disable=SC2034
  local _FUNCTION_ID="DomainCertCheck"
  local _STATE=0

  # shellcheck disable=SC2034,SC2154
  _ssl_remote_socket="${_domain_ip}:${_domain_port}"
  # shellcheck disable=SC2154
  _ssl_domain_name="$_domain_name"

  # shellcheck disable=SC2154
  if [[ -z "$_ssl_version_openssl_curl" ]] ; then

    _ssl_domain_cert=$(echo | \
                       $_openssl s_client -servername "$_ssl_domain_name" \
                       -connect "$_ssl_remote_socket" 2>/dev/null | \
                       sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')

    _ssl_domain_cert_non_sni=$(echo | \
                       $_openssl s_client \
                       -connect "$_ssl_remote_socket" 2>/dev/null | \
                       sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')

  else

    _ssl_domain_cert=$(echo | \
                       $_openssl s_client "$_ssl_version_openssl_curl" -servername "$_ssl_domain_name" \
                       -connect "$_ssl_remote_socket" 2>/dev/null | \
                       sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')

    _ssl_domain_cert_non_sni=$(echo | \
                      $_openssl s_client "$_ssl_version_openssl_curl" \
                      -connect "$_ssl_remote_socket" 2>/dev/null | \
                      sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')

  fi

  _ssl_domain_names=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
                     N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  if [[ -n "$_ssl_domain_cert_non_sni" ]] ; then

    _ssl_domain_names_non_sni=$(echo "$_ssl_domain_cert_non_sni" | \
                       $_openssl x509 -noout -text | \
                       sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
                       N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' | \
                       sed -e 's/^[ \t]*//' | \
                       tr -d '"')

  fi

  _ssl_domain_issuer=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Issuer:" | \
                     cut -d ":" -f2- | tr -s ' ' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_subject=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Subject:" | \
                     cut -d ":" -f2- | tr -s ' ' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_not_before=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Not Before:" | \
                     cut -d ":" -f2- | tr -s ' ' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_not_after=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Not After :" | \
                     cut -d ":" -f2- | tr -s ' ' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_public_key=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Public-Key:" | \
                     cut -d ":" -f2- | tr -s ' ' | tr -d '()' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_signature=$(echo "$_ssl_domain_cert" | \
                     $_openssl x509 -noout -text | \
                     grep "Signature Algorithm:" | head -n 1 | \
                     cut -d ":" -f2- | tr -s ' ' | tr -d '()' | \
                     sed -e 's/^[ \t]*//' | \
                     tr -d '"')

  _ssl_domain_issuer_o=$(echo "$_ssl_domain_issuer" | \
                     grep -o "O =.*" | \
                     cut -d "=" -f2- | \
                     cut -d "," -f1 | \
                     awk '{$1=$1};1')

  _ssl_domain_issuer_cn=$(echo "$_ssl_domain_issuer" | \
                     grep -o "CN =.*" | \
                     cut -d "=" -f2- | \
                     cut -d "," -f1 | \
                     awk '{$1=$1};1')

  _ssl_domain_subject_o=$(echo "$_ssl_domain_subject" | \
                     tr ',' '\n' | \
                     grep -o "O =.*" | \
                     cut -d "=" -f2- | \
                     cut -d "," -f1 | \
                     awk '{$1=$1};1' | \
                     tr '\n' ' ' | \
                     tr -d \'\" | sed 's/ *$//' | \
                     tr -d '"')

  _ssl_domain_subject_ou=$(echo "$_ssl_domain_subject" | \
                     tr ',' '\n' | \
                     grep -o "OU =.*" | \
                     cut -d "=" -f2- | \
                     cut -d "," -f1 | \
                     awk '{$1=$1};1' | \
                     tr '\n' ' ' | \
                     tr -d \'\" | sed 's/ *$//' | \
                     tr -d '"')

  _ssl_domain_cn=$(echo "$_ssl_domain_names" | \
                     grep -o "CN =.*" | \
                     cut -d "=" -f2- | \
                     cut -d "," -f1 | \
                     awk '{$1=$1};1')

  _ssl_domain_san=$(echo "$_ssl_domain_names" | \
                     grep "DNS:" | \
                     cut -d ":" -f2- | \
                     tr '\n' ' ')

  _ssl_domain_not_after_expr="$_ssl_domain_not_after"

  if [[ "$_ssl_domain_public_key" == "4096 bit" ]] || \
     [[ "$_ssl_domain_public_key" == "2048 bit" ]] || \
     [[ "$_ssl_domain_public_key" == "521 bit" ]] || \
     [[ "$_ssl_domain_public_key" == "384 bit" ]] || \
     [[ "$_ssl_domain_public_key" == "256 bit" ]] || \
     [[ "$_ssl_domain_public_key" == "224 bit" ]] ; then

    # shellcheck disable=SC2154
    local _pkey_trgb="$trgb_3200"

  elif [[ "$_ssl_domain_public_key" == "192 bit" ]] ; then

    # shellcheck disable=SC2154
    local _pkey_trgb="$trgb_3300"

  else

    # shellcheck disable=SC2154
    local _pkey_trgb="$trgb_3100"

  fi

  # shellcheck disable=SC2154
  if [[ "$ssl_state" -eq 1 ]] ; then

    local _equal_state="0"
    export _validity_state="0"
    local _all_common_names="$_ssl_domain_cn $_ssl_domain_san"

    IFS=" " read -r -a _common_names <<< "$(sort <<<"$_all_common_names")"
    for _cn in "${_common_names[@]}" ; do

      if [[ "$_ssl_domain_name" == "$_cn" ]] ; then

        # shellcheck disable=SC2034
        _equal_state="1"

        break

      else

        if [[ "$_cn" = *"*"* ]] ; then

          _cn_crt=$(echo "$_cn" | cut -d "." -f2-)
          _cn_dom=$(echo "$_ssl_domain_name" | cut -d "." -f2-)

          if [[ "$_cn_crt" == "$_cn_dom" ]] ; then

            # shellcheck disable=SC2034
            _equal_state="1"

            break

          fi

        fi

      fi

    done

    unset IFS

    # shellcheck disable=SC2004
    _now_epoch=$(date +%s)
    _expiry_epoch=$(date -d "$_ssl_domain_not_after_expr" +%s)
    _expiry_epoch_to_end="$((_expiry_epoch - _now_epoch))"
    _expiry_epoch_to_end_days="$((_expiry_epoch_to_end / (3600 * 24)))"

    if [[ "$_expiry_epoch" -gt "$_now_epoch" ]] ; then

      _time_to_expire=$(date -d @$_expiry_epoch_to_end +"%H:%M:%S")

      if [[ "$_expiry_epoch_to_end_days" -eq 0 ]] ; then

        # Less then 1h
        if [[ "$_expiry_epoch_to_end" -lt 3600 ]] ; then

          _expr_time_msg="expires in $_time_to_expire"
          _expr_timtrgb="$trgb_3310"

        # Less then 3h
        elif [[ "$_expiry_epoch_to_end" -lt 10800 ]] ; then

          _expr_time_msg="expires in $_time_to_expire"
          _expr_timtrgb="$trgb_3310"

        # Less then 6h
        elif [[ "$_expiry_epoch_to_end" -lt 21600 ]] ; then

          _expr_time_msg="expires in $_time_to_expire"
          _expr_timtrgb="$trgb_3310"

        # Less then 12h
        elif [[ "$_expiry_epoch_to_end" -lt 43200 ]] ; then

          _expr_time_msg="expires in $_time_to_expire"
          _expr_timtrgb="$trgb_3310"

        # Less then 24h
        else

          _expr_time_msg="expires in $_time_to_expire"
          _expr_timtrgb="$trgb_3310"

        fi

      elif [[ "$_expiry_epoch_to_end_days" -le 7 ]] ; then

        _expr_time_msg="expires in $_expiry_epoch_to_end_days days"
        _expr_timtrgb="$trgb_3310"

      elif [[ "$_expiry_epoch_to_end_days" -le 14 ]] ; then

        _expr_time_msg="expires in $_expiry_epoch_to_end_days days"
        _expr_timtrgb="$trgb_3300"

      else

        _expr_time_msg="expires in $_expiry_epoch_to_end_days days"
        _expr_timtrgb="$trgb_3200"

      fi

    else

      _expr_time_msg="expired"
      _expr_timtrgb="$trgb_3100"

    fi

    # shellcheck disable=SC2086,SC2154
    printf '         public-key(\e['${_pkey_trgb}'m%s\e[m), ' \
           "$_ssl_domain_public_key"

    # shellcheck disable=SC2086,SC2154
    printf 'signature(\e['${trgb_9420}'m%s\e[m)\n' \
           "$_ssl_domain_signature"

    # shellcheck disable=SC2086,SC2154
    printf '         date: \e['${trgb_3722}'m%s / %s\e[m (\e['${_expr_timtrgb}'m%s\e[m)\n' \
           "$_ssl_domain_not_before" "$_ssl_domain_not_after" "$_expr_time_msg"

    if [[ -z "$_ssl_domain_issuer_o" ]] && \
       [[ -z "$_ssl_domain_issuer_cn" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         issuer: \e['${trgb_3812}'m%s\e[m\n' \
             "<empty>"

    elif [[ -z "$_ssl_domain_issuer_o" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         issuer: \e['${trgb_3722}'m%s\e[m\n' \
             "$_ssl_domain_issuer_cn" | \
             fmt -w "$MAX_WIDTH" -s

    elif [[ -z "$_ssl_domain_issuer_cn" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         issuer: (\e['${trgb_3812}'m%s\e[m)\n' \
             "$_ssl_domain_issuer_o" | \
             fmt -w "$MAX_WIDTH" -s

    else

      # shellcheck disable=SC2086,SC2154
      printf '         issuer: \e['${trgb_3722}'m%s\e[m (\e['${trgb_3812}'m%s\e[m)\n' \
             "$_ssl_domain_issuer_cn" "$_ssl_domain_issuer_o" | \
             fmt -w "$MAX_WIDTH" -s

    fi

    if [[ -z "$_ssl_domain_subject_o" ]] && \
       [[ -z "$_ssl_domain_subject_ou" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         owner: \e['${trgb_3812}'m%s\e[m\n' \
             "<empty>"

    elif [[ -z "$_ssl_domain_subject_ou" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         owner: \e['${trgb_3722}'m%s\e[m\n' \
             "$_ssl_domain_subject_o" | \
             fmt -w "$MAX_WIDTH" -s

    elif [[ -z "$_ssl_domain_subject_o" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         owner: (\e['${trgb_3812}'m%s\e[m)\n' \
             "$_ssl_domain_subject_ou" | \
             fmt -w "$MAX_WIDTH" -s

    else

      # shellcheck disable=SC2086,SC2154
      printf '         owner: \e['${trgb_3722}'m%s\e[m (\e['${trgb_3812}'m%s\e[m)\n' \
             "$_ssl_domain_subject_o" "$_ssl_domain_subject_ou" | \
             fmt -w "$MAX_WIDTH" -s

    fi

    if [[ -z "$_ssl_domain_cn" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         cn: <empty>\n'

    else

      # shellcheck disable=SC2086,SC2154
      printf '         cn: \e['${trgb_3722}'m%s\e[m\n' \
             "$_ssl_domain_cn" | \
             fmt -w "$MAX_WIDTH" -s

    fi

    if [[ -z "$_ssl_domain_san" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         san: <empty>\n'

    else

      # shellcheck disable=SC2086,SC2154
      printf '         san: \e['${trgb_3812}'m%s\e[m\n' \
             "$_ssl_domain_san" | \
             fmt -w "$MAX_WIDTH" -s

    fi

    # Check SNI vs without-SNI.
    if [[ "$_ssl_domain_names" == "$_ssl_domain_names_non_sni" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         sni: \e['${trgb_3200}'m%s\e[m\n' \
             "match"

    elif [[ -z "$_ssl_domain_cert_non_sni" ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         sni: \e['${trgb_3100}'m%s\e[m\n' \
             "no peer certificate available"

    else

      # shellcheck disable=SC2086,SC2154
      printf '         sni: \e['${trgb_3100}'m%s\e[m\n' \
             "not match"

    fi

    if [[ "$_equal_state" -eq 1 ]] ; then

      # shellcheck disable=SC2086,SC2154
      printf '         validity: \e['${trgb_3200}'m%s\e[m\n' \
             "match"

    else

      # shellcheck disable=SC2086,SC2154
      printf '         validity: \e['${trgb_3100}'m%s\e[m\n' \
             "is not valid (hostname mismatch)"

      _validity_state="1"

    fi

  fi

  return $_STATE

}
