#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-10-11; 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
set -Ceuo pipefail

__umask=$(umask)
umask 0077

#######################################
# Pre allocates space for LUKS container.
# Globals:
#   None
# Arguments:
#   1: LUKS Container
#   2: LUKS Container Size
# Returns:
#   0: on success
#   42: on failure
#######################################
preallocate() {
  declare file="$1" size="$2"
  declare -i blocksize=$((8*1024*1024))
  declare -i blockcounter=$(( (size + blocksize - 1) / blocksize ))

  if fallocate -l "${size}" -- "${file}" 2>/dev/null; then

    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ [fallocate -l %s -- %s] successful. \e[0m\n" "${size}" "${file}"
    return 0

  else

    printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ ❌ [fallocate -l %s -- %s] NOT successful. \e[0m\n" "${size}" "${file}"

  fi

  if dd if=/dev/zero of="${file}" bs="${blocksize}" count="${blockcounter}" status=progress conv=fsync; then

    printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ [dd if=/dev/zero of=%s bs=%s count=%s status=progress conv=fsync ] successful. \e[0m\n" "${file}" "${blocksize}" "${blockcounter}"
    return 0

  else

    printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ ❌ [dd if=/dev/zero of=%s bs=%s count=%s status=progress conv=fsync ] NOT successful. \e[0m\n" "${file}" "${blocksize}" "${blockcounter}"
    return 42

  fi
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f preallocate

printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 '%s' starting ... \e[0m\n" "${0}"

declare ROOTFS="${VAR_HANDLER_BUILD_DIR}/binary/live/filesystem.squashfs"
declare LUKSFS="${VAR_HANDLER_BUILD_DIR}/binary/live/ciss_rootfs.crypt"
declare KEYFD=""

# shellcheck disable=SC2155
declare -i SIZE=$(stat -c%s -- "${ROOTFS}")

### Safety margin:
#   - LUKS2-Header and Metadata
#   - dm-integrity Overhead (Tags and Journal)
#   - Filesystem-Slack
declare -i OVERHEAD_FIXED=$((64 * 1024 * 1024))
declare -i OVERHEAD_PCT=3
declare -i ALIGN_BYTES=$(( 2048 * 1024 ))
declare -i BASE_SIZE=$(( SIZE + OVERHEAD_FIXED + (SIZE * OVERHEAD_PCT / 100) ))
declare -i LUKSFS_SIZE=$(( ( (BASE_SIZE + ALIGN_BYTES - 1) / ALIGN_BYTES ) * ALIGN_BYTES ))

preallocate "${LUKSFS}" "${LUKSFS_SIZE}"

exec {KEYFD}<"${VAR_TMP_SECRET}/luks.txt"

cryptsetup luksFormat \
  --batch-mode \
  --cipher aes-xts-plain64 \
  --integrity hmac-sha512 \
  --iter-time 1000 \
  --key-file "/proc/$$/fd/${KEYFD}" \
  --key-size 512 \
  --label crypt_liveiso \
  --luks2-keyslots-size 16777216 \
  --luks2-metadata-size 4194304 \
  --pbkdf argon2id \
  --sector-size 4096 \
  --type luks2 \
  --use-random \
  --verbose \
  "${LUKSFS}"

cryptsetup open --key-file "/proc/$$/fd/${KEYFD}" "${LUKSFS}" crypt_liveiso

# shellcheck disable=SC2155
declare -i LUKS_FREE=$(blockdev --getsize64 /dev/mapper/crypt_liveiso)
declare -i SQUASH_FS="${SIZE}"

if (( LUKS_FREE >= SQUASH_FS )); then

  printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ LUKS_FREE '%s' >= SQUASH_FS '%s' \e[0m\n" "${LUKS_FREE}" "${SQUASH_FS}"

else

  printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ LUKS_FREE '%s' <= SQUASH_FS '%s' \e[0m\n" "${LUKS_FREE}" "${SQUASH_FS}" >&2
  exit 42

fi

dd if="${ROOTFS}" of=/dev/mapper/crypt_liveiso bs=8M status=progress conv=fsync
sync
cryptsetup close crypt_liveiso

exec {KEYFD}<&-

shred -fzu -n 5 -- "${VAR_TMP_SECRET}/luks.txt"

#rm -f -- "${ROOTFS}"

umask "${__umask}"
__umask=""

printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ '%s' applied successfully. \e[0m\n" "${0}"

exit 0
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
