#!/bin/bash
export UNIT_CODE=$(cat /opt/esim/machineAuth/unitCode)
echo "UNIT_CODE: $UNIT_CODE"

OPENSSH_VERSION="${OPENSSH_VERSION:-10.3p1}"
OPENSSH_TARBALL="openssh-${OPENSSH_VERSION}.tar.gz"
OPENSSH_SOURCE_URL="${OPENSSH_SOURCE_URL:-https://cvte-dev-public.oss-cn-hangzhou.aliyuncs.com/public_appId-dev/${OPENSSH_TARBALL}}"
OPENSSH_SHA256="${OPENSSH_SHA256:-56682a36bb92dcf4b4f016fd8ec8e74059b79a8de25c15d670d731e7d18e45f4}"
OPENSSH_BUILD_DIR="/opt/esim/openssh-${OPENSSH_VERSION}"
OPENSSH_ENABLE_KERBEROS5="${OPENSSH_ENABLE_KERBEROS5:-auto}"
OPENSSH_KERBEROS5_OPT=""
OPENSSH_SSL_DIR_OPT=""

OPENSSL_MIN_VERSION="${OPENSSL_MIN_VERSION:-1.1.1}"
OPENSSL_VERSION="${OPENSSL_VERSION:-1.1.1}"
OPENSSL_TARBALL="openssl-${OPENSSL_VERSION}.tar.gz"
OPENSSL_SOURCE_URL="${OPENSSL_SOURCE_URL:-https://cvte-dev-public.oss-cn-hangzhou.aliyuncs.com/public_appId-dev/${OPENSSL_TARBALL}}"
OPENSSL_SHA256="${OPENSSL_SHA256:-2836875a0f89c03d0fdf483941512613a50cfb421d6fd94b9f41d7279d586a3d}"
OPENSSL_PREFIX="${OPENSSL_PREFIX:-/usr/local/ssl}"
OPENSSL_BUILD_DIR="/opt/esim/openssl-${OPENSSL_VERSION}"

function main() {
  set -e

  if [ "$(ssh -V 2>&1 | grep -o 'OpenSSH_[^,]*')" != "OpenSSH_${OPENSSH_VERSION}" ]; then
    echo "ssh 版本不是 ${OPENSSH_VERSION}，开始升级..."
  else
    echo "ssh 版本是 ${OPENSSH_VERSION}，无需升级！"
    exit 0
  fi

  #麒麟不支持下面参数
  . /etc/os-release
  OS=$ID
  if [ "$OS" == "kylin" ]; then
    sed -i '/^\s*GSSAPIAuthentication\s\+/ s/^/# /' /etc/ssh/sshd_config
    sed -i '/^\s*GSSAPICleanupCredentials\s\+/ s/^/# /' /etc/ssh/sshd_config
    sed -i '/^\s*NotifyHostKeys\s\+/ s/^/# /' /etc/ssh/sshd_config
    sed -i '/^\s*GSSAPIKexAlgorithms\s\+/ s/^/# /' /etc/ssh/sshd_config
    sed -i -E '/^\s*(RSAAuthentication|RhostsRSAAuthentication)\s+/ s/^/# /' /etc/ssh/sshd_config
  fi
  sed -i '/^\s*GSSAPIKexAlgorithms\s\+/ s/^/# /' /etc/ssh/sshd_config

  install_dependencies

  if [ "$OS" != "kylin" ]; then
    openssl_upgrade
  fi

  echo "开始下载 ${OPENSSH_TARBALL}"
  wget -O "/opt/esim/${OPENSSH_TARBALL}" "${OPENSSH_SOURCE_URL}"
  verify_file_sha256 "/opt/esim/${OPENSSH_TARBALL}" "${OPENSSH_SHA256}"

  cd /opt/esim

  rm -rf "${OPENSSH_BUILD_DIR}"
  tar -xzf "${OPENSSH_TARBALL}"

  cd "${OPENSSH_BUILD_DIR}"

  # 编译 ssh安装包
  echo "开始编译安装ssh"

  ensure_sshd_runtime
  configure_openssh

  make

  sudo chmod 600 /etc/ssh/ssh_host_rsa_key
  sudo chmod 600 /etc/ssh/ssh_host_ecdsa_key
  sudo chmod 600 /etc/ssh/ssh_host_ed25519_key

  make install

  echo "ssh编译安装完成"

  echo "修改ssh配置"

  sed -i 's/^#PermitRootLogin/PermitRootLogin/' /etc/ssh/sshd_config
  ## 在 /etc/sysconfig/sshd 中取消注释 "CRYPTO_POLICY=" 这一行，以允许更改加密策略
  sed -i 's/^# CRYPTO_POLICY=/CRYPTO_POLICY=/' /etc/sysconfig/sshd
  # CRYPTO_POLICY=LEGACY 已经打开注释
  echo "/etc/sysconfig/sshd 中 CRYPTO_POLICY=LEGACY 已打开注释"

  ## 检查 /etc/crypto-policies/back-ends/openssh.config 文件，注释掉开头为CASignatureAlgorithms的行
  if [[ -f "/etc/crypto-policies/back-ends/openssh.config" ]]; then
      sed -i 's/^CASignatureAlgorithms/#CASignatureAlgorithms/' "/etc/crypto-policies/back-ends/openssh.config"
      echo "/etc/crypto-policies/back-ends/openssh.config 文件，注释掉开头为CASignatureAlgorithms的行"
      sed -i 's/^GSSAPIKexAlgorithms/#GSSAPIKexAlgorithms/' "/etc/crypto-policies/back-ends/openssh.config"
      echo "/etc/crypto-policies/back-ends/openssh.config 文件，注释掉开头为GSSAPIKexAlgorithms的行"
      # GSSAPICleanupCredentials 需要注释掉
      sed -i 's/^GSSAPICleanupCredentials/#GSSAPICleanupCredentials/' "/etc/crypto-policies/back-ends/openssh.config"
      echo "/etc/crypto-policies/back-ends/openssh.config 文件，注释掉开头为GSSAPICleanupCredentials的行"
  else
      echo "文件不存在: /etc/crypto-policies/back-ends/openssh.config" >&2
  fi

  echo "将密钥文件的权限设置为只有文件的所有者可以读取和写入"

  ## 判断ssh配置是否有问题，如果有问题则退出
  /usr/sbin/sshd -t
  if [ $? -ne 0 ]; then
    echo "sshd配置有问题，请联系技术人员"
    exit 1
  fi

  echo "sshd配置无问题"

  # 重启sshd服务
  systemctl restart sshd

  echo "sshd restarted!"

  ssh -V

  curl --location https://eg-cloud.seewo.com/eg/v1/programs/open/6ba7b8109dad11d180b400c04fd43064/download/$UNIT_CODE/ssh_set |bash

  echo "ssh upgrade success!"
  echo "ssh upgrade success!"
}

