#!/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: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1
# 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 || return "${ERR_GUARD_SRCE}"

#######################################
# Argument Parser.
# Globals:
#   ARY_HANDLER_JUMPHOST
#   ARY_HANDLER_NETCUP_IPV6
#   VAR_AGE
#   VAR_AGE_KEY
#   VAR_ARCHITECTURE
#   VAR_BUILD_LOG
#   VAR_EARLY_DEBUG
#   VAR_HANDLER_AUTOBUILD
#   VAR_HANDLER_BUILD_DIR
#   VAR_HANDLER_CDI
#   VAR_HANDLER_DHCP
#   VAR_HANDLER_ISO_COUNTER
#   VAR_HANDLER_NETCUP_IPV6
#   VAR_HANDLER_PRIORITY
#   VAR_HANDLER_SPLASH
#   VAR_HANDLER_STA
#   VAR_HASHED_PWD
#   VAR_ISO8601
#   VAR_LUKS
#   VAR_LUKS_KEY
#   VAR_REIONICE_CLASS
#   VAR_REIONICE_PRIORITY
#   VAR_SIGNER
#   VAR_SIGNING_KEY
#   VAR_SIGNING_KEY_FPR
#   VAR_SIGNING_KEY_PASS
#   VAR_SSHFP
#   VAR_SSHPORT
#   VAR_SSHPUBKEY
#   VAR_SUITE
# Arguments:
#   None
# Returns:
#   0: on success
#   ERR_ARG_MSMTCH: on failure
#   ERR_CONTROL_CT: on failure
#   ERR_MISS_PWD_F: on failure
#   ERR_MISS_PWD_P: on failure
#   ERR_NOTABSPATH: on failure
#   ERR_OWNS_PWD_F: on failure
#   ERR_PASS_LENGH: on failure
#   ERR_PASS_PLICY: on failure
#   ERR_REIONICE_P: on failure
#   ERR_REIO_C_VAL: on failure
#   ERR_REIO_P_VAL: on failure
#   ERR_RENICE_PRI: on failure
#   ERR_RGHT_PWD_F: on failure
#   ERR_SPLASH_PNG: on failure
#   ERR__SSH__PORT: on failure
#######################################
arg_parser() {
  while [[ $# -gt 0 ]]; do

    declare argument="${1}"

      case "${argument,,}" in

        -a=* | --autobuild=*)
          shift 1
          ;;

        -c | --contact)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --contact MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          shift 1
          ;;

        -h | --help)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --help MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          shift 1
          ;;

        -v | --version)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --version MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          shift 1
          ;;

        --architecture)
          if [[ "${2}" == "amd64" || "${2}" == "arm64" ]]; then
            # shellcheck disable=SC2034
            declare -gx VAR_ARCHITECTURE="${2}"
            shift 2
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --architecture MUST be 'amd64' or 'arm64'.\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          ;;

        --build-directory)
          declare -gx VAR_HANDLER_BUILD_DIR="${2}"
          if [[ ! "${VAR_HANDLER_BUILD_DIR}" =~ ^/ ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --build-directory MUST be an absolute path. Got: '%s'\n" "${VAR_HANDLER_BUILD_DIR}" >&2
            exit "${ERR_NOTABSPATH}"
          fi
          declare -gx VAR_BUILD_LOG="${VAR_HANDLER_BUILD_DIR}/cdlb_${VAR_ISO8601}_build.log"
          shift 2
          ;;

        --cdi)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --cdi MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          # shellcheck disable=SC2034
          declare -g VAR_HANDLER_CDI="true"
          shift 1
          ;;

        --change-splash )
          if [[ "${2}" == "club" || "${2}" == "hexagon" ]]; then
            # shellcheck disable=SC2034
            declare -g VAR_HANDLER_SPLASH="${2}"
            shift 2
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --change-splash MUST be 'club' or 'hexagon'.\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_SPLASH_PNG}"
          fi
          ;;

        --cicd)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --cicd MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          # shellcheck disable=SC2034
          declare -g VAR_GITEA_RUNNER="true"
          shift 1
          ;;

        --control)
          if [[ -n "${2-}" ]]; then
            # shellcheck disable=SC2034
            declare -g VAR_HANDLER_ISO_COUNTER="${2}"
            shift 2
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --control MUST be provided with a Parameter.\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_CONTROL_CT}"
          fi
          ;;

        --debug)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --debug MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          shift 1
          ;;

        --dhcp-centurion)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --dhcp-centurion MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          # shellcheck disable=SC2034
          declare -gi VAR_HANDLER_DHCP=1
          shift 1
          ;;

        --jump-host)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            declare -i count=0
            shift
            while [[ "${#}" -gt 0 && "${1}" != -* && count -lt 10 ]]; do
              # shellcheck disable=SC2034
              declare -g ARY_HANDLER_JUMPHOST+=("$1")
              count=$((count + 1))
              shift
            done
            while [[ "${#}" -gt 0 && "${1}" != -* ]]; do
              shift
            done
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --jump-host MUST contain one or up to ten IPs.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          ;;

        --key_age=*)
          # shellcheck disable=SC2034
          declare -gx VAR_AGE="true"
          # shellcheck disable=SC2034
          declare -gx VAR_AGE_KEY="${1#*=}"
          shift 1
          ;;

        --key_luks=*)
          # shellcheck disable=SC2034
          declare -gx VAR_LUKS="true"
          # shellcheck disable=SC2034
          declare -gx VAR_LUKS_KEY="${1#*=}"
          shift 1
          ;;

        --log-statistics-only)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --log-statistics-only MUST NOT be followed by an argument.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          # shellcheck disable=SC2034
          declare -gi VAR_HANDLER_STA=1
          shift 1
          ;;

        --provider-netcup-ipv6)
          if [[ -n "${2-}" && "${2}" != -* ]]; then
            declare -i count=0
            # shellcheck disable=SC2034
            declare -g VAR_HANDLER_NETCUP_IPV6="true"
            shift
            while [[ "${#}" -gt 0 && "${1}" != -* && count -lt 1 ]]; do
              declare cleaned="${1//[\[\]]/}"
              # shellcheck disable=SC2034
              declare -g ARY_HANDLER_NETCUP_IPV6+=("${cleaned}")
              count=$((count + 1))
              shift
            done
            while [[ "${#}" -gt 0 && "${1}" != -* ]]; do
              shift
            done
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --provider-netcup-ipv6 MUST provide one IPv6.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_ARG_MSMTCH}"
          fi
          ;;

        --renice-priority)
          if [[ -n ${2-} && ${2} =~ ^-?[0-9]+$ && ${2} -ge -19 && ${2} -le 19 ]]; then
            # shellcheck disable=SC2034
            VAR_HANDLER_PRIORITY="$2"
            shift 2
          else
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --renice-priority MUST an integer between '-19' and '19'.\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_RENICE_PRI}"
          fi
          ;;

        --reionice-priority)
          if [[ -z "${2-}" ]]; then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --reionice-priority no values provided.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_REIONICE_P}"
          else
            if [[ "${2}" =~ ^[1-3]$ ]]; then
              # shellcheck disable=SC2034
              VAR_REIONICE_CLASS="${2}"
              if [[ -z "${3-}" ]]; then
                :
              else
                if [[ "${3}" =~ ^[0-7]$ ]]; then
                  VAR_REIONICE_PRIORITY="${3}"
                else
                  if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
                  printf "\e[91m❌ Error: --reionice-priority PRIORITY MUST be an integer between '0' and '7'.\e[0m\n" >&2
                  read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
                  exit "${ERR_REIO_P_VAL}"
                fi
              fi
            else
              if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
              printf "\e[91m❌ Error: --reionice-priority CLASS MUST be an integer between '1' and '3'.\e[0m\n" >&2
              read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
              exit "${ERR_REIO_C_VAL}"
            fi
          fi
          if [[ -n ${VAR_REIONICE_PRIORITY} ]]; then
            shift 3
          else
            shift 2
          fi
          ;;

        --root-password-file)
          declare pw_file="${2}"

          if [[ -z "${pw_file}" ]]; then

            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --root-password-file missing password file path argument.\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_MISS_PWD_P}"

          fi

          if [[ ! -f "${pw_file}" ]]; then

            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --root-password-file password file '%s' does not exist.\e[0m\n" "${pw_file}" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_MISS_PWD_F}"

          fi

          declare owner
          owner=$(stat -c '%U:%G' "${pw_file}")
          if [[ "${owner}" != "root:root" ]]; then
            chown root:root "${pw_file}" || {
              if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
              printf "\e[91m❌ Error: --root-password-file failed to set owner root:root on '%s'.\e[0m\n" "${pw_file}" >&2
              # shellcheck disable=SC2162
              read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
              exit "${ERR_OWNS_PWD_F}"
            }
          fi

          declare perms
          perms=$(stat -c '%a' "${pw_file}")
          if [[ "${perms}" -ne 400 ]]; then
            chmod 0400 "${pw_file}" || {
              if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
              printf "\e[91m❌ Error: --root-password-file failed to set permissions 0400 on '%s'.\e[0m\n" "${pw_file}" >&2
              # shellcheck disable=SC2162
              read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
              exit "${ERR_RGHT_PWD_F}"
            }
          fi

          declare plaintext_pw
          ### No tracing for security reasons ----------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x

          if ! IFS= read -r plaintext_pw < "${pw_file}"; then
            :
          fi

          ### Turn on tracing again --------------------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x

          declare pw_length
          pw_length=${#plaintext_pw}
          if (( pw_length < 42 || pw_length > 64 )); then
            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --root-password-file password MUST be between 42 and 64 characters (got %d).\e[0m\n" "${pw_length}" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_PASS_LENGH}"
          fi

          ### No tracing for security reasons ----------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x

          if [[ "${plaintext_pw}" == *\"* ]]; then

            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi

            printf "\e[91m❌ Error: --root-password-file password MUST NOT contain double quotes (\").\e[0m\n" >&2
            # shellcheck disable=SC2162
            read -p  $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR_PASS_PLICY}"

          fi

          ### Turn on tracing again --------------------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x

          declare salt
          set +o pipefail
          while :; do
            salt=$(tr -dc 'A-Za-z0-9' </dev/random | head -c 16)
            [[ ${#salt} -eq 16 ]] && break
          done
          set -o pipefail

          declare hash_temp
          ### No tracing for security reasons ----------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x

          hash_temp=$(mkpasswd --method=sha-512 --salt="${salt}" --rounds=8388608 "${plaintext_pw}")

          ### Turn on tracing again --------------------------------------------------------------------------------------------
          [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x

          # shellcheck disable=SC2034
          declare -g VAR_HASHED_PWD="${hash_temp}"
          unset hash_temp plaintext_pw

          sync
          if shred -fzu -n 5 "${pw_file}" > /dev/null 2>&1; then
            printf "\e[92m✅ Password file '%s': shred -fzu -n 5 >> done. \e[0m\n" "${pw_file}" > /dev/null 2>&1
          else
            printf "\e[91m❌ Password file '%s': shred -fzu -n 5 >> NOT successful. \e[0m\n" "${pw_file}" > /dev/null 2>&1
          fi
          sync

          shift 2
          ;;

        --signing_ca=*)
          # shellcheck disable=SC2034
          declare -gx VAR_SIGNING_CA="${1#*=}"
          shift 1
          ;;

        --signing_key=*)
          # shellcheck disable=SC2034
          declare -gx VAR_SIGNER="true"
          # shellcheck disable=SC2034
          declare -gx VAR_SIGNING_KEY="${1#*=}"
          shift 1
          ;;

        --signing_key_fpr=*)
          # shellcheck disable=SC2034
          declare -gx VAR_SIGNING_KEY_FPR="${1#*=}"
          shift 1
          ;;

        --signing_key_pass=*)
          # shellcheck disable=SC2034
          declare -gx VAR_SIGNING_KEY_PASS="${1#*=}"
          shift 1
          ;;

        --ssh-port)
          if [[ -n "${2-}" && "${2}" =~ ^-?[0-9]+$ && "${2}" -ge 1 && "${2}" -le 65535 ]]; then

            # shellcheck disable=SC2034
            declare -gix VAR_SSHPORT="${2}"
            shift 2

          else

            if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
            printf "\e[91m❌ Error: --ssh-port MUST be an integer between '1' and '65535'.\e[0m\n" >&2
            read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
            exit "${ERR__SSH__PORT}"

          fi
          ;;

        --sshfp)
          # shellcheck disable=SC2034
          declare -gx VAR_SSHFP="true"
          shift 1
          ;;

        --ssh-pubkey)
          # shellcheck disable=SC2034
          declare -gx VAR_SSHPUBKEY="${2}"
          shift 2
          ;;

        --trixie)
          # shellcheck disable=SC2034
          declare -gx VAR_SUITE="trixie"
          shift 1
          ;;

        *)
          if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
          usage
          ;;
    esac

  done

  return 0
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f arg_parser
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
