#!/bin/bash

## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -x
set -e

true "INFO: Currently running script: $BASH_SOURCE $@"

MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd "$MYDIR"
cd ..
cd help-steps

source pre
source colors
source variables

create-live-build-image() {
   ## Prepare live-build directory
   dist_live_build_folder="${dist_binary_build_folder}/live-build"
   mkdir -p "${dist_live_build_folder}/auto"
   pushd "${dist_live_build_folder}"

   ## Avoid errors related to /dev/null when running under Qubes OS
   if LC_ALL=C mount | grep ' on /home ' | grep -q 'nodev'; then
      $SUDO_TO_ROOT mount -o remount,rw,dev /home
   fi

   ## Install basic live-build configuration
   live_build_localrepo_location=""
   live_build_localrepo_list=""

   if [ "${build_remote_derivative_pkgs}" != 'true' ]; then
      derivative_repository_name='kicksecure'
      set_dist_build_reprepro_folder_options
      live_build_localrepo_location="${dist_apt_repository_folder}"
      live_build_localrepo_list="local main contrib non-free"
      ## Sanity test.
      test -d "${dist_apt_repository_folder}"
   fi

   $SUDO_TO_ROOT lb clean # in case there's a leftover build tree present

   mkdir -p auto

   live_build_cross_arch_config=''
   if [ "${host_architecture}" != "${dist_build_target_arch}" ]; then
      true "${green}INFO: dist_build_target_arch=${dist_build_target_arch}${reset}"
      true "${green}INFO: host_architecture=${host_architecture}${reset}"
      true "${green}INFO: Host architecture and target architecture do not match. Therefore cross-building${reset}"
      live_build_cross_arch_qemu=''
      case "${dist_build_target_arch}" in
         ## Both 32-bit ARM variants use the same emulator
         'armel'   ) live_build_cross_arch_qemu='arm';;
         'armhf'   ) live_build_cross_arch_qemu='arm';;
         'arm64'   ) live_build_cross_arch_qemu='aarch64';;
         'i386'    ) live_build_cross_arch_qemu='i386';;
         'amd64'   ) live_build_cross_arch_qemu='x86_64';;
         'mipsel'  ) live_build_cross_arch_qemu='mipsel';;
         'mips64el') live_build_cross_arch_qemu='mips64el';;
         ## Yes, the emulator for ppc64el really is ppc64le. This is not a typo.
         'ppc64el' ) live_build_cross_arch_qemu='ppc64le';;
         'riscv64' ) live_build_cross_arch_qemu='riscv64';;
         's390x'   ) live_build_cross_arch_qemu='s390x';;
      esac
      live_build_cross_arch_config="--bootstrap-qemu-arch ${dist_build_target_arch} \\
   --bootstrap-qemu-static /usr/bin/qemu-${live_build_cross_arch_qemu}-static \\"
   fi

   live_build_arch_specific_config=''
   case "${dist_build_target_arch}" in
      i386|amd64) live_build_arch_specific_config="--bootloaders 'grub-pc grub-efi' \\";;
      armel|armhf|arm64|riscv64) live_build_arch_specific_config="--bootloaders 'grub-efi' \\";;
      *) true;; # don't specify a bootloader at all, leave live-build to figure it out, if it can
   esac

   echo "#!/bin/sh

set -e