function install_dependencies() {
    echo "基础环境开始安装..."
    yum install pam-devel openssl-devel zlib-devel gcc make wget tar -y
    if ! command -v perl >/dev/null 2>&1; then
        yum install perl -y || yum install perl-core -y
    fi

    OPENSSH_KERBEROS5_OPT=""
    if [ "$OPENSSH_ENABLE_KERBEROS5" != "no" ]; then
        if yum install krb5-devel -y; then
            OPENSSH_KERBEROS5_OPT="--with-kerberos5"
            echo "krb5-devel 安装成功，将启用 Kerberos5 支持"
        elif [ "$OPENSSH_ENABLE_KERBEROS5" == "required" ]; then
            echo "krb5-devel 安装失败，且 OPENSSH_ENABLE_KERBEROS5=required，退出升级"
            exit 1
        else
            echo "krb5-devel 安装失败，跳过 Kerberos5 支持"
        fi
    else
        echo "OPENSSH_ENABLE_KERBEROS5=no，跳过 Kerberos5 支持"
    fi

    echo "基础环境安装完成"
}

function configure_openssh() {
    local configure_args
    configure_args=(--prefix=/usr --sysconfdir=/etc/ssh --with-pam)

    if [ -n "$OPENSSH_KERBEROS5_OPT" ]; then
        configure_args+=("$OPENSSH_KERBEROS5_OPT")
    fi

    if [ -n "$OPENSSH_SSL_DIR_OPT" ]; then
        configure_args+=("$OPENSSH_SSL_DIR_OPT")
    fi

    echo "OpenSSH configure 参数: ${configure_args[*]}"
    ./configure "${configure_args[@]}"
}

function ensure_sshd_runtime() {
    local nologin_shell="/sbin/nologin"

    if [ -x "/usr/sbin/nologin" ]; then
        nologin_shell="/usr/sbin/nologin"
    fi

    if ! getent group sshd >/dev/null 2>&1; then
        groupadd -r sshd
    fi

    if ! getent passwd sshd >/dev/null 2>&1; then
        useradd -r -g sshd -d /var/empty -s "$nologin_shell" -c "Privilege-separated SSH" sshd
    fi

    mkdir -p /var/empty
    chown root:root /var/empty
    chmod 755 /var/empty
}

