#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-05-05; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.live.builder
# SPDX-Security-Contact: security@coresecret.eu

guard_sourcing

#######################################
# Wrapper for accompanying all CISS.debian.hardening features into the Live ISO image.
# Globals:
#   ARY_HANDLER_JUMPHOST
#   ARY_HANDLER_JUMPHOST_UNIQUE
#   VAR_ARCHITECTURE
#   VAR_HANDLER_BUILD_DIR
#   VAR_SSHPORT
#   VAR_SSHPUBKEY
#   VAR_WORKDIR
# Arguments:
#   None
#######################################
hardening_ultra() {
  # shellcheck disable=SC2164
  cd "${VAR_WORKDIR}"


  ### ./config/bootloaders
  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/bootloaders ... \e[0m\n"

  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/bootloaders" ]]; then

    mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/bootloaders"
    cp -af ./config/bootloaders "${VAR_HANDLER_BUILD_DIR}/config"

  else

    cp -af ./config/bootloaders "${VAR_HANDLER_BUILD_DIR}/config"

  fi

  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/bootloaders done.\e[0m\n"


  ### ./config/includes.binary
  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/includes.binary ... \e[0m\n"

  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/includes.binary/boot/grub" ]]; then

    mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/includes.binary/boot/grub"
    cp -af ./config/includes.binary "${VAR_HANDLER_BUILD_DIR}/config"

  else

    cp -af ./config/includes.binary "${VAR_HANDLER_BUILD_DIR}/config"

  fi

  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/includes.binary done.\e[0m\n"


  ### ./config/includes.chroot
  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/includes.chroot ... \e[0m\n"

  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" ]]; then

    mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot"
    cp -af ./config/includes.chroot "${VAR_HANDLER_BUILD_DIR}/config"

  else

    cp -af ./config/includes.chroot "${VAR_HANDLER_BUILD_DIR}/config"

  fi

  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/includes.chroot done.\e[0m\n"


  ### ./config/hooks/early
  if [[ -d "${VAR_WORKDIR}/config/hooks/early" ]]; then

    printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/hooks/early ... \e[0m\n"

    if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/hooks/early" ]]; then

      mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/hooks/early"
      cp -af ./config/hooks/early "${VAR_HANDLER_BUILD_DIR}/config/hooks"

    else

      cp -af ./config/hooks/early "${VAR_HANDLER_BUILD_DIR}/config/hooks"

    fi

    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/hooks/early done.\e[0m\n"

  fi


  ### ./config/hooks/live
  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/hooks/live ... \e[0m\n"

  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/hooks/live" ]]; then

    mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/hooks/live"
    cp -af ./config/hooks/live "${VAR_HANDLER_BUILD_DIR}/config/hooks"

  else

    cp -af ./config/hooks/live "${VAR_HANDLER_BUILD_DIR}/config/hooks"

  fi

  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/hooks/live done.\e[0m\n"



  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Copying ./config/package-lists ... \e[0m\n"
  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/package-lists" ]]; then
    mkdir -p "${VAR_HANDLER_BUILD_DIR}/config/package-lists"
  fi
  cp -af ./config/package-lists/live.list.common.chroot "${VAR_HANDLER_BUILD_DIR}/config/package-lists/live.list.chroot"

  case "${VAR_ARCHITECTURE}" in
    amd64)
      declare arch_list="./config/package-lists/live.list.amd64.chroot"
      declare arch_comment="# amd64 specific packages"
      ;;
    arm64)
      declare arch_list="./config/package-lists/live.list.arm64.chroot"
      declare arch_comment="# arm64 specific packages"
      ;;
    *)
      printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ ❌ Unsupported architecture '%s'.\e[0m\n" "${VAR_ARCHITECTURE}"
      exit 1
      ;;
  esac

  declare pkgs
    # shellcheck disable=SC2312
    mapfile -t pkgs < <(
    grep -v '^\s*#' "${arch_list}" | sed '/^\s*$/d'
  )

  awk -v comment="${arch_comment}" -v n_pkgs="${#pkgs[@]}" -v pkgs="$(printf '%s\n' "${pkgs[@]}")" '
    BEGIN {
      split(pkgs, pkg_arr, "\n")
      inserted = 0
    }
    {
    # Detect the vim-modeline (last line marker)
    if ($0 ~ /^# vim:.*$/ && !inserted) {
      print comment
      for (i = 1; i <= length(pkg_arr); i++) {
        print pkg_arr[i]
      }
      inserted = 1
    }
    print
    }
    ' "${VAR_HANDLER_BUILD_DIR}/config/package-lists/live.list.chroot" > temp && mv temp "${VAR_HANDLER_BUILD_DIR}/config/package-lists/live.list.chroot"
  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Copying ./config/package-lists done.\e[0m\n"

  printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Updating SSH Keys, Ports ... \e[0m\n"
  if [[ ! -d "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"  ]]; then

    mkdir -p  "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
    cp -af "${VAR_SSHPUBKEY}/authorized_keys" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
    chmod 0600 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/authorized_keys"
    chown root:root "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/authorized_keys"

    declare -r sshport="${VAR_SSHPORT:-22}"

    sed -i "s|^port      = MUST_BE_SET|port      = ${sshport}|" "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/9950_fail2ban_hardening.chroot"
    sed -i "s|^declare -r SSHPORT=\"MUST_BE_SET\"|declare -r SSHPORT=\"${sshport}\"|" "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/0900_ufw_setup.chroot"
    sed -i "s|^Port MUST_BE_CHANGED|Port ${sshport}|" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc/ssh/sshd_config"

    if [[ ${#ARY_HANDLER_JUMPHOST[@]} -gt 0 ]]; then

      declare file="${VAR_HANDLER_BUILD_DIR}/config/hooks/live/0900_ufw_setup.chroot"
      sed -i "/^ufw allow in \"\${SSHPORT}\"\/tcp comment 'Incoming SSH (Custom-Port)'$/d" "${file}"
      declare line
      # shellcheck disable=SC2312
      line=$(grep -n '^ufw default deny forward$' "${file}" | cut -d: -f1)

      if [[ -z "${line}" ]]; then
        printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ ❌'ufw default deny forward' not found in: '%s'\e[0m\n" "${file}" >&2
        exit 1
      fi

      declare host
      for host in "${ARY_HANDLER_JUMPHOST_UNIQUE[@]}"; do
        ((line++))
        sed -i "${line}a ufw allow from ${host} to any port ${sshport} proto tcp comment \"Incoming SSH ([${host}]:${sshport})\"" "${file}"
      done
    fi

  else

    cp -af "${VAR_SSHPUBKEY}/authorized_keys" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
    chmod 0600 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/authorized_keys"
    chown root:root "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/authorized_keys"

    declare -r sshport="${VAR_SSHPORT:-22}"

    sed -i "s|^port      = MUST_BE_SET|port      = ${sshport}|" "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/9950_fail2ban_hardening.chroot"
    sed -i "s|^declare -r SSHPORT=\"MUST_BE_SET\"|declare -r SSHPORT=\"${sshport}\"|" "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/0900_ufw_setup.chroot"
    sed -i "s|^Port MUST_BE_CHANGED|Port ${sshport}|" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc/ssh/sshd_config"

    if [[ ${#ARY_HANDLER_JUMPHOST_UNIQUE[@]} -gt 0 ]]; then

      declare file="${VAR_HANDLER_BUILD_DIR}/config/hooks/live/0900_ufw_setup.chroot"
      sed -i "/^ufw allow in \"\${SSHPORT}\"\/tcp comment 'Incoming SSH (Custom-Port)'$/d" "${file}"
      declare line
      # shellcheck disable=SC2312
      line=$(grep -n '^ufw default deny forward$' "${file}" | cut -d: -f1)

      if [[ -z "${line}" ]]; then
        printf "\e[91m❌ Error: 'ufw default deny forward' not found in: '%s'\e[0m\n" "${file}" >&2
        exit 1
      fi

      declare host
      for host in "${ARY_HANDLER_JUMPHOST_UNIQUE[@]}"; do
        ((line++))
        sed -i "${line}a ufw allow from ${host} to any port ${sshport} proto tcp comment \"Incoming SSH ([${host}]:${sshport})\"" "${file}"
      done
    fi
  fi
  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Updating SSH Keys, Ports done. \e[0m\n"

  if [[ -f "${VAR_WORKDIR}/hosts.allow" ]]; then
    printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 SSH Hardening Ultra ... \e[0m\n"
    cp -af "${VAR_WORKDIR}/hosts.allow" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc"
    cp -af "${VAR_WORKDIR}/hosts.deny" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc"
    chmod 0644 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc/hosts.allow"
    chmod 0644 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc/hosts.deny"
    rm -f "${VAR_WORKDIR}/hosts.allow"
    rm -f "${VAR_WORKDIR}/hosts.deny"
    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ SSH Hardening Ultra done.\e[0m\n"
  fi

  if ((${#ARY_HANDLER_JUMPHOST[@]} > 0)); then
    printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 Updating fail2ban Jumphosts IPs ... \e[0m\n"
    # Join array entries with spaces, preserving any newlines
    declare ips="${ARY_HANDLER_JUMPHOST[*]}"
    # Flatten to a single line and strip literal brackets []
    declare flat_ips
    # shellcheck disable=SC2312
    flat_ips=$(printf "%s" "${ips}" | tr '\n' ' ' | tr -d '[]')
    # flat_ips now contains e.g., "123.128.111.42 2a03:ffff:0815:4711:... 2a03:.../64"

    # Perform an in-place replacement of MUST_BE_SET with the cleaned list
    sed -i -e "s|^\(ignoreip[[:space:]]*=[[:space:]]*127\.0\.0\.0/8 ::1[[:space:]]*\)MUST_BE_SET|\1${flat_ips}|" \
        "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/9950_fail2ban_hardening.chroot"
    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Updating fail2ban Jumphosts IPs done. \e[0m\n"
  else
    printf "\e[93m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 No jump hosts configured, removing placeholder ... \e[0m\n"
    sed -i \
        -e "s|^\(ignoreip[[:space:]]*=[[:space:]]*127\.0\.0\.0/8 ::1\)[[:space:]]*MUST_BE_SET|\1|" \
        -e "s|\(ignoreip[[:space:]]*=[[:space:]]*127\.0\.0\.0/8 ::1\)[[:space:]]*$|\1|" \
        "${VAR_HANDLER_BUILD_DIR}/config/hooks/live/9950_fail2ban_hardening.chroot"
    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ Placeholder removed. \e[0m\n"
  fi
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
