From 7ad3a9387733a80ef1e108205be70f434d4cb900 Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Tue, 11 Aug 2026 08:57:27 +0200 Subject: [PATCH] Dont do hybrid if it is not available --- .editorconfig | 4 ++ credentialsd-ui/data/resources/ui/window.blp | 6 +- credentialsd-ui/src/gui/view_model/gtk/mod.rs | 16 ++--- credentialsd/src/credential_service/mod.rs | 64 +++++++++++-------- 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/.editorconfig b/.editorconfig index 5600faaf..e47132b7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,6 +16,10 @@ indent_size = 4 indent_size = 2 max_line_length = 80 +[*.{blp}] +indent_size = 2 +max_line_length = 80 + [NEWS] indent_size = 2 max_line_length = 72 diff --git a/credentialsd-ui/data/resources/ui/window.blp b/credentialsd-ui/data/resources/ui/window.blp index 217b48e4..70f62def 100644 --- a/credentialsd-ui/data/resources/ui/window.blp +++ b/credentialsd-ui/data/resources/ui/window.blp @@ -50,10 +50,10 @@ template $CredentialsUiWindow: ApplicationWindow { child: Box { orientation: vertical; margin-start: 8; - Box { orientation: vertical; halign: start; + visible: bind template.view-model as <$CredentialManagerViewModel>.hybrid_transport_available; styles [ "cred-source-header", @@ -120,9 +120,9 @@ template $CredentialsUiWindow: ApplicationWindow { } } } - } - Separator {} + Separator {} + } Box { orientation: vertical; diff --git a/credentialsd-ui/src/gui/view_model/gtk/mod.rs b/credentialsd-ui/src/gui/view_model/gtk/mod.rs index b525463c..109bc89c 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/mod.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/mod.rs @@ -47,7 +47,7 @@ mod imp { pub activate_usb_prompt: RefCell, #[property(get, set)] - pub devices: RefCell, + pub hybrid_transport_available: RefCell, #[property(get, set)] pub credentials: RefCell, @@ -265,15 +265,15 @@ impl ViewModel { )); } - fn update_devices(&self, _devices: &[Device]) { - // TODO: This This is called when a new credential source is available to show it in the UI. - // At this time, the list is static, and the UI templates do not read this value. - // Eventually, the UI template will need to read the value, when - // pre-known credentials (like hybrid linked devices, or passkey - // autofill). However, I believe in the current paradigm, we will know all available + fn update_devices(&self, devices: &[Device]) { + let hybrid_available = devices.iter().any(|dev| { + dev.transport == Transport::HybridLinked || dev.transport == Transport::HybridQr + }); + self.set_hybrid_transport_available(hybrid_available); + // TODO: This is called when a new credential source is available to show it in the UI. + // However, I believe in the current paradigm, we will know all available // credential sources at the beginning of the request, so we won't need // to update these during the request. We may be able to reomve this method altogether. - // for now, we're ignoring this value. } fn update_credentials(&self, credentials: &[Credential]) { diff --git a/credentialsd/src/credential_service/mod.rs b/credentialsd/src/credential_service/mod.rs index 28188f03..39435bf9 100644 --- a/credentialsd/src/credential_service/mod.rs +++ b/credentialsd/src/credential_service/mod.rs @@ -11,11 +11,14 @@ use std::{ use async_trait::async_trait; use futures_lite::{FutureExt, Stream, StreamExt}; -use libwebauthn::pin::persistent_token::{MemoryPersistentTokenStore, PersistentTokenStore}; use libwebauthn::{ self, ops::webauthn::{GetAssertionResponse, MakeCredentialResponse}, }; +use libwebauthn::{ + available_transports, + pin::persistent_token::{MemoryPersistentTokenStore, PersistentTokenStore}, +}; use nfc::{NfcEvent, NfcHandler, NfcState, NfcStateInternal}; use tokio::sync::oneshot; @@ -199,16 +202,16 @@ impl Manage async fn get_available_public_key_devices(&self) -> Result, ()> { // We create the list new for each call, in case someone plugs in // an NFC-reader in the middle of an auth-flow - let mut devices = vec![ - Device { - id: String::from("0"), - transport: Transport::Usb, - }, - Device { + let mut devices = vec![Device { + id: String::from("0"), + transport: Transport::Usb, + }]; + if libwebauthn::transport::cable::is_available().await { + devices.push(Device { id: String::from("1"), transport: Transport::HybridQr, - }, - ]; + }); + } if libwebauthn::transport::nfc::is_nfc_available() { devices.push(Device { id: String::from("2"), @@ -221,11 +224,16 @@ impl Manage async fn start_discovery( &self, ) -> Pin + Send + 'static>> { - let usb = self - .get_usb_credential() - .await - .map(DeviceStateUpdate::from) - .boxed(); + let available_transports = available_transports().await; + let mut selected_transports = Vec::new(); + if available_transports.contains(&libwebauthn::Transport::Usb) { + let usb = self + .get_usb_credential() + .await + .map(DeviceStateUpdate::from) + .boxed(); + selected_transports.push(usb); + } /* TODO: Some cards that support NFC but not CCID (SoloKey Solo 2 NFC) cause a framing error immediately after establishing a libwebauthn @@ -234,18 +242,24 @@ impl Manage security keys, while at the same time supporting actual NFC cards and CCID. Maybe we can defer sending "Connected" to the UI until a user presence or verification message is sent. - let nfc = self - .get_nfc_credential() - .await - .map(DeviceStateUpdate::from) - .boxed(); + if available_transports.contains(&libwebauthn::Transport::Nfc) { + let nfc = self + .get_nfc_credential() + .await + .map(DeviceStateUpdate::from) + .boxed(); + selected_transports.push(nfc); + } */ - let hybrid = self - .get_hybrid_credential() - .await - .map(DeviceStateUpdate::from) - .boxed(); - futures::stream::select_all([usb, /* nfc, */ hybrid]).boxed() + if available_transports.contains(&libwebauthn::Transport::Hybrid) { + let hybrid = self + .get_hybrid_credential() + .await + .map(DeviceStateUpdate::from) + .boxed(); + selected_transports.push(hybrid); + } + futures::stream::select_all(selected_transports).boxed() } }