#!/bin/bash

## Copyright (C) 2019 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -o errexit
set -o nounset
set -o errtrace
set -o pipefail

# shellcheck source=../libexec/helper-scripts/get_colors.sh
source /usr/libexec/helper-scripts/get_colors.sh
# shellcheck source=../libexec/helper-scripts/get_password.sh
source /usr/libexec/helper-scripts/get_password.sh

run_update_grub() {
   printf "%s\n" "$0: INFO: Running 'update-grub'..." >&2
   if update-grub; then
      printf "%s\n" "$0: INFO: 'update-grub' succeeded." >&2
      return 0
   fi
   printf "%s\n" "$0: ERROR: 'update-grub' failed. This script is most \
likely just the trigger, not the cause. Unless you know this is not an issue, \
you should fix 'update-grub', otherwise your system might no longer \
boot." >&2
   return 1
}

if [ "$(id -u)" != "0" ]; then
   printf "%s\n" "$0: ERROR: This must be run as root (sudo)!" >&2
   exit 1
fi

## Hardcoded for simplicity.
user="user"
grub_config_file="/etc/grub.d/44_password"

printf "%s\n" "$0: INFO: This is a GRUB bootloader password management tool for systems with only one human user. It supports:

* Setting an encrypted bootloader password by creating GRUB account '$user' and storing it in '$grub_config_file'. (Then running 'update-grub'.)
* Deleting the bootloader password by removing '$grub_config_file'.
* It configures GRUB to always require a password at boot for all actions.

This tool does NOT handle:

* Full Disk Encryption (FDE)

Advanced GRUB features not supported:

* Multiple GRUB user accounts
* Fine-grained permissions (e.g., allow boot without password but require one to edit kernel cmdline)
* Changing manually set GRUB passwords not managed by this tool

Advanced use should be configured manually.

See user documentation:
https://www.kicksecure.com/wiki/Protection_Against_Physical_Attacks#grub-pwchange
" >&2

echo -n "Enter the new password for GRUB account '$user': " >&2
echo >&2
get_password
first_input="$password"
echo >&2

echo -n "Re-enter the new password to confirm: " >&2
echo >&2
get_password
second_input="$password"
echo >&2

if [ ! "$first_input" = "$second_input" ]; then
   printf "%s\n" "$0: ERROR: Passwords do not match. No changes made." >&2
   exit 1
fi

## Delete password if the new password is empty.
if [ "$first_input" = "" ]; then
   read -r -p "WARNING: You are about to delete the password for GRUB account '$user'. Continue? [Y/N] " delete_pw_yn

   if [ "${delete_pw_yn,,}" = 'y' ]; then
      safe-rm --verbose --force -- "${grub_config_file}"
      run_update_grub
      if grub-password-status-check &>/dev/null; then
         printf "%s\n" "$0: ERROR: A GRUB bootloader password still exists but is not managed by '$0'. To debug, run: sudo grub-password-status-check" >&2
         exit 1
      fi
      printf "%s\n" "$0: SUCCESS: GRUB bootloader password deleted successfully." >&2
      exit 0
   fi

   printf "%s\n" "$0: CANCELLED password deletion." >&2
   exit 0
fi

password_hash="$(LC_ALL=C grub-mkpasswd-pbkdf2 <<< "${password}"$'\n'"${password}" | awk '/hash of / {print $NF}')"

## Change the password.
printf "%s\n" "\
#!/bin/sh

## This file was auto-generated by: $0
## Manual edits will be lost if the user runs: $0
##
## You may delete this file to disable the GRUB password.
## Remember to run 'sudo update-grub' after making changes.

cat <<EOF
set superusers=\"user\"
password_pbkdf2 user $password_hash
EOF" \
| sponge -- "${grub_config_file}"
chmod +x -- "${grub_config_file}"

unset first_input
unset second_input
unset password
unset password_hash

run_update_grub

if grub-password-status-check &>/dev/null; then
   printf "%s\n" "$0: SUCCESS: GRUB bootloader password for GRUB account '$user' was set successfully in '${grub_config_file}'." >&2
else
   printf "%s\n" "$0: ERROR: Failed to set GRUB password for GRUB account '$user'. To debug, run: sudo grub-password-status-check" >&2
fi
