diff --git a/setup/arch-autoinstall.sh b/setup/arch-autoinstall.sh index fdc7c21..fe342f5 100755 --- a/setup/arch-autoinstall.sh +++ b/setup/arch-autoinstall.sh @@ -328,9 +328,9 @@ LUKS_BACKUP_KEY="" # path to key file, set only when encryption is active if [[ "$ENCRYPT_DISK" == "YES" ]]; then echo "Encrypting root partition..." - # -v (verbose) shows progress; luksFormat initialises a LUKS1 container by default - # and prompts for the primary passphrase interactively. - cryptsetup -v luksFormat "$ROOT_PART" + # --type luks2 is required for systemd-cryptenroll (FIDO2 token enrollment). + # -v (verbose) shows progress; prompts for the primary passphrase interactively. + cryptsetup -v luksFormat "$ROOT_PART" --type luks2 # Open the container and expose it as /dev/mapper/cryptroot for formatting. cryptsetup open "$ROOT_PART" cryptroot @@ -508,15 +508,15 @@ echo "%wheel ALL=(ALL:ALL) ALL" >> /etc/sudoers # 2. Password-only LUKS: uses classic `encrypt` hook (no systemd dependency). # 3. Unencrypted: minimal hook set — no encrypt hook needed. if [[ "$ENCRYPT_DISK" == "YES" && "$FIDO_ROOT" == "YES" ]]; then - sed -i 's/^HOOKS=.*/HOOKS=(base udev systemd autodetect microcode modconf kms consolefont block sd-encrypt lvm2 btrfs filesystems keyboard keymap fsck)/' /etc/mkinitcpio.conf + sed -i 's/^HOOKS=.*/HOOKS=(base udev systemd autodetect microcode modconf kms consolefont block sd-encrypt btrfs filesystems keyboard keymap fsck)/' /etc/mkinitcpio.conf elif [[ "$ENCRYPT_DISK" == "YES" ]]; then - sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf kms consolefont block encrypt lvm2 btrfs filesystems keyboard keymap fsck)/' /etc/mkinitcpio.conf + sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf kms consolefont block encrypt btrfs filesystems keyboard keymap fsck)/' /etc/mkinitcpio.conf else sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect microcode modconf kms consolefont block btrfs filesystems keyboard fsck)/' /etc/mkinitcpio.conf fi -# Regenerate the initramfs for the selected kernel preset. -mkinitcpio -p "$KERNEL" +# -P regenerates all installed kernel presets (more thorough than -p ). +mkinitcpio -P ################################################### # GRUB CONFIG @@ -526,8 +526,8 @@ UUID=$(blkid -s UUID -o value "$ROOT_PART") if [[ "$ENCRYPT_DISK" == "YES" ]]; then if [[ "$FIDO_ROOT" == "YES" ]]; then # systemd-cryptsetup syntax: rd.luks.name==. - # The FIDO2 device is auto-detected by systemd-cryptenroll at boot. - KERNEL_CMD="rd.luks.name=${UUID}=cryptroot root=/dev/mapper/cryptroot" + # rd.luks.options=fido2-device=auto tells sd-encrypt to probe for the FIDO2 token. + KERNEL_CMD="rd.luks.name=${UUID}=cryptroot rd.luks.options=fido2-device=auto root=/dev/mapper/cryptroot" else # Classic initramfs encrypt hook syntax: cryptdevice=UUID=:. KERNEL_CMD="cryptdevice=UUID=${UUID}:cryptroot root=/dev/mapper/cryptroot" @@ -547,21 +547,38 @@ grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=M-Archy-G grub-mkconfig -o /boot/grub/grub.cfg ################################################### -# USER FIDO2 LOGIN +# USER FIDO2 LOGIN (directory + PAM only) ################################################### +# Key enrollment runs outside the chroot — pamu2fcfg cannot reach /dev/hidraw* +# from inside because the host's udev owns those device nodes. if [[ "$FIDO_USER" == "YES" ]]; then mkdir -p "/home/$USERNAME/.config/Yubico" - echo "Insert FIDO2 key for user login and touch when prompted..." - # pamu2fcfg registers the FIDO2 key and writes the credential to u2f_keys. - # Running under sudo -u ensures the file is generated with the correct UID context. - sudo -u "$USERNAME" pamu2fcfg -u "$USERNAME" > "/home/$USERNAME/.config/Yubico/u2f_keys" - chown "$USERNAME":"$USERNAME" "/home/$USERNAME/.config/Yubico/u2f_keys" - # Append the PAM rule so pam_u2f is required for system-local-login sessions. - echo "auth required pam_u2f.so" >> /etc/pam.d/system-local-login + chown "$USERNAME:$USERNAME" "/home/$USERNAME/.config/Yubico" + # `cue` prints a prompt so the user knows to touch the key when challenged. + echo "auth required pam_u2f.so cue" >> /etc/pam.d/system-local-login fi CHROOT_EOF +############################################ +# USER FIDO2 ENROLLMENT (outside chroot) +############################################ +# pamu2fcfg must run outside arch-chroot: the host's udev manages /dev/hidraw* +# and the new user has no access to those nodes from inside the chroot. +if [[ "$FIDO_USER" == "YES" ]]; then + echo "Enrolling FIDO2 key for user login (outside chroot)..." + U2F_KEYFILE="/mnt/home/${USERNAME}/.config/Yubico/u2f_keys" + mkdir -p "/mnt/home/${USERNAME}/.config/Yubico" + # Scope the credential to this hostname so it cannot be replayed on another system. + pamu2fcfg -u "$USERNAME" -o "pam://$HOSTNAME" -i "pam://$HOSTNAME" > "$U2F_KEYFILE" + # Query numeric UID/GID from inside the chroot so ownership is correct. + _NEWUID=$(arch-chroot /mnt id -u "$USERNAME" 2>/dev/null || echo "1000") + _NEWGID=$(arch-chroot /mnt id -g "$USERNAME" 2>/dev/null || echo "1000") + chown -R "$_NEWUID:$_NEWGID" "/mnt/home/${USERNAME}/.config/Yubico" + chmod 600 "$U2F_KEYFILE" + echo "FIDO2 key enrolled for $USERNAME." +fi + ############################################ # DOTFILES TUI SETUP (in-chroot, optional) ############################################ diff --git a/setup/generate-answerfile.sh b/setup/generate-answerfile.sh index 2bf878b..96315e8 100644 --- a/setup/generate-answerfile.sh +++ b/setup/generate-answerfile.sh @@ -191,12 +191,11 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then # ── Components ──────────────────────────────────────────────────────────── AF_COMPONENTS=$(dialog --backtitle "$BACKTITLE" \ --title " Select Components " \ - --checklist "Space toggles · Enter confirms · Esc quits" 16 68 5 \ + --checklist "Space toggles · Enter confirms · Esc quits" 16 68 4 \ "pkg" "Package managers yay · nvm · rust" on \ "core" "Core packages 100+ base system packages" on \ "svc" "Core services NetworkManager · cronie · fail2ban" on \ "shell" "Shell setup zsh · nvim · yazi · micro · starship" on \ - "plymouth" "Plymouth boot splash — skull logo + spinner" on \ 3>&1 1>&2 2>&3) || AF_COMPONENTS="" # ── DE ──────────────────────────────────────────────────────────────────── diff --git a/setup/tui-install.sh b/setup/tui-install.sh index 767dbc9..bf1dc61 100755 --- a/setup/tui-install.sh +++ b/setup/tui-install.sh @@ -170,9 +170,9 @@ count_steps() { [[ "$c" == *"shell"* ]] && TOTAL=$(( TOTAL + 1 )) # A non-"none" DE selection always installs exactly one DE module. [[ "$de" != "none" ]] && TOTAL=$(( TOTAL + 1 )) - # Optional app modules: one glob check per app, one increment per match. - # Glob syntax *"tag"* matches if the space-separated SELECTED_APPS string - # contains the tag anywhere — works because tags never share substrings. + # Optional app modules: one word-boundary check per app, one increment per match. + # Padding $a with spaces and matching " tag " prevents partial-name false matches + # (e.g. "plymouth" must not match against "plymouth-custom"). # BEGIN GENERATED MODULES: module-counters [[ " $a " == *" ollama "* ]] && TOTAL=$(( TOTAL + 1 )) [[ " $a " == *" llama-cpp "* ]] && TOTAL=$(( TOTAL + 1 )) @@ -414,7 +414,7 @@ else # Esc / Cancel returns exit code 1; the '|| { ...; exit 0; }' treats that as a clean abort. COMPONENTS=$(dialog --backtitle "$BACKTITLE" \ --title " Select Components " \ - --checklist "Space toggles · Enter confirms · Esc quits" 16 68 5 \ + --checklist "Space toggles · Enter confirms · Esc quits" 16 68 4 \ "pkg" "Package managers yay · nvm · rust" on \ "core" "Core packages 100+ base system packages" on \ "svc" "Core services NetworkManager · cronie · fail2ban" on \