#!/usr/bin/env bash

set -euo pipefail

usage() {
  echo "usage: $0 [/path/to/an/existing_keyfile]"
  echo "   Perform a one-time password-less boot on system with a Luks encrypted root drive"
  echo "   /path/to/an/existing_keyfile is an optional path to a file already configured"
  echo "   to unlock the root drive. It will be used to unlock it and add a \"throw away\" keyfile"
  echo "   if provided. Otherwise you will be prompted for an existing passphrase to do so."
}

existing_keyfile="_NONE"
if [[ $# == 1 ]]; then
  if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "-?" ]]; then
    usage
    exit 0
  fi
  existing_keyfile="$1"
elif [[ $# != 0 ]]; then
  echo "ERROR: wrong number of arguments, should be 0 or 1"
  usage
  exit 2
fi


#############
# CONSTANTS #
#############
cleanup_script="/usr/bin/passless-boot_post_boot_cleanup.sh"
keyfile="/boot/crypto_key"
service="passless-boot_post_boot_cleanup.service"
service_file="/etc/systemd/system/$service"


################
# START SCRIPT #
################
if ! grep -q cryptdevice /proc/cmdline; then
  echo "❌ the kernel command line DOES NOT contains a cryptdevice=<crypt_device>... directive!"
  echo "❌ this probably means your system is not encrypted."
  echo "❌ Are you sure you know what you're doing?"
  exit 5
fi
cryptdevice="$(tr ' ' '\n' < /proc/cmdline | grep cryptdevice | tr ':' '\n' | grep cryptdevice | sed 's/^cryptdevice=//')"
if [[ "$cryptdevice" == "UUID="* ]]; then
  cryptdevice="/dev/disk/by-uuid/${cryptdevice#UUID=}"
fi

if [[ -b "$cryptdevice" ]]; then
  echo "✅ the current kernel was booted on cryptdevice $cryptdevice"
else
  echo "❌ failed to get the currently booted cryptdevice from /proc/cmdline:"
  cat /proc/cmdline
  echo "❌ this script only works with a cryptdevice=<device> option on the kernel command line"
  echo "   where <device> is a valid block device (or a  UUID=...)"
  exit 10
fi

if ! cryptsetup isLuks "$cryptdevice"; then
  echo "❌ the cryptdevice from the kernel commandline, $cryptdevice, is not a Luks encrypted drive."
  exit 20
fi

if ! grep -q cryptkey /proc/cmdline; then
  echo "⚠  the kernel command line DOES NOT contains a cryptkey=<cryptkey_device>... directive!"
  echo "⚠  this probably means your setup is incomplete, and password-less reboot might fail."
  echo "⚠  however, it could also mean you have just made the change and not rebooted yet."
  echo "⚠  if you understand what is going on, and want to attempt password-less reboot setup anyway"
  read -r -p '⚠  please copy the \"/dev/disk/by-uuid/<UUID>\" you want as cryptkey= kernel option: ' cryptkey_device
  if [[ -z "$cryptkey_device" ]]; then
     echo "❌ not continuing."
     exit 50
  fi
else
  cryptkey_device="$(tr ' ' '\n' < /proc/cmdline | grep cryptkey | tr ':' '\n' | grep cryptkey | sed 's/cryptkey=//')"
fi

if [[ -b "$cryptkey_device" ]]; then
  echo "✅ $cryptkey_device is a block device."
else
  echo "❌ $cryptkey_device is not a valid block device."
  exit 20
fi

if findmnt --noheadings --output=TARGET "$cryptkey_device" | grep -q "^/boot$"; then
  echo "✅ cryptkey device $cryptkey_device is mounted on /boot"
else
  echo "⚠  the cryptkey device $cryptkey_device specified on the kernel command line is not mounted at /boot."
  echo "❌ this situation is unexpected and the script will not work. Are you sure your boot drive is mounted properly?"
  exit 60
fi

need_to_add_keyfile="TRUE"
if [[ -e "$keyfile" ]]; then
  echo "✅ $keyfile exists"
  echo -n "🕑 checking validity of $keyfile for unlocking $cryptdevice."
  if cryptsetup --key-file="$keyfile" --test-passphrase open "$cryptdevice"; then
    echo -ne "\r\033[0K\r"
    echo "✅ $keyfile is valid for unlocking of $cryptdevice."
    need_to_add_keyfile="FALSE"
  else
    echo -ne "\r\033[0K\r"
    echo "⚠  $keyfile will not yet unlock $cryptdevice."
  fi
else
  echo -n "🕑 no keyfile at $keyfile, creating a new 256 byte keyfile at $keyfile..." 
  dd if=/dev/random of="$keyfile" bs=256 count=1 status=none
  echo -ne "\r\033[0K\r"
fi

if [[ "$need_to_add_keyfile" == "TRUE" ]]; then
  if [[ "$existing_keyfile" == "_NONE" ]]; then
    echo "⚠  adding keyfile to cryptdevice, please type password..."
    cryptsetup luksAddKey "$cryptdevice" "$keyfile"
  else
    echo -n "🕑 adding keyfile to cryptdevice using existing key $existing_keyfile, please be patient..."
    cryptsetup --key-file "$existing_keyfile" luksAddKey "$cryptdevice" "$keyfile"
  fi

  if cryptsetup --key-file="$keyfile" --test-passphrase open "$cryptdevice"; then
    echo -ne "\r\033[0K\r"
    echo "✅ keyfile $keyfile is now valid for unlocking of $cryptdevice"
  else
    echo -ne "\r\033[0K\r"
    echo "❌ keyfile $keyfile will still not unlock $cryptdevice."
    echo "❌ password-less boot impossible."
    exit 30
  fi
fi

echo "✅ keyfile in place and valid for unlocking root cryptdevice."
echo "✅ password-less boot should be possible."

if [[ -z "$service_file" ]]; then
  echo "⚠  cleanup service $service_file seems to be missing."
  echo "⚠  boot will work but you will have to clean up manually or the keyfile will remain in unencrypted /boot."
elif [[ -z "$cleanup_script" || ! -x "$cleanup_script" ]]; then
  echo "⚠  cleanup script $cleanup_script seems to be missing or not executable."
  echo "⚠  boot will work but you will have to clean up manually or the keyfile will remain in unencrypted /boot."
else
  echo "✅ all cleanup files exist and seem functional."
  echo -n "🕑 enabling cleanup service..."
  systemctl enable "$service" |& grep -v "Created symlink " || true # hide line, but prevent exit when grep fails
  if [[ "$(systemctl is-enabled "$service")" == "enabled" ]]; then
    echo -ne "\r\033[0K\r"
    echo "✅ cleanup service enabled."
  else
    echo -ne "\r\033[0K\r"
    echo "⚠  failed to enable cleanup service."
    echo "⚠  boot will work but you will have to clean up manually or the keyfile will remain in unencrypted /boot."
  fi
  echo "✅ cleanup setup successfully."
fi

if which rguard >& /dev/null; then
  echo -n "🕑 deactivating reboot-guard protection..."
  if rguard -0 --loglevel error; then
    echo -ne "\r\033[0K\r"
    echo "✅ reboot-guard deactivated."
    echo "🎉 you may now reboot without needing to enter a root device password!"
  else
    echo -ne "\r\033[0K\r"
    echo "❌ failed to deactivate reboot-guard."
  fi
fi

exit 0