lb config noauto \\
   --apt apt-get \\
   --apt-http-proxy '${REPO_PROXY}' \\
   --apt-indices false \\
   --apt-options '${APTGETOPT[*]} --yes --allow-remove-essential' \\
   --apt-recommends false \\
   --apt-source-archives false \\
   --architecture '${dist_build_target_arch}' \\
   --archive-areas 'main contrib non-free non-free-firmware' \\
   --backports true \\
   --binary-image iso-hybrid \\
   --bootappend-live 'rd.live.overlay.overlayfs=1 boot=live components splash live-config.hostname=${dist_build_hostname} rd.live.image root=live:CDLABEL=${dist_build_type_short} rd.live.dir=live rd.live.squashimg=filesystem.squashfs' \\
   --bootappend-live-failsafe 'none' \\
   --cache false \\
   --chroot-localrepo-locations '${live_build_localrepo_location}' \\
   --chroot-localrepo-lists '${live_build_localrepo_list}' \\
   --debian-installer live \\
   --debootstrap-engine mmdebstrap \\
   --debootstrap-options '--include=ca-certificates,openssl,fasttrack-archive-keyring --variant=minbase' \\
   --debug \\
   --distribution '${dist_build_apt_stable_release}' \\
   --firmware-binary false \\
   --firmware-chroot false \\
   --image-name '${dist_build_type_short}-${dist_build_version}' \\
   --initramfs dracut-live \\
   --iso-application '${dist_build_type_short_pretty}' \\
   --iso-preparer '${dist_build_type_short_pretty} live-build; https://github.com/Kicksecure/live-build' \\
   --iso-publisher 'https://${project_clearnet}' \\
   --iso-volume '${dist_build_type_short}' \\
   --linux-packages 'linux-image linux-headers' \\
   --mirror-binary '${dist_build_apt_sources_mirror}' \\
   --mirror-binary-security '${dist_build_apt_sources_security_mirror}' \\
   --mirror-bootstrap 'deb ${dist_build_apt_sources_mirror} ${dist_build_apt_stable_release} main' \\
   --mirror-bootstrap-security 'deb ${dist_build_apt_sources_security_mirror} ${dist_build_apt_stable_release}-security main' \\
   --mirror-chroot '${dist_build_apt_sources_mirror}' \\
   --mirror-chroot-security '${dist_build_apt_sources_security_mirror}' \\
   --mirror-debian-installer '${dist_build_apt_sources_mirror}' \\
   --parent-mirror-binary '${dist_build_apt_sources_mirror}' \\
   --parent-mirror-binary-security '${dist_build_apt_sources_security_mirror}' \\
   --parent-mirror-bootstrap 'deb ${dist_build_apt_sources_mirror} ${dist_build_apt_stable_release} main' \\
   --parent-mirror-bootstrap-security 'deb ${dist_build_apt_sources_security_mirror} ${dist_build_apt_stable_release}-security main' \\
   --parent-mirror-chroot '${dist_build_apt_sources_mirror}' \\
   --parent-mirror-chroot-security '${dist_build_apt_sources_security_mirror}' \\
   --parent-mirror-debian-installer '${dist_build_apt_sources_mirror}' \\
   --verbose \\
   --zsync false \\
   ${live_build_cross_arch_config} \\
   ${live_build_arch_specific_config} \\
   \"\${@}\"" \
   | sponge -- auto/config

   chmod +x auto/config

   ## Debugging.
   bash -n auto/config
   realpath auto/config

   cp "${source_code_folder_dist}/live-build-data/live-build-config/live_build_auto_clean" auto/clean
   chmod +x auto/clean

   ## Generate initial autoconfig data (incomplete)
   lb config

   ## Install full configuration
   pushd config

   ## Apt archives
   mkdir -p archives
   echo "deb http://HTTPS///fasttrack.debian.net/debian-fasttrack/ ${dist_build_apt_stable_release}-fasttrack main contrib" | sponge -- archives/fasttrack.list.chroot
   if [ "${build_remote_derivative_pkgs}" = 'true' ]; then
      echo "deb http://HTTPS///deb.kicksecure.com ${dist_build_apt_stable_release} main contrib non-free" | sponge -- archives/kicksecuretmp.list.chroot
      cp "${source_code_folder_dist}/packages/kicksecure/repository-dist/usr/share/keyrings/derivative.asc" archives/kicksecuretmp.key.chroot
   fi

   ## Package lists
   mkdir -p package-lists
   cp "${source_code_folder_dist}/live-build-data/live-build-config/live_build_package_list_live" package-lists/live.list.chroot
   ## NOTE: This file is called 'z-kicksecure.list.chroot' because the list
   ## files are handled in alphabetical order and these packages MUST be
   ## handled last.
   cp "${source_code_folder_dist}/live-build-data/live-build-config/live_build_package_list_kicksecure" package-lists/z-kicksecure.list.chroot

   ## Replace linux-image-XXX_ARCHITECTURE_XXX and linux-headers-XXX_ARCHITECTURE_XXX with actual ${dist_build_target_arch}.
   sed -i "s/XXX_ARCHITECTURE_XXX/${dist_build_target_arch}/" package-lists/z-kicksecure.list.chroot

   case "${dist_build_target_arch}" in
      armel|armhf|arm64|mipsel|mips64el|riscv64)
         ## firmware-nonfreedom unsupported because of intel-microcode and amd64-microcode
         ## no VirtualBox utilities
         ## no supoprt for livepatch, thus doesn't support tirdad
         sed -i 's/XXX_FIRMWARE_XXX//' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_VIRTUALBOX_UTILS_XXX//' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_DUMMY_TIRDAD_XXX/dummy-dependency-tirdad/' package-lists/z-kicksecure.list.chroot
         ;;
      ppc64el|s390x)
         ## firmware-nonfreedom unsupported because of intel-microcode and amd64-microcode
         ## no VirtualBox utilities
         ## supports livepatch, thus tirdad should work
         sed -i 's/XXX_FIRMWARE_XXX//' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_VIRTUALBOX_UTILS_XXX//' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_DUMMY_TIRDAD_XXX//' package-lists/z-kicksecure.list.chroot
         ;;
      i386)
         ## firmware-nonfreedom supported, intel-microcode and amd64-microcode both exist
         ## Yes, amd64-microcode exists on i386.
         ## VirtualBox utilities exist
         ## no supoprt for livepatch, thus doesn't support tirdad
         sed -i 's/XXX_FIRMWARE_XXX/firmware-nonfreedom/' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_VIRTUALBOX_UTILS_XXX/virtualbox-guest-utils\nvirtualbox-guest-x11/' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_DUMMY_TIRDAD_XXX/dummy-dependency-tirdad/' package-lists/z-kicksecure.list.chroot
         ;;
      amd64)
         ## Supports everything
         sed -i 's/XXX_FIRMWARE_XXX/firmware-nonfreedom/' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_VIRTUALBOX_UTILS_XXX/virtualbox-guest-utils\nvirtualbox-guest-x11/' package-lists/z-kicksecure.list.chroot
         sed -i 's/XXX_DUMMY_TIRDAD_XXX//' package-lists/z-kicksecure.list.chroot
         ;;
   esac

   ## Apt configuration
   mkdir -p apt
   live_build_package_pins="Package: calamares