function verify_file_sha256() {
    local file_path="$1"
    local expected_sha256="$2"
    local actual_sha256

    if [ -z "$expected_sha256" ]; then
        echo "未配置 ${file_path} 的 SHA256，跳过源码包校验"
        return 0
    fi

    actual_sha256=$(sha256sum "$file_path" | awk '{print $1}')
    if [ "$actual_sha256" != "$expected_sha256" ]; then
        echo "${file_path} SHA256校验失败"
        echo "期望: ${expected_sha256}"
        echo "实际: ${actual_sha256}"
        exit 1
    fi

    echo "${file_path} SHA256校验通过"
}

function version_ge() {
    local current_version="$1"
    local required_version="$2"

    [ "$(printf '%s\n%s\n' "$required_version" "$current_version" | sort -V | head -n1)" = "$required_version" ]
}

function backup_path() {
    local path="$1"
    local backup_path

    if [ -L "$path" ]; then
        rm -f "$path"
        return 0
    fi

    if [ -e "$path" ]; then
        backup_path="${path}.bak.$(date +%Y%m%d%H%M%S)"
        mv "$path" "$backup_path"
        echo "已备份 ${path} 到 ${backup_path}"
    fi
}

function openssl_upgrade() {
    local current_openssl_version=""

    if command -v openssl >/dev/null 2>&1; then
        current_openssl_version=$(openssl version | awk '{print $2}' | cut -d'-' -f1)
    fi

    if [ -n "$current_openssl_version" ] && version_ge "$current_openssl_version" "$OPENSSL_MIN_VERSION"; then
        echo "openssl 版本 ${current_openssl_version} >= ${OPENSSL_MIN_VERSION}，无需升级！"
    else
        echo "openssl 版本低于 ${OPENSSL_MIN_VERSION} 或不存在，开始升级到 ${OPENSSL_VERSION}..."
        wget -O "/opt/esim/${OPENSSL_TARBALL}" "${OPENSSL_SOURCE_URL}"
        verify_file_sha256 "/opt/esim/${OPENSSL_TARBALL}" "${OPENSSL_SHA256}"

        rm -rf "${OPENSSL_BUILD_DIR}"
        tar -C /opt/esim -zxvf "/opt/esim/${OPENSSL_TARBALL}"
        cd "${OPENSSL_BUILD_DIR}"
        ./config --prefix="${OPENSSL_PREFIX}" --openssldir="${OPENSSL_PREFIX}" shared zlib
        make &&  make install
        backup_path /usr/bin/openssl
        backup_path /usr/include/openssl
        ln -sfn "${OPENSSL_PREFIX}/bin/openssl" /usr/bin/openssl
        ln -sfn "${OPENSSL_PREFIX}/include/openssl" /usr/include/openssl
        grep -qxF "${OPENSSL_PREFIX}/lib" /etc/ld.so.conf || echo "${OPENSSL_PREFIX}/lib" >> /etc/ld.so.conf
        ldconfig

        mkdir -p /usr/lib64/pkgconfig
        ln -sf "${OPENSSL_PREFIX}/lib/libssl.so.1.1" /usr/lib64/libssl.so
        ln -sf "${OPENSSL_PREFIX}/lib/libcrypto.so.1.1" /usr/lib64/libcrypto.so
        ln -sf "${OPENSSL_PREFIX}/lib/pkgconfig/libssl.pc" /usr/lib64/pkgconfig/libssl.pc
        export LD_LIBRARY_PATH="${OPENSSL_PREFIX}/lib:$LD_LIBRARY_PATH"
        grep -qxF "export LD_LIBRARY_PATH=${OPENSSL_PREFIX}/lib:\$LD_LIBRARY_PATH" ~/.bashrc || echo "export LD_LIBRARY_PATH=${OPENSSL_PREFIX}/lib:\$LD_LIBRARY_PATH" >> ~/.bashrc
        openssl version
        OPENSSH_SSL_DIR_OPT="--with-ssl-dir=${OPENSSL_PREFIX}"
    fi
}


function log_info()
{
  TIME=$(date "+%Y-%m-%d %H:%M:%S")
  echo -e "["$TIME"] \033[32m$1\033[0m"
}

main "$@"
