//! Map zbus errors to short, user-facing strings. The GUI surfaces these in //! `adw::Toast` and inside the touch-prompt dialog's failure state. //! //! Pure logic; testable without a display server. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[allow(dead_code)] // wired through keys_page.rs / enroll_dialog.rs in Tasks 4-6. pub(crate) enum ErrorKind { /// Daemon unreachable / bus dropped — caller should swap to disconnected banner. Disconnected, /// polkit denied. Daemon's message is usually fine to show verbatim. AccessDenied, /// Anything else — daemon returned a typed `Failed(msg)` or similar. Other, } #[allow(dead_code)] // wired through keys_page.rs / enroll_dialog.rs in Tasks 4-6. pub(crate) fn classify(err: &zbus::Error) -> ErrorKind { match err { zbus::Error::InputOutput(_) | zbus::Error::Address(_) | zbus::Error::Handshake(_) => { ErrorKind::Disconnected } zbus::Error::FDO(boxed) => match boxed.as_ref() { zbus::fdo::Error::AccessDenied(_) => ErrorKind::AccessDenied, zbus::fdo::Error::ServiceUnknown(_) | zbus::fdo::Error::NameHasNoOwner(_) => { ErrorKind::Disconnected } _ => ErrorKind::Other, }, _ => ErrorKind::Other, } } #[allow(dead_code)] // wired through keys_page.rs / enroll_dialog.rs in Tasks 4-6. pub(crate) fn user_message(err: &zbus::Error) -> String { match classify(err) { ErrorKind::Disconnected => { "Couldn't reach the authentication daemon. Make sure authforge-daemon is running." .to_string() } ErrorKind::AccessDenied => match err { zbus::Error::FDO(boxed) => match boxed.as_ref() { zbus::fdo::Error::AccessDenied(msg) => msg.clone(), _ => "Access denied.".to_string(), }, _ => "Access denied.".to_string(), }, ErrorKind::Other => err.to_string(), } } #[cfg(test)] mod tests { use super::*; #[test] fn service_unknown_classifies_as_disconnected() { let e = zbus::Error::FDO(Box::new(zbus::fdo::Error::ServiceUnknown( "no daemon".to_string(), ))); assert_eq!(classify(&e), ErrorKind::Disconnected); } #[test] fn access_denied_classifies_as_access_denied() { let e = zbus::Error::FDO(Box::new(zbus::fdo::Error::AccessDenied( "polkit said no".to_string(), ))); assert_eq!(classify(&e), ErrorKind::AccessDenied); } #[test] fn access_denied_user_message_is_daemon_message_verbatim() { let e = zbus::Error::FDO(Box::new(zbus::fdo::Error::AccessDenied( "polkit said no".to_string(), ))); assert_eq!(user_message(&e), "polkit said no"); } #[test] fn disconnected_user_message_mentions_authforge_daemon() { let e = zbus::Error::FDO(Box::new(zbus::fdo::Error::ServiceUnknown( "no daemon".to_string(), ))); assert!(user_message(&e).contains("authforge-daemon")); } }