#!/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 <