From 9e2f4374602b5d191b55800f5e9aad51d479c3da Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sat, 23 May 2026 22:29:43 -0700 Subject: [PATCH] fix(setup): restore MultiSelect for PAM service selection; rewrite DM descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a UX regression introduced in #43 that replaced the single MultiSelect screen with per-service Confirm prompts (one dialog per candidate service). Changes: - Restore dialoguer::MultiSelect in wizard_pam_setup: all detected services are listed on one screen with [x]/[ ] toggles, pre-checked per default_enabled, confirmed with a single Enter keypress. Non-TTY / non-interactive mode auto-selects per defaults (unchanged). - Rewrite display-manager descriptions to remove the alarmist "declining is recommended unless you have recovery access" language. auth sufficient pam_facelock.so falls through to password on module failure, so lockout is not a real risk. The genuine concern with DMs is unverified integration, not lockout — GDM's auth stack is genuinely unusual so it retains a hedge; SDDM and LightDM use conventional stacks and need no warning. - Set default_enabled = true for all three DMs (consistent with how sudo/polkit-1/lockers are handled — same actual risk profile). Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/facelock-cli/src/commands/setup.rs | 60 ++++++++++++++--------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/crates/facelock-cli/src/commands/setup.rs b/crates/facelock-cli/src/commands/setup.rs index aea2c82..691fda7 100644 --- a/crates/facelock-cli/src/commands/setup.rs +++ b/crates/facelock-cli/src/commands/setup.rs @@ -4,7 +4,7 @@ use std::path::Path; use std::process::Command; use anyhow::{Context, bail}; -use dialoguer::{Confirm, Select, theme::ColorfulTheme}; +use dialoguer::{Confirm, MultiSelect, Select, theme::ColorfulTheme}; use indicatif::{ProgressBar, ProgressStyle}; use sha2::{Digest, Sha256}; @@ -940,24 +940,36 @@ fn wizard_pam_setup(theme: &ColorfulTheme) -> anyhow::Result> { return Ok(Vec::new()); } + let labels: Vec<&str> = candidates.iter().map(|c| c.description).collect(); + let defaults: Vec = candidates.iter().map(|c| c.default_enabled).collect(); + + let selected_services: Vec = if !is_interactive() { + // Non-TTY / non-interactive: auto-select per defaults. + candidates + .iter() + .zip(defaults.iter()) + .filter(|(_, d)| **d) + .map(|(c, _)| c.service.to_string()) + .collect() + } else { + let selections = MultiSelect::with_theme(theme) + .with_prompt("Select services to enable face authentication for") + .items(&labels) + .defaults(&defaults) + .interact()?; + selections + .into_iter() + .map(|i| candidates[i].service.to_string()) + .collect() + }; + let mut configured = Vec::new(); - for candidate in candidates { - let prompt = format!("Enable face auth for {}?", candidate.description); - let should_enable = if !is_interactive() { - candidate.default_enabled - } else { - Confirm::with_theme(theme) - .with_prompt(&prompt) - .default(candidate.default_enabled) - .interact()? - }; - if should_enable { - println!(" Configuring PAM for {}...", candidate.service); - match pam_install(candidate.service, true) { - Ok(()) => configured.push(candidate.service.to_string()), - Err(e) => { - println!(" Failed to configure {}: {e}", candidate.service); - } + for service in &selected_services { + println!(" Configuring PAM for {service}..."); + match pam_install(service, true) { + Ok(()) => configured.push(service.clone()), + Err(e) => { + println!(" Failed to configure {service}: {e}"); } } } @@ -1434,20 +1446,20 @@ const PAM_CANDIDATES: &[PamCandidate] = &[ PamCandidate { service: "gdm-password", category: PamCategory::DisplayManager, - description: "GDM login screen (GNOME) \u{2014} declining is recommended unless you have recovery access", - default_enabled: false, + description: "GDM login screen (GNOME) \u{2014} integration not yet verified with GDM's auth flow", + default_enabled: true, }, PamCandidate { service: "sddm", category: PamCategory::DisplayManager, - description: "SDDM login screen (KDE) \u{2014} declining is recommended unless you have recovery access", - default_enabled: false, + description: "SDDM login screen (KDE)", + default_enabled: true, }, PamCandidate { service: "lightdm", category: PamCategory::DisplayManager, - description: "LightDM login screen (Ubuntu/Xfce/Mint) \u{2014} declining is recommended unless you have recovery access", - default_enabled: false, + description: "LightDM login screen (Ubuntu/Xfce/Mint)", + default_enabled: true, }, ];