Pin: release a=${dist_build_apt_stable_release}-backports
Pin-Priority: 900"
   echo "${live_build_package_pins}" | sponge -- apt/preferences

   ## Branding and GRUB configuration
   mkdir -p bootloaders
   cp -r "${source_code_folder_dist}/live-build-data/grub-config" bootloaders/grub-pc
   mkdir -p includes.installer/usr/share/graphics
   cp "${source_code_folder_dist}/live-build-data/d-i-branding"/* includes.installer/usr/share/graphics/
   mkdir -p 'includes.installer/usr/share/themes/Clearlooks/gtk-2.0'
   cp "${source_code_folder_dist}/live-build-data/d-i-theme/gtkrc" includes.installer/usr/share/themes/Clearlooks/gtk-2.0/gtkrc

   ## d-i config
   cp "${source_code_folder_dist}/live-build-data/preseed.cfg" includes.installer/preseed.cfg

   popd

   ## Parse full configuration
   lb config
   lb config --dump
   lb config --validate

   if [ "$build_dry_run" = "true" ]; then
      true "${bold}${cyan}INFO: dry-run, skipping the rest of $BASH_SOURCE. ${reset}"
      ## Cannot be completely empty or torrent creation would later fail during prepare-release step.
      echo "dummy" | sponge -- "${binary_image_iso_file}"
      return 0
   fi

   ## Build ISO bootstrap
   if ! $SUDO_TO_ROOT lb bootstrap --verbose --debug; then
      error "${bold}${red}ERROR: Live build bootstrap stage failed!${reset}"
   fi

   CHROOT_FOLDER="$(realpath chroot)"

   ## Keep security-misc from erroring out during installation
   $SUDO_TO_ROOT mkdir -p "${CHROOT_FOLDER}/var/lib/security-misc"
   $SUDO_TO_ROOT touch "${CHROOT_FOLDER}/var/lib/security-misc/skip_install_check"

   ## Make dist-base-files create a user as it should
   $SUDO_TO_ROOT mkdir -p "${CHROOT_FOLDER}/var/lib/dist-base-files"
   $SUDO_TO_ROOT touch "${CHROOT_FOLDER}/var/lib/dist-base-files/live_build"

   ## Ensure kernel is configured properly, we aren't using grml-debootstrap so we have to do this ourselves
   $SUDO_TO_ROOT mkdir -p "${CHROOT_FOLDER}/etc"
   $SUDO_TO_ROOT cp "${source_code_folder_dist}/live-build-data/live-build-config/live_build_kernel_img_conf" "${CHROOT_FOLDER}/etc/kernel-img.conf"

   ## Build ISO chroot
   if ! $SUDO_TO_ROOT lb chroot --verbose --debug; then
      error "${bold}${red}ERROR: Live build chroot stage failed!${reset}"
   fi

   ## repository-dist-initializer
   ## requires: variable CHROOT_FOLDER
   repository_dist_initializer_setup

   if [ "${build_remote_derivative_pkgs}" = 'true' ]; then
      ## Get rid of temporary repo and key
      safe-rm config/archives/kicksecuretmp.list.chroot
      safe-rm config/archives/kicksecuretmp.key.chroot
   fi

   ## Extract bootloader configuration and put it in the live-build config
   ## live-build unmounts several important directories when it exits a stage,
   ## but we actually need some of those here, so we have to manually remount
   ## them.
   $SUDO_TO_ROOT mount --bind /dev "${CHROOT_FOLDER}/dev"
   $SUDO_TO_ROOT mount --bind /dev/pts "${CHROOT_FOLDER}/dev/pts"
   $SUDO_TO_ROOT mount --bind /sys "${CHROOT_FOLDER}/sys"
   $SUDO_TO_ROOT mount --bind /proc "${CHROOT_FOLDER}/proc"

   live_build_bootloader_config="$($SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" grub-mkconfig \
      | grep '^\s*linux' \
      | head -n1 \
      | cut -d' ' -f5-)"

   sed -i "s/LB_BOOTAPPEND_LIVE=\"\(.*\)\"/LB_BOOTAPPEND_LIVE=\"\1 ${live_build_bootloader_config}\"/" config/binary

   ## Get rid of the temp bootloader, we don't need it anymore and it will
   ## cause installation issues
   $SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" apt-get "${APTGETOPT[@]}" --yes purge grub-efi*
   $SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" apt-get "${APTGETOPT[@]}" --yes autopurge

   $SUDO_TO_ROOT umount "${CHROOT_FOLDER}/proc"
   $SUDO_TO_ROOT umount "${CHROOT_FOLDER}/sys"
   $SUDO_TO_ROOT umount "${CHROOT_FOLDER}/dev/pts"
   $SUDO_TO_ROOT umount "${CHROOT_FOLDER}/dev"

   ## Add debian-installer
   if ! $SUDO_TO_ROOT lb installer --verbose --debug; then
      error "${bold}${red}ERROR: Live build debian-installer stage failed!${reset}"
   fi

   ## Get rid of a bad sources.list file, this has apt-cacher-ng junk embedded ('http://HTTPS///' / folder 'build_sources/')
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/etc/apt/sources.list"
   ## Don't keep recommended packages from installing, apparently live-build's way of doing this ends up persistent!
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/etc/apt/apt.conf.d/00recommends"
   ## Don't force Dracut to make reproducible images, the default is to not use reproducible mode, this is most likely a live-build artifact
   ## security-misc implements sets dracut's 'reproducible=yes' setting anyhow in file:
   ## ./packages/kicksecure/security-misc/etc/dracut.conf.d/30-security-misc.conf
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/etc/dracut.conf.d/50-reproducible.conf"
   ## Blank file most likely left by live-build
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/etc/udev/rules.d/70-persistent-cd.rules"
   ## We inserted this earlier to prevent security-misc from erroring out, but it could actually cause problems now, and it's no longer needed
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/var/lib/security-misc/skip_install_check"
   ## This is similarly inserted to create a new user, but we don't need it any more and it could cause problems
   $SUDO_TO_ROOT safe-rm "${CHROOT_FOLDER}/var/lib/dist-base-files/live_build"

   if [ "$($SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" dpkg-query --show --showformat='${Status}\n' anon-apt-sources-list)" = 'install ok installed' ]; then
      ## Put the debian.list file back, live-build appropriates it and then deletes it
      $SUDO_TO_ROOT cp "${source_code_folder_dist}/packages/kicksecure/anon-apt-sources-list/etc/apt/sources.list.d/debian.list" "${CHROOT_FOLDER}/etc/apt/sources.list.d/debian.list"
   fi

   ## Run chroot post-install scripts from initializer-dist, TODO consider moving these file removes to there?
   if [ -d "${CHROOT_FOLDER}/usr/libexec/initializer-dist/chroot-scripts-post.d" ]; then
      ## Check which chroot scripts we got.
      $SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" run-parts --verbose --test "/usr/libexec/initializer-dist/chroot-scripts-post.d/"

      ## Run the chroot scripts.
      $SUDO_TO_ROOT chroot "${CHROOT_FOLDER}" run-parts --verbose --exit-on-error "/usr/libexec/initializer-dist/chroot-scripts-post.d/"
   else
      true "${green}${bold}INFO: Folder /usr/libexec/initializer-dist/chroot-scripts-post.d does not exist in chroot.
Not running any chroot scripts.${reset}"
   fi

   ## Network configuration
   echo "${dist_build_hostname}" | $SUDO_TO_ROOT sponge -- chroot/etc/hostname
   $SUDO_TO_ROOT cp "${source_code_folder_dist}/live-build-data/live-build-config/live_build_etc_hosts" "${CHROOT_FOLDER}/etc/hosts"

   ## Package into an ISO
   if ! $SUDO_TO_ROOT lb binary --verbose --debug; then
      error "${bold}${red}ERROR: Live build binary stage failed!${reset}"
   fi

   ## live-build does not support configuration of the output ISO file name.
   ## Rename from ISO file name defined by live-build format to derivative-maker format.
   mv "${dist_build_type_short}-${dist_build_version}-${dist_build_target_arch}.hybrid.iso" "${binary_image_iso_file}"

   popd
}

main() {
   if [ "${dist_build_install_to_root}" = "true" ]; then
      true "${green}INFO: Skipping $BASH_SOURCE, because dist_build_install_to_root is set to true.${reset}"
      return 0
   fi

   if [ "${dist_build_iso}" != "true" ]; then
      true "${green}INFO: Skipping $BASH_SOURCE, because dist_build_iso is not set to true.${reset}"
      return 0
   fi

   create-live-build-image
}

main "$@"
