First commit

This commit is contained in:
myve 2025-11-22 23:15:27 +00:00
commit 36ad41a2fc
18 changed files with 10005 additions and 0 deletions

347
recover.sh Executable file
View file

@ -0,0 +1,347 @@
#!/usr/bin/env bash
set -a -E
# Exit function
trap '[ "${?}" -ne 77 ] || exit 77' ERR
function die
{
echo -e '\n\e[1;31mError encountered, script aborted...\e[0m\n'
exit 77
}
# Internet connection check
if ! nc -z -w 1 archlinux.org 443 >/dev/null 2>&1 || ! nc -z -w 1 google.com 443 >/dev/null 2>&1
then
die 'No internet connectivity detected, plug in an ethernet cable or run \e[32miwd-connect\e[33m if using wifi and try again'
fi
clear
echo -e '\e[3m## rev '${revision}'\e[0m\n'
echo -e '\t\e[1;4;34mArch Linux Recovery\e[0m\n\n'
echo -e '\e[1mSelect a system configuration from the options below\e[0m\n'
echo -e '\t1) Basic'
echo -e '\t2) Full Disk LUKS Encryption with EFISTUB'
echo -e '\t3) Full Disk LUKS Encryption with Secured GRUB'
echo -e '\t4) Yubikey Full Disk Encryption with EFISTUB'
echo -e '\t5) Yubikey Full Disk Encryption with Secured GRUB'
if ls -l /dev/disk/* | grep -q 'virtio\|QEMU'
then
echo
until [[ ${arch} = [1-5] ]]
do
read -n 1 -p '> ' arch
[[ ${arch} = [1-5] ]] || echo -e '\n\n\e[1;31mInvalid selection, type an option from 1 to 5\e[0m'
done
else
echo -e '\t6) Full Disk Encryption with Detached LUKS Header and Secured GRUB'
echo -e '\t7) Yubikey Encrypted Detached LUKS Header with Secured GRUB\n'
until [[ ${arch} = [1-7] ]]
do
read -n 1 -p '> ' arch
[[ ${arch} = [1-7] ]] || echo -e '\n\n\e[1;31mInvalid selection, type an option from 1 to 7\e[0m'
done
fi
# Prevent continuing unless yubikey is detected, only applies to yubikey setups
if [[ ${arch} = [457] ]] && ! dmesg | grep -q -i YubiKey
then
echo -e '\n\n\e[1mYubikey not detected'
echo -e 'Insert one to continue\e[5m...\e[0m'
until dmesg | grep -q -i YubiKey
do
sleep 1
done
fi
# Installation drive
echo -e '\n\n\e[1;36mIdentify the system drive from the list of available devices below\e[0m'
lsblk -d -o name,model,size,mountpoint | grep -v 'archiso'
echo -e '\e[3m## SSD and HDD device format begins with "sd" or "hd" (sda, sdb, sd[*])'
echo -e '## NVME and PCI device format is "nvme[*]n1" (nvme0n1, nvme1n1, nvme[*]n1)\e[0m'
while true
do
read -r -p 'Installation device: ' installation_disk
lsblk -o name | grep -q -w ${installation_disk} && [ ${installation_disk} ] && break
lsblk -d -o name,model,size,mountpoint | grep -v 'archiso'
[ -z ${installation_disk} ] && echo -e '\e[1;31mField cannot be empty, try again\e[0m' ||
echo -e '\e[1;31mInvalid selection or drive not available, try again\e[0m'
done
echo -e '\n\e[1mInstallation drive set as \e[32m/dev/'${installation_disk}'\e[0m'
echo
# Detached boot drive
if [[ ${arch} = [67] ]]
then
echo -e '\e[1;34mIdentify the removable boot drive from the list of available devices below\e[0m'
lsblk -d -o name,model,size,mountpoint | grep -v "archiso\|${installation_disk}"
echo -e '\e[3m## Removable drives usually begin with "sd" (sda, sdb, sd[*])\e[0m'
while true
do
read -r -p 'Removable boot device: ' external_boot_disk
lsblk -o name | grep -v ${installation_disk} | grep -q -w ${external_boot_disk} && [ ${external_boot_disk} ] && break
lsblk -d -o name,model,size,mountpoint | grep -v "archiso\|${installation_disk}"
if [ -z ${external_boot_disk} ]
then
echo -e '\e[1;31mField cannot be empty, try again\e[0m'
elif [ ${external_boot_disk} = ${installation_disk} ]
then
echo -e '\e[1;31mBoot drive cannot be the same as the system drive, try again\e[0m'
else
echo -e '\e[1;31mInvalid selection or drive not available, try again\e[0m'
fi
done
echo -e '\n\e[1mDetached boot drive set as \e[32m/dev/'${external_boot_disk}'\e[0m'
echo
fi
if [[ ${arch} = [457] ]]
then
until [[ ${decrypt_root} = [yYnN] ]]
do
read -n 1 -p $'\n\e[1mDoes the yubikey automatically decrypt root upon boot (1FA)? (y/n): \e[0m' decrypt_root
[[ ${decrypt_root} = [yYnN] ]] || echo -e -n '\n\n\e[1;31mNot a valid answer, type "y" or "n"\e[0m'
done
echo
fi
# Functions
function decryptRootLuks
{
while true
do
unset lukspass
echo -e '\e[1;36mEnter the encryption passphrase for the system drive\e[0m'
until [ ${lukspass} ]
do
read -s -r -p 'Encryption password: ' lukspass
[ ${lukspass} ] || echo -e '\n\n\e[1;31mPassphrase field cannot be empty, try again\e[0m'
done
echo -e '\n\n\e[1;36mAttempting to decrypt '${rootpart}'\e[0m'
if printf '%s' "${lukspass}" | cryptsetup open -v ${rootpart} cryptroot ${luks_header}
then
unset lukspass
echo -e '\e[1;92mDecryption successful\e[0m'
break
else
echo -e '\e[1;31mPassphrase failed, try again\e[0m\n'
fi
done
}
function decryptRootYubikey
{
echo
yes | pacman -Sy &>/dev/null
for package in yubikey-personalization yubikey-full-disk-encryption
do
if ! pacman -Q | grep -q -w ${package}
then
missing_yubikey_req+=(${package})
fi
done
if [ ${missing_yubikey_req} ]
then
yes | pacman -Sy ${missing_yubikey_req[@]}
unset missing_yubikey_req
echo
fi
# # Custom challenge slot
# sed -i '/YKFDE_CHALLENGE_SLOT/c\YKFDE_CHALLENGE_SLOT="1"' /etc/ykfde.conf
while true
do
unset lukspass
echo -e '\e[1;36mEnter the encryption passphrase for the system drive\e[0m'
until [ ${lukspass} ]
do
read -s -r -p 'Encryption password: ' lukspass
[ ${lukspass} ] || echo -e '\n\n\e[1;31mPassphrase field cannot be empty, try again\e[0m'
done
if [[ ${decrypt_root} = [yY] ]]
then
sed -i '/YKFDE_CHALLENGE=/c\YKFDE_CHALLENGE="'"$(printf '%q' ${lukspass})"'"' /etc/ykfde.conf
fi
echo -e '\n\n\e[1;36mAttempting to decrypt '${rootpart}' with yubikey HMAC encryption\e[0m'
if printf '%s\n' "${lukspass}" | ykfde-open -d ${rootpart} -n cryptroot -- ${luks_header}
then
unset lukspass
echo -e '\e[1;92mDecryption successful\e[0m'
break
else
echo -e '\e[1;31mPassphrase failed, try again\e[0m\n'
fi
done
}
function decryptBootLuks
{
while true
do
unset grubpass
echo -e '\e[1;36mEnter the encryption passphrase for the bootloader\e[0m'
until [ ${grubpass} ]
do
read -s -r -p 'Bootloader password: ' grubpass
[ ${grubpass} ] || echo -e '\n\n\e[1;31mPassword field cannot be empty, try again\e[0m'
done
echo -e '\n\n\e[1;36mAttempting to decrypt bootloader...\e[0m'
if printf '%s' "${grubpass}" | cryptsetup open ${bootpart} cryptboot
then
unset grubpass
echo -e '\e[1;92mDecryption successful\e[0m'
break
else
echo -e '\e[1;31mPassphrase failed, try again\e[0m\n'
fi
done
}
function configureVolumes
{
echo -e '\n\e[1;36mMounting volumes\e[0m'
case $(blkid -s TYPE -o value ${rootvol}) in
zfs_member)
if ! zpool list | grep -q zroot
then
zpool import -R /mnt zroot -N -d ${rootvol}
fi
zfs mount zroot/ROOT
zfs mount -a
;;
btrfs)
mount ${rootvol} /mnt
;;
ext4)
mount ${rootvol} /mnt
mount ${bootvol} /mnt/boot
if [[ ${arch} = [3567] ]]
then
mount ${efivol} /mnt/boot/efi
fi
;;
esac
}
# Grab disk-id of ${drive}
installation_disk_id=$(ls -l /dev/disk/by-id/* | grep "${installation_disk}$" | grep 'wwn\|nvme-uuid\|nvme-nvme\|nvme-eui\|QEMU\|virtio\|VBOX' | awk '{print $9}' | head -1)
external_boot_disk_id=$(ls -l /dev/disk/by-id/* | grep "${external_boot_disk}$" | grep 'wwn\|nvme-uuid\|nvme-nvme\|nvme-eui\|QEMU\|virtio\|VBOX\|usb' | awk '{print $9}' | head -1)
# System configurations
case ${arch} in
1) # Basic
export {efivol,bootvol}=${installation_disk_id}-part1
export {rootpart,rootvol}=${installation_disk_id}-part2
configureVolumes
;;
2|4) # FDE with EFISTUB
export {efivol,bootvol}=${installation_disk_id}-part1
rootpart=${installation_disk_id}-part2
rootvol=/dev/mapper/cryptroot
case ${arch} in
2)
if [[ $(blkid -s TYPE -o value ${rootpart}) = "zfs_member" ]]
then
zpool import -R /mnt zroot -N -d ${rootpart}
printf '%s' "${lukspass}" | zfs load-key zroot
else
decryptRootLuks
fi
;;
4) decryptRootYubikey;;
esac
configureVolumes
;;
3|5) # FDE with Secured GRUB
efivol=${installation_disk_id}-part1
bootpart=${installation_disk_id}-part2
rootpart=${installation_disk_id}-part3
rootvol=/dev/mapper/cryptroot
bootvol=/dev/mapper/cryptboot
case ${arch} in
3) decryptRootLuks;;
5) decryptRootYubikey;;
esac
decryptBootLuks
configureVolumes
;;
6|7) # FDE with detached luks header
efivol=${external_boot_disk_id}-part1
bootpart=${external_boot_disk_id}-part2
rootpart=${installation_disk_id}
rootvol=/dev/mapper/cryptroot
bootvol=/dev/mapper/cryptboot
luks_header='--header /mnt/header.img'
decryptBootLuks
mount /dev/mapper/cryptboot /mnt
case ${arch} in
6) decryptRootLuks;;
7) decryptRootYubikey;;
esac
umount /mnt
configureVolumes
;;
esac
echo -e '\e[1;92mSystem successfully mounted...\e[0m\n'
if [[ $(blkid -s TYPE -o value ${rootvol}) = "btrfs" ]]
then
install /dev/stdin /usr/local/bin/btrfs-mount <<- BTRFSSU
#!/usr/bin/env bash
btrfsopts=$(awk '$2=="/"' /mnt/etc/fstab | awk '{print $4}' | sed 's/,subvol=.*//')
umount -R /mnt
echo
# Mount @root subvolume
mount -o ${btrfsopts},subvol=@ ${rootvol} /mnt
# Mount all subvolumes
arch-chroot /mnt mount --all
lsblk
echo -e '\n\t\e[1;92mBtrfs subvolumes successful mounted!\e[0m\n'
BTRFSSU
echo -e '\e[1mRun \e[92mbtrfs-mount\e[0m\e[1m to mount all the btrfs subvolumes\e[0m\n'
fi
if [[ ${arch} = [3567] ]]
then
install /dev/stdin /usr/local/bin/re-grub <<REGRUB
#!/usr/bin/env bash
set -e
if findmnt '/mnt/boot/efi' | grep -q "${efivol}" && findmnt '/mnt/boot' | grep -q "${bootvol}"
then
arch-chroot /mnt /bin/bash <<'GRUB'
grub-install --target=x86_64-efi --bootloader-id=GRUB --efi-directory=/boot/efi --recheck
grub-mkconfig -o /boot/grub/grub.cfg
echo -e '\n\t\e[1;92mGrub successfuly re-installed!\e[0m\n'
GRUB
else
echo -e '\n\t\e[1;31mEFI partition not mounted, try again\e[0m\n'
fi
REGRUB
echo -e '\e[1mRun \e[92mre-grub\e[0m\e[1m to regenerate grub\e[0m\n'
fi