From 9462f836cf55d7d9bd5e93a9cf780e95572fa417 Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Thu, 2 Oct 2025 17:51:13 +0200 Subject: [PATCH 1/7] Add NFC --- credentialsd-common/Cargo.lock | 180 +++++- credentialsd-common/Cargo.toml | 3 +- credentialsd-common/src/client.rs | 1 + credentialsd-common/src/model.rs | 41 +- credentialsd-common/src/server.rs | 133 +++++ credentialsd-ui/Cargo.lock | 190 +++++-- credentialsd-ui/data/resources/ui/window.ui | 41 ++ credentialsd-ui/src/client.rs | 9 + credentialsd-ui/src/dbus.rs | 1 + .../src/gui/view_model/gtk/device.rs | 4 +- credentialsd-ui/src/gui/view_model/gtk/mod.rs | 38 +- .../src/gui/view_model/gtk/window.rs | 19 + credentialsd-ui/src/gui/view_model/mod.rs | 63 ++- credentialsd/Cargo.lock | 182 ++++-- credentialsd/Cargo.toml | 3 +- credentialsd/src/credential_service/mod.rs | 73 ++- credentialsd/src/credential_service/nfc.rs | 519 ++++++++++++++++++ credentialsd/src/dbus/flow_control.rs | 177 +++++- credentialsd/src/dbus/ui_control.rs | 22 + credentialsd/src/main.rs | 3 + 20 files changed, 1566 insertions(+), 136 deletions(-) create mode 100644 credentialsd/src/credential_service/nfc.rs diff --git a/credentialsd-common/Cargo.lock b/credentialsd-common/Cargo.lock index 0319b86..2ace38e 100644 --- a/credentialsd-common/Cargo.lock +++ b/credentialsd-common/Cargo.lock @@ -67,6 +67,35 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +[[package]] +name = "apdu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa1a20ca6e9b354419bd6c2714beb435203b3e942440e09016e6deeffb08ffd" +dependencies = [ + "apdu-core", + "apdu-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "apdu-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5ab921a56bbe68325ba6d3711ee2c681239fe4c9c295c6a1c2fe6992e27f86" + +[[package]] +name = "apdu-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd675f7ce10250005ac39b9ee8e618fe51370ce6f39170559726cdd0ff7fe7c" +dependencies = [ + "apdu-core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "asn1-rs" version = "0.7.1" @@ -91,7 +120,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -103,7 +132,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -114,7 +143,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -148,7 +177,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -197,6 +226,29 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.104", + "which", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -216,7 +268,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.104", "which", ] @@ -604,7 +656,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -727,7 +779,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -829,6 +881,17 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-winsdk" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" +dependencies = [ + "serde", + "serde_derive", + "winreg", +] + [[package]] name = "fnv" version = "1.0.7" @@ -916,7 +979,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1294,10 +1357,10 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ed4eb5e9a63098f7eeaf0fe0fc7b63c84977e8b8253ebe3707b124b6d8036" dependencies = [ "aes", + "apdu", + "apdu-core", "async-trait", "base64-url", "bitflags 2.9.1", @@ -1316,6 +1379,8 @@ dependencies = [ "hmac", "maplit", "mockall", + "nfc1", + "nfc1-sys", "num-derive", "num-traits", "num_enum", @@ -1425,7 +1490,29 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn", + "syn 2.0.104", +] + +[[package]] +name = "nfc1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d6dc2e4110af159c220d2d004661e380b6c40d93c5b04e839e4944f9d5291d" +dependencies = [ + "nfc1-sys", +] + +[[package]] +name = "nfc1-sys" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6652c6cdf52433ff143439595ffb4b945afafbe5f27cec8d2fc5dfb5832796e8" +dependencies = [ + "bindgen 0.65.1", + "cc", + "find-winsdk", + "pkg-config", + "vcpkg", ] [[package]] @@ -1462,7 +1549,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1502,7 +1589,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1628,6 +1715,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1736,7 +1829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.104", ] [[package]] @@ -2086,7 +2179,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2097,7 +2190,7 @@ checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2139,7 +2232,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2150,7 +2243,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2287,6 +2380,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.104" @@ -2306,7 +2410,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2347,7 +2451,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2358,7 +2462,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2420,7 +2524,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2510,7 +2614,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2587,6 +2691,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2640,7 +2750,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -2662,7 +2772,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2773,7 +2883,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2784,7 +2894,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3061,6 +3171,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +dependencies = [ + "serde", + "winapi", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -3110,7 +3230,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3141,7 +3261,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "zvariant_utils", ] @@ -3155,6 +3275,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn", + "syn 2.0.104", "winnow", ] diff --git a/credentialsd-common/Cargo.toml b/credentialsd-common/Cargo.toml index ae96c7c..e4b561d 100644 --- a/credentialsd-common/Cargo.toml +++ b/credentialsd-common/Cargo.toml @@ -7,6 +7,7 @@ license = "LGPL-3.0-only" [dependencies] futures-lite = "2.6.0" -libwebauthn = "0.2" +# libwebauthn = "0.2" +libwebauthn = { path = "../../libwebauthn/libwebauthn", features = ["libnfc"] } serde = { version = "1", features = ["derive"] } zvariant = "5.6.0" diff --git a/credentialsd-common/src/client.rs b/credentialsd-common/src/client.rs index af1f968..1bff01d 100644 --- a/credentialsd-common/src/client.rs +++ b/credentialsd-common/src/client.rs @@ -15,6 +15,7 @@ pub trait FlowController { fn get_hybrid_credential(&mut self) -> impl Future> + Send; fn get_usb_credential(&mut self) -> impl Future> + Send; + fn get_nfc_credential(&mut self) -> impl Future> + Send; fn subscribe( &mut self, ) -> impl Future< diff --git a/credentialsd-common/src/model.rs b/credentialsd-common/src/model.rs index b3cdd20..8d223cc 100644 --- a/credentialsd-common/src/model.rs +++ b/credentialsd-common/src/model.rs @@ -170,7 +170,7 @@ impl Transport { } } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum ViewUpdate { SetTitle(String), SetDevices(Vec), @@ -183,6 +183,9 @@ pub enum ViewUpdate { UsbNeedsUserVerification { attempts_left: Option }, UsbNeedsUserPresence, + NfcNeedsPin { attempts_left: Option }, + NfcNeedsUserVerification { attempts_left: Option }, + HybridNeedsQrCode(String), HybridConnecting, HybridConnected, @@ -262,10 +265,46 @@ pub enum UsbState { Failed(Error), } +/// Used to share public state between credential service and UI. +#[derive(Clone, Debug, Default)] +pub enum NfcState { + /// Not polling for FIDO USB device. + #[default] + Idle, + + /// Awaiting FIDO USB device to be plugged in. + Waiting, + + /// USB device connected, prompt user to tap + Connected, + + /// The device needs the PIN to be entered. + NeedsPin { attempts_left: Option }, + + /// The device needs on-device user verification. + NeedsUserVerification { attempts_left: Option }, + + // TODO: implement cancellation + // This isn't actually sent from the server. + //UserCancelled, + /// Multiple credentials have been found and the user has to select which to use + SelectCredential { + /// List of user-identities to decide which to use. + creds: Vec, + }, + + /// USB tapped, received credential + Completed, + + /// Interaction with the authenticator failed. + Failed(Error), +} + #[derive(Clone, Debug)] pub enum BackgroundEvent { UsbStateChanged(UsbState), HybridQrStateChanged(HybridState), + NfcStateChanged(NfcState), } #[derive(Debug, Clone)] diff --git a/credentialsd-common/src/server.rs b/credentialsd-common/src/server.rs index eaa9436..4c33494 100644 --- a/credentialsd-common/src/server.rs +++ b/credentialsd-common/src/server.rs @@ -28,6 +28,9 @@ impl From<&BackgroundEvent> for Structure<'_> { BackgroundEvent::HybridQrStateChanged(state) => { tag_value_to_struct(0x02, Some(Value::Structure(state.into()))) } + BackgroundEvent::NfcStateChanged(state) => { + tag_value_to_struct(0x03, Some(Value::Structure(state.into()))) + } } } } @@ -49,6 +52,10 @@ impl TryFrom<&Structure<'_>> for BackgroundEvent { (&structure).try_into()?, )) } + 0x03 => { + let structure: Structure = value.downcast_ref()?; + Ok(BackgroundEvent::NfcStateChanged((&structure).try_into()?)) + } _ => Err(zvariant::Error::Message(format!( "Unknown BackgroundEvent tag : {tag}" ))), @@ -336,6 +343,10 @@ impl Type for crate::model::UsbState { const SIGNATURE: &'static Signature = TAG_VALUE_SIGNATURE; } +impl Type for crate::model::NfcState { + const SIGNATURE: &'static Signature = TAG_VALUE_SIGNATURE; +} + impl From<&crate::model::UsbState> for Structure<'_> { fn from(value: &crate::model::UsbState) -> Self { let (tag, value): (u8, Option) = match value { @@ -462,6 +473,128 @@ impl<'de> Deserialize<'de> for crate::model::UsbState { } } +impl From<&crate::model::NfcState> for Structure<'_> { + fn from(value: &crate::model::NfcState) -> Self { + let (tag, value): (u8, Option) = match value { + crate::model::NfcState::Idle => (0x01, None), + crate::model::NfcState::Waiting => (0x02, None), + crate::model::NfcState::Connected => (0x04, None), + // TODO: Add pin request reason to this struct + crate::model::NfcState::NeedsPin { attempts_left } => { + let num = match attempts_left { + Some(num) => *num as i32, + None => -1, + }; + (0x05, Some(Value::I32(num))) + } + crate::model::NfcState::NeedsUserVerification { attempts_left } => { + let num = match attempts_left { + Some(num) => *num as i32, + None => -1, + }; + (0x06, Some(Value::I32(num))) + } + crate::model::NfcState::SelectCredential { creds } => { + let creds: Vec = creds.iter().map(Credential::from).collect(); + let value = Value::new(creds); + (0x08, Some(value)) + } + crate::model::NfcState::Completed => (0x09, None), + crate::model::NfcState::Failed(error) => { + let value = Value::<'_>::from(error.to_string()); + (0x0A, Some(value)) + } + }; + tag_value_to_struct(tag, value) + } +} + +impl TryFrom<&Structure<'_>> for crate::model::NfcState { + type Error = zvariant::Error; + + fn try_from(structure: &Structure<'_>) -> Result { + let (tag, value) = parse_tag_value_struct(structure)?; + match tag { + 0x01 => Ok(Self::Idle), + 0x02 => Ok(Self::Waiting), + 0x04 => Ok(Self::Connected), + 0x05 => { + let attempts_left: i32 = value.downcast_ref()?; + let attempts_left = if attempts_left == -1 { + None + } else { + Some(attempts_left as u32) + }; + Ok(Self::NeedsPin { attempts_left }) + } + 0x06 => { + let attempts_left: i32 = value.downcast_ref()?; + let attempts_left = if attempts_left == -1 { + None + } else { + Some(attempts_left as u32) + }; + Ok(Self::NeedsUserVerification { attempts_left }) + } + 0x08 => { + let creds: Array = value.downcast_ref()?; + let creds: Result, zvariant::Error> = creds + .iter() + .map(|v| v.try_to_owned().unwrap()) + .map(|v| { + let cred: Result = + Value::from(v) + .downcast::() + .map(crate::model::Credential::from); + cred + }) + .collect(); + Ok(Self::SelectCredential { creds: creds? }) + } + 0x09 => Ok(Self::Completed), + 0x0A => { + let err_code: &str = value.downcast_ref()?; + let err = match err_code { + "AuthenticatorError" => crate::model::Error::AuthenticatorError, + "NoCredentials" => crate::model::Error::NoCredentials, + "CredentialExcluded" => crate::model::Error::CredentialExcluded, + "PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted, + s => crate::model::Error::Internal(String::from(s)), + }; + Ok(Self::Failed(err)) + } + _ => Err(zvariant::Error::IncorrectType), + } + } +} + +impl TryFrom> for crate::model::NfcState { + type Error = zvariant::Error; + + fn try_from(structure: Structure<'_>) -> Result { + Self::try_from(&structure) + } +} + +impl Serialize for crate::model::NfcState { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let structure: Structure = self.into(); + structure.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for crate::model::NfcState { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserialize_tag_value(deserializer) + } +} + fn deserialize_tag_value<'a, 'de, T, D>(deserializer: D) -> Result where T: TryFrom>, diff --git a/credentialsd-ui/Cargo.lock b/credentialsd-ui/Cargo.lock index 762af0d..801392c 100644 --- a/credentialsd-ui/Cargo.lock +++ b/credentialsd-ui/Cargo.lock @@ -67,6 +67,35 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +[[package]] +name = "apdu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa1a20ca6e9b354419bd6c2714beb435203b3e942440e09016e6deeffb08ffd" +dependencies = [ + "apdu-core", + "apdu-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "apdu-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5ab921a56bbe68325ba6d3711ee2c681239fe4c9c295c6a1c2fe6992e27f86" + +[[package]] +name = "apdu-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd675f7ce10250005ac39b9ee8e618fe51370ce6f39170559726cdd0ff7fe7c" +dependencies = [ + "apdu-core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "asn1-rs" version = "0.7.1" @@ -91,7 +120,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -103,7 +132,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -225,7 +254,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -287,7 +316,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -327,7 +356,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -376,6 +405,29 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.104", + "which", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -395,7 +447,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.104", "which", ] @@ -878,7 +930,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1001,7 +1053,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1083,7 +1135,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1161,6 +1213,17 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "find-winsdk" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" +dependencies = [ + "serde", + "serde_derive", + "winreg", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1248,7 +1311,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1469,7 +1532,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1606,7 +1669,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1938,10 +2001,10 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ed4eb5e9a63098f7eeaf0fe0fc7b63c84977e8b8253ebe3707b124b6d8036" dependencies = [ "aes", + "apdu", + "apdu-core", "async-trait", "base64-url", "bitflags 2.9.1", @@ -1960,6 +2023,8 @@ dependencies = [ "hmac", "maplit", "mockall", + "nfc1", + "nfc1-sys", "num-derive", "num-traits", "num_enum", @@ -2109,7 +2174,29 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn", + "syn 2.0.104", +] + +[[package]] +name = "nfc1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d6dc2e4110af159c220d2d004661e380b6c40d93c5b04e839e4944f9d5291d" +dependencies = [ + "nfc1-sys", +] + +[[package]] +name = "nfc1-sys" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6652c6cdf52433ff143439595ffb4b945afafbe5f27cec8d2fc5dfb5832796e8" +dependencies = [ + "bindgen 0.65.1", + "cc", + "find-winsdk", + "pkg-config", + "vcpkg", ] [[package]] @@ -2169,7 +2256,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2209,7 +2296,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2404,6 +2491,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2537,7 +2630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.104", ] [[package]] @@ -2909,7 +3002,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2920,7 +3013,7 @@ checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2962,7 +3055,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2973,7 +3066,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3128,6 +3221,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.104" @@ -3147,7 +3251,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3226,7 +3330,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3237,7 +3341,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3308,7 +3412,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3415,7 +3519,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3541,6 +3645,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.0" @@ -3600,7 +3710,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -3635,7 +3745,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3756,7 +3866,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3767,7 +3877,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -4044,6 +4154,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +dependencies = [ + "serde", + "winapi", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -4118,7 +4238,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "zbus_names", "zvariant", "zvariant_utils", @@ -4153,7 +4273,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -4185,7 +4305,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "zvariant_utils", ] @@ -4199,6 +4319,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn", + "syn 2.0.104", "winnow", ] diff --git a/credentialsd-ui/data/resources/ui/window.ui b/credentialsd-ui/data/resources/ui/window.ui index c3c1639..7a80cec 100644 --- a/credentialsd-ui/data/resources/ui/window.ui +++ b/credentialsd-ui/data/resources/ui/window.ui @@ -107,6 +107,47 @@ + + + nfc + Plug in security key + + + vertical + + + media-removable-symbolic + + + + + + + + CredentialsUiWindow + + + + + + + + + + + + CredentialsUiWindow + + + + Enter your device PIN + + + + + + + hybrid_qr diff --git a/credentialsd-ui/src/client.rs b/credentialsd-ui/src/client.rs index a7aa3d9..fb59d56 100644 --- a/credentialsd-ui/src/client.rs +++ b/credentialsd-ui/src/client.rs @@ -53,6 +53,15 @@ impl FlowController for DbusCredentialClient { .map_err(|_| ()) } + async fn get_nfc_credential(&mut self) -> std::result::Result<(), ()> { + self.proxy() + .await? + .get_nfc_credential() + .await + .inspect_err(|err| tracing::error!("Failed to start NFC credential flow: {err}")) + .map_err(|_| ()) + } + async fn subscribe( &mut self, ) -> std::result::Result< diff --git a/credentialsd-ui/src/dbus.rs b/credentialsd-ui/src/dbus.rs index a22b72c..2bce739 100644 --- a/credentialsd-ui/src/dbus.rs +++ b/credentialsd-ui/src/dbus.rs @@ -19,6 +19,7 @@ pub trait FlowControlService { async fn get_hybrid_credential(&self) -> fdo::Result<()>; async fn get_usb_credential(&self) -> fdo::Result<()>; + async fn get_nfc_credential(&self) -> fdo::Result<()>; async fn select_device(&self, device_id: String) -> fdo::Result<()>; async fn enter_client_pin(&self, pin: String) -> fdo::Result<()>; diff --git a/credentialsd-ui/src/gui/view_model/gtk/device.rs b/credentialsd-ui/src/gui/view_model/gtk/device.rs index ad859ef..f90f174 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/device.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/device.rs @@ -57,8 +57,8 @@ fn transport_name(transport: &Transport) -> &'static str { Transport::Internal => "This device", Transport::HybridQr => "A mobile device", Transport::HybridLinked => "TODO: Linked Device", - Transport::Nfc => "An NFC device", - Transport::Usb => "A security key", + Transport::Nfc => "A security key (NFC)", + Transport::Usb => "A security key (USB)", // Transport::PasskeyProvider => ("symbolic-link-symbolic", "ACME Password Manager"), } } diff --git a/credentialsd-ui/src/gui/view_model/gtk/mod.rs b/credentialsd-ui/src/gui/view_model/gtk/mod.rs index 966c5f6..5224279 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/mod.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/mod.rs @@ -48,6 +48,9 @@ mod imp { #[property(get, set)] pub usb_pin_entry_visible: RefCell, + #[property(get, set)] + pub nfc_pin_entry_visible: RefCell, + #[property(get, set)] pub prompt: RefCell, @@ -157,6 +160,30 @@ impl ViewModel { }; view_model.set_prompt(prompt); } + ViewUpdate::NfcNeedsPin { attempts_left } => { + let prompt = match attempts_left { + Some(1) => { + "Enter your PIN. 1 attempt remaining.".to_string() + } + Some(attempts_left) => format!( + "Enter your PIN. {attempts_left} attempts remaining." + ), + None => "Enter your PIN.".to_string(), + }; + view_model.set_prompt(prompt); + view_model.set_nfc_pin_entry_visible(true); + } + ViewUpdate::NfcNeedsUserVerification { attempts_left } => { + let prompt = match attempts_left { + Some(1) => "Touch your device again. 1 attempt remaining." + .to_string(), + Some(attempts_left) => format!( + "Touch your device again. {attempts_left} attempts remaining." + ), + None => "Touch your device.".to_string(), + }; + view_model.set_prompt(prompt); + } ViewUpdate::UsbNeedsUserPresence => { view_model.set_prompt("Touch your device"); } @@ -228,7 +255,7 @@ impl ViewModel { Transport::Internal => "computer-symbolic", Transport::HybridQr => "phone-symbolic", Transport::HybridLinked => "phone-symbolic", - Transport::Nfc => "nfc-symbolic", + Transport::Nfc => "network-wireless-symbolic", Transport::Usb => "media-removable-symbolic", // Transport::PasskeyProvider => ("symbolic-link-symbolic", "ACME Password Manager"), // _ => "question-symbolic", @@ -309,6 +336,9 @@ impl ViewModel { Transport::HybridQr => { self.set_prompt(""); } + Transport::Nfc => { + self.set_prompt("Place your security key on your NFC reader"); + } Transport::Internal => {} _ => { todo!(); @@ -323,7 +353,11 @@ impl ViewModel { } pub async fn send_usb_device_pin(&self, pin: String) { - self.send_event(ViewEvent::UsbPinEntered(pin)).await; + self.send_event(ViewEvent::PinEntered(pin)).await; + } + + pub async fn send_nfc_device_pin(&self, pin: String) { + self.send_event(ViewEvent::PinEntered(pin)).await; } fn draw_qr_code(&self, qr_data: &str) -> Texture { diff --git a/credentialsd-ui/src/gui/view_model/gtk/window.rs b/credentialsd-ui/src/gui/view_model/gtk/window.rs index 121fc63..7864270 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/window.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/window.rs @@ -37,6 +37,9 @@ mod imp { #[template_child] pub usb_pin_entry: TemplateChild, + #[template_child] + pub nfc_pin_entry: TemplateChild, + #[template_child] pub qr_code_pic: TemplateChild, } @@ -56,6 +59,20 @@ mod imp { } )); } + + #[template_callback] + fn handle_nfc_pin_entered(&self, entry: >k::PasswordEntry) { + let view_model = &self.view_model.borrow(); + let view_model = view_model.as_ref().unwrap(); + let pin = entry.text().to_string(); + glib::spawn_future_local(clone!( + #[weak] + view_model, + async move { + view_model.send_nfc_device_pin(pin).await; + } + )); + } } impl Default for CredentialsUiWindow { @@ -66,6 +83,7 @@ mod imp { view_model: RefCell::default(), stack: TemplateChild::default(), usb_pin_entry: TemplateChild::default(), + nfc_pin_entry: TemplateChild::default(), qr_code_pic: TemplateChild::default(), } } @@ -164,6 +182,7 @@ impl CredentialsUiWindow { match d.transport().try_into() { Ok(Transport::Usb) => stack.set_visible_child_name("usb"), Ok(Transport::HybridQr) => stack.set_visible_child_name("hybrid_qr"), + Ok(Transport::Nfc) => stack.set_visible_child_name("nfc"), _ => {} }; } diff --git a/credentialsd-ui/src/gui/view_model/mod.rs b/credentialsd-ui/src/gui/view_model/mod.rs index 6f8ceae..ba97b97 100644 --- a/credentialsd-ui/src/gui/view_model/mod.rs +++ b/credentialsd-ui/src/gui/view_model/mod.rs @@ -7,6 +7,7 @@ use async_std::{ channel::{Receiver, Sender}, sync::Mutex as AsyncMutex, }; +use credentialsd_common::model::NfcState; use serde::{Deserialize, Serialize}; use tracing::{error, info}; @@ -102,6 +103,9 @@ impl ViewModel { Transport::HybridQr => { todo!("Implement cancellation for Hybrid QR"); } + Transport::Nfc => { + todo!("Implement cancellation for NFC"); + } _ => { todo!(); } @@ -114,6 +118,10 @@ impl ViewModel { let mut cred_service = self.flow_controller.lock().await; (*cred_service).get_usb_credential().await.unwrap(); } + Transport::Nfc => { + let mut cred_service = self.flow_controller.lock().await; + (*cred_service).get_nfc_credential().await.unwrap(); + } Transport::HybridQr => { let mut cred_service = self.flow_controller.lock().await; cred_service.get_hybrid_credential().await.unwrap(); @@ -146,7 +154,7 @@ impl ViewModel { self.select_device(&id).await; println!("Selected device {id}"); } - Event::View(ViewEvent::UsbPinEntered(pin)) => { + Event::View(ViewEvent::PinEntered(pin)) => { let mut cred_service = self.flow_controller.lock().await; if cred_service.enter_client_pin(pin).await.is_err() { error!("Failed to send pin to device"); @@ -241,6 +249,57 @@ impl ViewModel { } } } + Event::Background(BackgroundEvent::NfcStateChanged(state)) => { + match state { + NfcState::Connected => { + info!("Found NFC device") + } + + NfcState::NeedsPin { attempts_left } => { + self.tx_update + .send(ViewUpdate::NfcNeedsPin { attempts_left }) + .await + .unwrap(); + } + NfcState::NeedsUserVerification { attempts_left } => { + self.tx_update + .send(ViewUpdate::NfcNeedsUserVerification { attempts_left }) + .await + .unwrap(); + } + NfcState::Completed => { + self.tx_update.send(ViewUpdate::Completed).await.unwrap(); + } + NfcState::Idle | NfcState::Waiting => {} + NfcState::SelectCredential { creds } => { + self.tx_update + .send(ViewUpdate::SetCredentials(creds)) + .await + .unwrap(); + } + // TODO: Provide more specific error messages using the wrapped Error. + NfcState::Failed(err) => { + let error_msg = String::from(match err { + Error::NoCredentials => { + "No matching credentials found on this authenticator." + } + Error::PinAttemptsExhausted => { + "No more PIN attempts allowed. Try removing your device and plugging it back in." + } + Error::AuthenticatorError | Error::Internal(_) => { + "Something went wrong while retrieving a credential. Please try again later or use a different authenticator." + } + Error::CredentialExcluded => { + "This credential is already registered on this authenticator." + } + }); + self.tx_update + .send(ViewUpdate::Failed(error_msg)) + .await + .unwrap() + } + } + } Event::Background(BackgroundEvent::HybridQrStateChanged(state)) => { self.hybrid_qr_state = state.clone(); tracing::debug!("Received HybridQrState::{:?}", &state); @@ -297,7 +356,7 @@ pub enum ViewEvent { Initiated, DeviceSelected(String), CredentialSelected(String), - UsbPinEntered(String), + PinEntered(String), UserCancelled, } diff --git a/credentialsd/Cargo.lock b/credentialsd/Cargo.lock index ac6c2de..67035a0 100644 --- a/credentialsd/Cargo.lock +++ b/credentialsd/Cargo.lock @@ -67,6 +67,35 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +[[package]] +name = "apdu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa1a20ca6e9b354419bd6c2714beb435203b3e942440e09016e6deeffb08ffd" +dependencies = [ + "apdu-core", + "apdu-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "apdu-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5ab921a56bbe68325ba6d3711ee2c681239fe4c9c295c6a1c2fe6992e27f86" + +[[package]] +name = "apdu-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd675f7ce10250005ac39b9ee8e618fe51370ce6f39170559726cdd0ff7fe7c" +dependencies = [ + "apdu-core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "asn1-rs" version = "0.7.1" @@ -91,7 +120,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -103,7 +132,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -126,7 +155,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -148,7 +177,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -159,7 +188,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -193,7 +222,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -242,6 +271,29 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.104", + "which", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -261,7 +313,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.104", "which", ] @@ -690,7 +742,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -813,7 +865,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -895,7 +947,7 @@ checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -957,6 +1009,17 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-winsdk" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" +dependencies = [ + "serde", + "serde_derive", + "winreg", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1059,7 +1122,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1203,7 +1266,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1507,10 +1570,10 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ed4eb5e9a63098f7eeaf0fe0fc7b63c84977e8b8253ebe3707b124b6d8036" dependencies = [ "aes", + "apdu", + "apdu-core", "async-trait", "base64-url", "bitflags 2.9.0", @@ -1529,6 +1592,8 @@ dependencies = [ "hmac", "maplit", "mockall", + "nfc1", + "nfc1-sys", "num-derive", "num-traits", "num_enum", @@ -1653,7 +1718,29 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn", + "syn 2.0.104", +] + +[[package]] +name = "nfc1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d6dc2e4110af159c220d2d004661e380b6c40d93c5b04e839e4944f9d5291d" +dependencies = [ + "nfc1-sys", +] + +[[package]] +name = "nfc1-sys" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6652c6cdf52433ff143439595ffb4b945afafbe5f27cec8d2fc5dfb5832796e8" +dependencies = [ + "bindgen 0.65.1", + "cc", + "find-winsdk", + "pkg-config", + "vcpkg", ] [[package]] @@ -1713,7 +1800,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1752,7 +1839,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1853,7 +1940,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1932,6 +2019,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2040,7 +2133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.104", ] [[package]] @@ -2403,7 +2496,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2414,7 +2507,7 @@ checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2456,7 +2549,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2479,7 +2572,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2634,6 +2727,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.104" @@ -2653,7 +2757,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2726,7 +2830,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2737,7 +2841,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2808,7 +2912,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -2915,7 +3019,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3149,7 +3253,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3160,7 +3264,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3329,6 +3433,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +dependencies = [ + "serde", + "winapi", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -3398,7 +3512,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "zbus_names", "zvariant", "zvariant_utils", @@ -3433,7 +3547,7 @@ checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -3465,7 +3579,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "zvariant_utils", ] @@ -3479,6 +3593,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn", + "syn 2.0.104", "winnow", ] diff --git a/credentialsd/Cargo.toml b/credentialsd/Cargo.toml index 0b0fa5f..6e89dc9 100644 --- a/credentialsd/Cargo.toml +++ b/credentialsd/Cargo.toml @@ -14,7 +14,8 @@ async-trait = "0.1.88" base64 = "0.22.1" credentialsd-common = { path = "../credentialsd-common" } futures-lite = "2.6.0" -libwebauthn = "~0.2.2" +libwebauthn = { path = "../../libwebauthn/libwebauthn", features = ["libnfc"] } +# libwebauthn = "~0.2.2" openssl = "0.10.72" rand = "0.9.2" ring = "0.17.14" diff --git a/credentialsd/src/credential_service/mod.rs b/credentialsd/src/credential_service/mod.rs index 6bc8a03..ac2f14f 100644 --- a/credentialsd/src/credential_service/mod.rs +++ b/credentialsd/src/credential_service/mod.rs @@ -1,4 +1,5 @@ pub mod hybrid; +pub mod nfc; pub mod usb; use std::{ @@ -15,6 +16,7 @@ use libwebauthn::{ self, ops::webauthn::{GetAssertionResponse, MakeCredentialResponse}, }; +use nfc::{NfcEvent, NfcHandler, NfcState, NfcStateInternal}; use tokio::sync::oneshot::Sender; use credentialsd_common::{ @@ -60,7 +62,7 @@ impl RequestContext { } #[derive(Debug)] -pub struct CredentialService { +pub struct CredentialService { devices: Vec, /// Current request and channel to respond to caller. @@ -68,14 +70,24 @@ pub struct CredentialService hybrid_handler: H, usb_handler: U, + nfc_handler: N, ui_control_client: Arc, } -impl - CredentialService +impl< + H: HybridHandler + Debug, + U: UsbHandler + Debug, + N: NfcHandler + Debug, + UC: UiController + Debug, + > CredentialService { - pub fn new(hybrid_handler: H, usb_handler: U, ui_control_client: Arc) -> Self { + pub fn new( + hybrid_handler: H, + usb_handler: U, + nfc_handler: N, + ui_control_client: Arc, + ) -> Self { let devices = vec![ Device { id: String::from("0"), @@ -85,6 +97,10 @@ impl id: String::from("1"), transport: Transport::HybridQr, }, + Device { + id: String::from("2"), + transport: Transport::Nfc, + }, ]; Self { devices, @@ -93,6 +109,7 @@ impl hybrid_handler, usb_handler, + nfc_handler, ui_control_client, } @@ -194,7 +211,21 @@ impl Box::pin(UsbStateStream { inner: stream, ctx }) } else { tracing::error!( - "Attempted to start hybrid credential flow, but no request context was found." + "Attempted to start usb credential flow, but no request context was found." + ); + todo!("Handle error when context is not set up.") + } + } + + pub fn get_nfc_credential(&self) -> Pin + Send + 'static>> { + let guard = self.ctx.lock().unwrap(); + if let Some(RequestContext { ref request, .. }) = *guard { + let stream = self.nfc_handler.start(request); + let ctx = self.ctx.clone(); + Box::pin(NfcStateStream { inner: stream, ctx }) + } else { + tracing::error!( + "Attempted to start nfc credential flow, but no request context was found." ); todo!("Handle error when context is not set up.") } @@ -278,6 +309,35 @@ where } } +struct NfcStateStream { + inner: H, + ctx: Arc>>, +} + +impl Stream for NfcStateStream +where + H: Stream + Unpin + Sized, +{ + type Item = NfcState; + + fn poll_next( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + let ctx = &self.ctx.clone(); + match Box::pin(Box::pin(self).as_mut().inner.next()).poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(Some(NfcEvent { state })) => { + if let NfcStateInternal::Completed(response) = &state { + complete_request(ctx, response.clone()); + } + Poll::Ready(Some(state.into())) + } + Poll::Ready(None) => Poll::Ready(None), + } + } +} + fn complete_request(ctx: &Mutex>, response: CredentialResponse) { if let Some(ctx) = ctx.lock().unwrap().take() { ctx.send_response(Ok(response)); @@ -326,6 +386,7 @@ mod test { use super::{ hybrid::{test::DummyHybridHandler, HybridStateInternal}, + nfc::InProcessNfcHandler, AuthenticatorResponse, CredentialService, }; @@ -348,12 +409,14 @@ mod test { HybridStateInternal::Completed(Box::new(authenticator_response)), ]); let usb_handler = InProcessUsbHandler {}; + let nfc_handler = InProcessNfcHandler {}; let (ui_server, ui_client) = DummyUiServer::new(Vec::new()); let ui_server = Arc::new(ui_server); let user = ui_server.clone(); let cred_service = Arc::new(AsyncMutex::new(CredentialService::new( hybrid_handler, usb_handler, + nfc_handler, Arc::new(ui_client), ))); let (mut flow_server, flow_client) = DummyFlowServer::new(cred_service.clone()); diff --git a/credentialsd/src/credential_service/nfc.rs b/credentialsd/src/credential_service/nfc.rs new file mode 100644 index 0000000..c6b216c --- /dev/null +++ b/credentialsd/src/credential_service/nfc.rs @@ -0,0 +1,519 @@ +use std::time::Duration; + +use async_stream::stream; +use base64::{self, engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use futures_lite::Stream; +use libwebauthn::{ + ops::webauthn::GetAssertionResponse, + proto::CtapError, + transport::{nfc::device::NfcDevice, Channel, Device}, + webauthn::{Error as WebAuthnError, WebAuthn}, + UvUpdate, +}; +use tokio::sync::broadcast; +use tokio::sync::mpsc::{self, Receiver, Sender, WeakSender}; +use tracing::{debug, warn}; + +use credentialsd_common::model::{ + Credential, CredentialRequest, Error, GetAssertionResponseInternal, +}; + +use super::{AuthenticatorResponse, CredentialResponse}; + +pub(crate) trait NfcHandler { + fn start( + &self, + request: &CredentialRequest, + ) -> impl Stream + Send + Sized + Unpin + 'static; +} + +#[derive(Debug)] +pub struct InProcessNfcHandler {} + +impl InProcessNfcHandler { + async fn process_idle_waiting( + failures: &mut usize, + prev_nfc_state: &NfcStateInternal, + ) -> Result { + match libwebauthn::transport::nfc::list_devices().await { + Ok(mut hid_devices) => { + if hid_devices.is_empty() { + let state = NfcStateInternal::Waiting; + Ok(state) + } else { + Ok(NfcStateInternal::Connected(hid_devices.swap_remove(0))) + } + } + Err(err) => { + *failures += 1; + if *failures == 5 { + Err(Error::Internal(format!( + "Failed to list NFC authenticators: {:?}. Cancelling NFC state updates.", + err + ))) + } else { + tracing::warn!( + "Failed to list NFC authenticators: {:?}. Throttling NFC state updates", + err + ); + tokio::time::sleep(Duration::from_secs(1)).await; + Ok(prev_nfc_state.clone()) + } + } + } + } + + async fn process_select_credential( + response: GetAssertionResponse, + cred_rx: &mut Receiver, + ) -> Result { + match cred_rx.recv().await { + Some(cred_id) => { + let assertion = response + .assertions + .iter() + .find(|c| { + c.credential_id + .as_ref() + .map(|c| { + // In order to not expose the credential ID to the untrusted UI component, + // we hashed it, before sending it. So we have to re-hash all our credential + // IDs to identify the selected one. + URL_SAFE_NO_PAD + .encode(ring::digest::digest(&ring::digest::SHA256, &c.id)) + == cred_id + }) + .unwrap_or_default() + }) + .cloned(); + match assertion { + Some(assertion) => Ok(NfcStateInternal::Completed( + CredentialResponse::GetPublicKeyCredentialResponse(Box::new( + GetAssertionResponseInternal::new( + assertion, + "cross-platform".to_string(), + ), + )), + )), + None => Err(Error::NoCredentials), + } + } + None => { + tracing::debug!("cred channel closed before receiving cred from client."); + Err(Error::Internal( + "Cred channel disconnected prematurely".to_string(), + )) + } + } + } + + async fn process_user_interaction( + signal_rx: &mut Receiver>, + cred_tx: &Sender, + ) -> Result { + match signal_rx.recv().await { + Some(msg) => match msg { + Ok(NfcUvMessage::NeedsPin { + attempts_left, + pin_tx, + }) => Ok(NfcStateInternal::NeedsPin { + attempts_left, + pin_tx, + }), + Ok(NfcUvMessage::NeedsUserVerification { attempts_left }) => { + Ok(NfcStateInternal::NeedsUserVerification { attempts_left }) + } + Ok(NfcUvMessage::ReceivedCredentials(response)) => match *response { + AuthenticatorResponse::CredentialCreated(make_credential_response) => Ok( + NfcStateInternal::Completed(CredentialResponse::from_make_credential( + &make_credential_response, + &["nfc"], + "cross-platform", + )), + ), + AuthenticatorResponse::CredentialsAsserted(get_assertion_response) => { + if get_assertion_response.assertions.len() == 1 { + Ok(NfcStateInternal::Completed( + CredentialResponse::from_get_assertion( + &get_assertion_response.assertions[0], + "cross-platform", + ), + )) + } else { + Ok(NfcStateInternal::SelectCredential { + response: get_assertion_response, + cred_tx: cred_tx.clone(), + }) + } + } + }, + Err(err) => Err(err), + }, + None => Err(Error::Internal("NFC UV handler channel closed".to_string())), + } + } + + async fn process( + tx: Sender, + cred_request: CredentialRequest, + ) -> Result<(), Error> { + let mut state = NfcStateInternal::Idle; + let (signal_tx, mut signal_rx) = mpsc::channel(256); + let (cred_tx, mut cred_rx) = mpsc::channel(1); + debug!("polling for NFC status"); + let mut failures = 0; + // act on current NFC NFC state, send state changes to the stream, and + // loop until a credential or error is returned. + loop { + tracing::debug!("current nfc state: {:?}", state); + let prev_nfc_state = state; + let next_nfc_state = match prev_nfc_state { + NfcStateInternal::Idle | NfcStateInternal::Waiting => { + Self::process_idle_waiting(&mut failures, &prev_nfc_state).await + } + NfcStateInternal::Connected(device) => { + let signal_tx2 = signal_tx.clone(); + let cred_request = cred_request.clone(); + tokio::spawn(async move { + handle_events(&cred_request, device, &signal_tx2).await; + }); + Self::process_user_interaction(&mut signal_rx, &cred_tx).await + } + NfcStateInternal::NeedsPin { .. } + | NfcStateInternal::NeedsUserVerification { .. } => { + Self::process_user_interaction(&mut signal_rx, &cred_tx).await + } + NfcStateInternal::SelectCredential { + response, + cred_tx: _, + } => Self::process_select_credential(response, &mut cred_rx).await, + NfcStateInternal::Completed(_) => break Ok(()), + NfcStateInternal::Failed(err) => break Err(err), + }; + state = next_nfc_state.unwrap_or_else(NfcStateInternal::Failed); + tx.send(state.clone()).await.map_err(|_| { + Error::Internal("NFC state channel receiver closed prematurely".to_string()) + })?; + } + } +} + +async fn handle_events( + cred_request: &CredentialRequest, + mut device: NfcDevice, + signal_tx: &Sender>, +) { + let device_debug = device.to_string(); + match device.channel().await { + Err(err) => { + tracing::error!("Failed to open channel to NFC authenticator, cannot receive user verification events: {:?}", err); + } + Ok(mut channel) => { + let signal_tx2 = signal_tx.clone().downgrade(); + let ux_updates_rx = channel.get_ux_update_receiver(); + tokio::spawn(async move { + handle_nfc_updates(&signal_tx2, ux_updates_rx).await; + debug!("Reached end of NFC update task"); + }); + tracing::debug!( + "Polling for credential from NFC authenticator {}", + &device_debug + ); + let response: Result = loop { + let response = match cred_request { + CredentialRequest::CreatePublicKeyCredentialRequest(make_cred_request) => { + channel + .webauthn_make_credential(make_cred_request) + .await + .map(|response| { + NfcUvMessage::ReceivedCredentials(Box::new(response.into())) + }) + } + CredentialRequest::GetPublicKeyCredentialRequest(get_cred_request) => channel + .webauthn_get_assertion(get_cred_request) + .await + .map(|response| { + NfcUvMessage::ReceivedCredentials(Box::new(response.into())) + }), + }; + match response { + Ok(response) => { + tracing::debug!("Received credential from NFC authenticator"); + break Ok(response); + } + Err(WebAuthnError::Ctap(ctap_error)) + if ctap_error.is_retryable_user_error() => + { + warn!("Retrying WebAuthn credential operation"); + continue; + } + Err(err) => { + tracing::warn!( + "Failed to make/get credential with NFC authenticator: {:?}", + err + ); + break Err(err); + } + } + } + .map_err(|err| match err { + WebAuthnError::Ctap(CtapError::PINAuthBlocked) => Error::PinAttemptsExhausted, + WebAuthnError::Ctap(CtapError::NoCredentials) => Error::NoCredentials, + WebAuthnError::Ctap(CtapError::CredentialExcluded) => Error::CredentialExcluded, + _ => Error::AuthenticatorError, + }); + if let Err(err) = signal_tx.send(response).await { + tracing::error!("Failed to notify that ceremony completed: {:?}", err); + } + } + } +} + +impl NfcHandler for InProcessNfcHandler { + fn start( + &self, + request: &CredentialRequest, + ) -> impl Stream + Send + Sized + Unpin + 'static { + let request = request.clone(); + let (tx, mut rx) = mpsc::channel(32); + tokio::spawn(async move { + // TODO: instead of logging error here, push the errors into the + // stream so credential service can handle/forward them to the UI + if let Err(err) = InProcessNfcHandler::process(tx, request).await { + tracing::error!("Error getting credential from NFC: {:?}", err); + } + }); + Box::pin(stream! { + while let Some(state) = rx.recv().await { + yield NfcEvent { state } + } + }) + } +} + +// this exists to prevent making NfcStateInternal type public to the whole crate. +/// A message between NFC handler and credential service +pub struct NfcEvent { + pub(super) state: NfcStateInternal, +} + +/// Used to share internal state between handler and credential service +#[derive(Clone, Debug, Default)] +pub(super) enum NfcStateInternal { + /// Not polling for FIDO NFC device. + #[default] + Idle, + + /// Awaiting FIDO NFC device to be plugged in. + Waiting, + + /// NFC device connected, prompt user to tap + Connected(NfcDevice), + + /// The device needs the PIN to be entered. + NeedsPin { + attempts_left: Option, + pin_tx: mpsc::Sender, + }, + + /// The device needs on-device user verification. + NeedsUserVerification { attempts_left: Option }, + + /// Multiple credentials have been found and the user has to select which to use + SelectCredential { + response: GetAssertionResponse, + cred_tx: mpsc::Sender, + }, + + /// NFC tapped, received credential + Completed(CredentialResponse), + + /// There was an error while interacting with the authenticator. + Failed(Error), + // TODO: implement cancellation + // This isn't actually sent from the server. + //UserCancelled, +} + +/// Used to share public state between credential service and UI. +#[derive(Clone, Debug, Default)] +pub enum NfcState { + /// Not polling for FIDO NFC device. + #[default] + Idle, + + /// Awaiting FIDO NFC device to be plugged in. + Waiting, + + /// NFC device connected, prompt user to tap + Connected, + + /// The device needs the PIN to be entered. + NeedsPin { + attempts_left: Option, + pin_tx: mpsc::Sender, + }, + + /// The device needs on-device user verification. + NeedsUserVerification { attempts_left: Option }, + // TODO: implement cancellation + // This isn't actually sent from the server. + //UserCancelled, + + // Multiple credentials have been found and the user has to select which to use + // List of user-identities to decide which to use. + SelectCredential { + creds: Vec, + cred_tx: mpsc::Sender, + }, + + /// NFC tapped, received credential + Completed, + + /// Interaction with the authenticator failed. + Failed(Error), +} + +impl From for NfcState { + fn from(value: NfcStateInternal) -> Self { + match value { + NfcStateInternal::Idle => NfcState::Idle, + NfcStateInternal::Waiting => NfcState::Waiting, + NfcStateInternal::Connected(_) => NfcState::Connected, + NfcStateInternal::NeedsPin { + attempts_left, + pin_tx, + } => NfcState::NeedsPin { + attempts_left, + pin_tx, + }, + NfcStateInternal::NeedsUserVerification { attempts_left } => { + NfcState::NeedsUserVerification { attempts_left } + } + NfcStateInternal::Completed(_) => NfcState::Completed, + // NfcStateInternal::UserCancelled => NfcState:://UserCancelled, + NfcStateInternal::SelectCredential { response, cred_tx } => { + NfcState::SelectCredential { + creds: response + .assertions + .iter() + .map(|x| Credential { + id: x + .credential_id + .as_ref() + .map(|i| { + // In order to not expose the credential ID to the untrusted UI components, + // we hash and then encode it into a String. + URL_SAFE_NO_PAD + .encode(ring::digest::digest(&ring::digest::SHA256, &i.id)) + }) + .unwrap(), + + name: x + .user + .as_ref() + .and_then(|u| u.name.clone()) + .unwrap_or_else(|| String::from("")), + username: x + .user + .as_ref() + .map(|u| u.display_name.clone()) + .unwrap_or_default(), + }) + .collect(), + cred_tx, + } + } + NfcStateInternal::Failed(err) => NfcState::Failed(err), + } + } +} + +impl From for credentialsd_common::model::NfcState { + fn from(value: NfcState) -> Self { + Self::from(&value) + } +} +impl From<&NfcState> for credentialsd_common::model::NfcState { + fn from(value: &NfcState) -> Self { + match value { + NfcState::Idle => credentialsd_common::model::NfcState::Idle, + NfcState::Waiting => credentialsd_common::model::NfcState::Waiting, + NfcState::Connected => credentialsd_common::model::NfcState::Connected, + NfcState::NeedsPin { attempts_left, .. } => { + credentialsd_common::model::NfcState::NeedsPin { + attempts_left: *attempts_left, + } + } + NfcState::NeedsUserVerification { attempts_left } => { + credentialsd_common::model::NfcState::NeedsUserVerification { + attempts_left: *attempts_left, + } + } + NfcState::SelectCredential { creds, .. } => { + credentialsd_common::model::NfcState::SelectCredential { + creds: creds.to_owned(), + } + } + NfcState::Completed => credentialsd_common::model::NfcState::Completed, + NfcState::Failed(err) => credentialsd_common::model::NfcState::Failed(err.to_owned()), + } + } +} + +async fn handle_nfc_updates( + signal_tx: &WeakSender>, + mut state_rx: broadcast::Receiver, +) { + while let Ok(msg) = state_rx.recv().await { + let signal_tx = match signal_tx.upgrade() { + Some(tx) => tx, + None => break, + }; + match msg { + UvUpdate::UvRetry { attempts_left } => { + if let Err(err) = signal_tx + .send(Ok(NfcUvMessage::NeedsUserVerification { attempts_left })) + .await + { + tracing::error!("Authenticator requested user verficiation, but we cannot relay the message to credential service: {:?}", err); + } + } + UvUpdate::PinRequired(pin_update) => { + let (pin_tx, mut pin_rx) = mpsc::channel(1); + if let Err(err) = signal_tx + .send(Ok(NfcUvMessage::NeedsPin { + pin_tx, + attempts_left: pin_update.attempts_left, + })) + .await + { + tracing::error!("Authenticator requested a PIN from the user, but we cannot relay the message to the credential service: {:?}", err); + } + match pin_rx.recv().await { + Some(pin) => match pin_update.send_pin(&pin) { + Ok(()) => {} + Err(err) => tracing::error!("Error sending pin to device: {:?}", err), + }, + None => tracing::debug!("Pin channel closed before receiving pin from client."), + } + } + UvUpdate::PresenceRequired => { + tracing::debug!("Authenticator requested user presence, but that makes no sense for NFC. Skipping"); + } + } + } + debug!("NFC update channel closed."); +} + +/// Messages sent between NFC authenticator and handler for UV +enum NfcUvMessage { + NeedsPin { + attempts_left: Option, + pin_tx: mpsc::Sender, + }, + NeedsUserVerification { + attempts_left: Option, + }, + ReceivedCredentials(Box), +} diff --git a/credentialsd/src/dbus/flow_control.rs b/credentialsd/src/dbus/flow_control.rs index 9bd1e7e..e049254 100644 --- a/credentialsd/src/dbus/flow_control.rs +++ b/credentialsd/src/dbus/flow_control.rs @@ -25,6 +25,7 @@ use zbus::{ ObjectServer, }; +use crate::credential_service::nfc::{NfcHandler, NfcState}; use crate::credential_service::{ hybrid::{HybridHandler, HybridState}, usb::UsbHandler, @@ -36,9 +37,10 @@ pub const SERVICE_NAME: &str = "xyz.iinuwa.credentialsd.FlowControl"; pub async fn start_flow_control_service< H: HybridHandler + Debug + Send + Sync + 'static, U: UsbHandler + Debug + Send + Sync + 'static, + N: NfcHandler + Debug + Send + Sync + 'static, UC: UiController + Debug + Send + Sync + 'static, >( - credential_service: CredentialService, + credential_service: CredentialService, ) -> zbus::Result<( Connection, Sender<( @@ -55,9 +57,10 @@ pub async fn start_flow_control_service< FlowControlService { signal_state: Arc::new(AsyncMutex::new(SignalState::Idle)), svc, - usb_pin_tx: Arc::new(AsyncMutex::new(None)), - usb_cred_tx: Arc::new(AsyncMutex::new(None)), + pin_tx: Arc::new(AsyncMutex::new(None)), + cred_tx: Arc::new(AsyncMutex::new(None)), usb_event_forwarder_task: Arc::new(AsyncMutex::new(None)), + nfc_event_forwarder_task: Arc::new(AsyncMutex::new(None)), hybrid_event_forwarder_task: Arc::new(AsyncMutex::new(None)), }, )? @@ -73,12 +76,13 @@ pub async fn start_flow_control_service< Ok((conn, initiator_tx)) } -struct FlowControlService { +struct FlowControlService { signal_state: Arc>, - svc: Arc>>, - usb_pin_tx: Arc>>>, - usb_cred_tx: Arc>>>, + svc: Arc>>, + pin_tx: Arc>>>, + cred_tx: Arc>>>, usb_event_forwarder_task: Arc>>, + nfc_event_forwarder_task: Arc>>, hybrid_event_forwarder_task: Arc>>, } @@ -93,10 +97,11 @@ struct FlowControlService { default_service = "xyz.iinuwa.credentialsd.FlowControl", ) )] -impl FlowControlService +impl FlowControlService where H: HybridHandler + Debug + Send + Sync + 'static, U: UsbHandler + Debug + Send + Sync + 'static, + N: NfcHandler + Debug + Send + Sync + 'static, UC: UiController + Debug + Send + Sync + 'static, { async fn subscribe( @@ -139,7 +144,7 @@ where let signal_state = self.signal_state.clone(); let object_server = object_server.clone(); let task = tokio::spawn(async move { - let interface: zbus::Result>> = + let interface: zbus::Result>> = object_server.interface(SERVICE_PATH).await; let emitter = match interface { @@ -187,12 +192,12 @@ where #[zbus(object_server)] object_server: &ObjectServer, ) -> fdo::Result<()> { let mut stream = self.svc.lock().await.get_usb_credential(); - let usb_pin_tx = self.usb_pin_tx.clone(); - let usb_cred_tx = self.usb_cred_tx.clone(); + let usb_pin_tx = self.pin_tx.clone(); + let usb_cred_tx = self.cred_tx.clone(); let signal_state = self.signal_state.clone(); let object_server = object_server.clone(); let task = tokio::spawn(async move { - let interface: zbus::Result>> = + let interface: zbus::Result>> = object_server.interface(SERVICE_PATH).await; let emitter = match interface { @@ -241,15 +246,74 @@ where Ok(()) } + async fn get_nfc_credential( + &self, + #[zbus(object_server)] object_server: &ObjectServer, + ) -> fdo::Result<()> { + let mut stream = self.svc.lock().await.get_nfc_credential(); + let nfc_pin_tx = self.pin_tx.clone(); + let nfc_cred_tx = self.cred_tx.clone(); + let signal_state = self.signal_state.clone(); + let object_server = object_server.clone(); + let task = tokio::spawn(async move { + let interface: zbus::Result>> = + object_server.interface(SERVICE_PATH).await; + + let emitter = match interface { + Ok(ref i) => i.signal_emitter(), + Err(err) => { + tracing::error!("Failed to get connection to D-Bus to send signals: {err}"); + return; + } + }; + while let Some(state) = stream.next().await { + match credentialsd_common::model::BackgroundEvent::NfcStateChanged((&state).into()) + .try_into() + { + Err(err) => { + tracing::error!("Failed to serialize state update: {err}"); + break; + } + Ok(event) => match send_state_update(emitter, &signal_state, event).await { + Ok(_) => {} + Err(err) => { + tracing::error!("Failed to send state update to UI: {err}"); + break; + } + }, + }; + match state { + NfcState::NeedsPin { pin_tx, .. } => { + let mut nfc_pin_tx = nfc_pin_tx.lock().await; + let _ = nfc_pin_tx.insert(pin_tx); + } + NfcState::SelectCredential { cred_tx, .. } => { + let mut nfc_cred_tx = nfc_cred_tx.lock().await; + let _ = nfc_cred_tx.insert(cred_tx); + } + NfcState::Completed | NfcState::Failed(_) => { + break; + } + _ => {} + }; + } + }) + .abort_handle(); + if let Some(prev_task) = self.nfc_event_forwarder_task.lock().await.replace(task) { + prev_task.abort(); + } + Ok(()) + } + async fn enter_client_pin(&self, pin: String) -> fdo::Result<()> { - if let Some(pin_tx) = self.usb_pin_tx.lock().await.take() { + if let Some(pin_tx) = self.pin_tx.lock().await.take() { pin_tx.send(pin).await.unwrap(); } Ok(()) } async fn select_credential(&self, credential_id: String) -> fdo::Result<()> { - if let Some(cred_tx) = self.usb_cred_tx.lock().await.take() { + if let Some(cred_tx) = self.cred_tx.lock().await.take() { cred_tx.send(credential_id).await.unwrap(); } Ok(()) @@ -354,6 +418,7 @@ pub mod test { use crate::credential_service::{ hybrid::{HybridHandler, HybridState}, + nfc::{NfcHandler, NfcState}, usb::UsbHandler, CredentialService, UiController, UsbState, }; @@ -365,6 +430,7 @@ pub mod test { GetDevices, GetHybridCredential, GetUsbCredential, + GetNfcCredential, InitStream, } @@ -376,6 +442,7 @@ pub mod test { GetDevices(Vec), GetHybridCredential, GetUsbCredential, + GetNfcCredential, InitStream(Result + Send + 'static>>, ()>), } @@ -386,6 +453,7 @@ pub mod test { Self::GetDevices(arg0) => f.debug_tuple("GetDevices").field(arg0).finish(), Self::GetHybridCredential => f.debug_tuple("GetHybridCredential").finish(), Self::GetUsbCredential => f.debug_tuple("GetUsbCredential").finish(), + Self::GetNfcCredential => f.debug_tuple("GetNfcCredential").finish(), Self::InitStream(_) => f .debug_tuple("InitStream") .field(&String::from("")) @@ -442,6 +510,15 @@ pub mod test { } } + async fn get_nfc_credential(&mut self) -> Result<(), ()> { + let response = self.send(DummyFlowRequest::GetNfcCredential).await.unwrap(); + if let DummyFlowResponse::GetNfcCredential = response { + Ok(()) + } else { + Err(()) + } + } + async fn subscribe( &mut self, ) -> Result + Send + 'static>>, ()> { @@ -474,25 +551,28 @@ pub mod test { } #[derive(Debug)] - pub struct DummyFlowServer + pub struct DummyFlowServer where H: HybridHandler + Debug + Send + Sync, U: UsbHandler + Debug + Send + Sync, + N: NfcHandler + Debug + Send + Sync, UC: UiController + Debug + Send + Sync, { rx: mpsc::Receiver<(DummyFlowRequest, oneshot::Sender)>, - svc: Arc>>, + svc: Arc>>, bg_event_tx: Option>, - usb_pin_tx: Arc>>>, + pin_tx: Arc>>>, usb_event_forwarder_task: Arc>>, + nfc_event_forwarder_task: Arc>>, hybrid_event_forwarder_task: Arc>>, } impl< H: HybridHandler + Debug + Send + Sync, U: UsbHandler + Debug + Send + Sync, + N: NfcHandler + Debug + Send + Sync, UC: UiController + Debug + Send + Sync, - > DummyFlowServer + > DummyFlowServer { /* async fn send(&self, request: ManagementRequest) -> Result { @@ -514,14 +594,17 @@ pub mod test { } } */ - pub fn new(svc: Arc>>) -> (Self, DummyFlowClient) { + pub fn new( + svc: Arc>>, + ) -> (Self, DummyFlowClient) { let (request_tx, request_rx) = mpsc::channel(32); let server = Self { rx: request_rx, svc, bg_event_tx: None, - usb_pin_tx: Arc::new(AsyncMutex::new(None)), + pin_tx: Arc::new(AsyncMutex::new(None)), usb_event_forwarder_task: Arc::new(Mutex::new(None)), + nfc_event_forwarder_task: Arc::new(Mutex::new(None)), hybrid_event_forwarder_task: Arc::new(Mutex::new(None)), }; let client = DummyFlowClient { tx: request_tx }; @@ -549,6 +632,10 @@ pub mod test { self.get_usb_credential().await.unwrap(); DummyFlowResponse::GetUsbCredential } + DummyFlowRequest::GetNfcCredential => { + self.get_nfc_credential().await.unwrap(); + DummyFlowResponse::GetNfcCredential + } DummyFlowRequest::InitStream => { let rsp = self.subscribe().await; DummyFlowResponse::InitStream(rsp) @@ -616,7 +703,7 @@ pub mod test { async fn get_usb_credential(&mut self) -> Result<(), ()> { let mut stream = self.svc.lock().await.get_usb_credential(); if let Some(tx_weak) = self.bg_event_tx.as_ref().map(|t| t.clone().downgrade()) { - let usb_pin_tx = self.usb_pin_tx.clone(); + let usb_pin_tx = self.pin_tx.clone(); let task = tokio::spawn(async move { while let Some(state) = stream.next().await { if let Some(tx) = tx_weak.upgrade() { @@ -652,6 +739,45 @@ pub mod test { Ok(()) } + async fn get_nfc_credential(&mut self) -> Result<(), ()> { + let mut stream = self.svc.lock().await.get_nfc_credential(); + if let Some(tx_weak) = self.bg_event_tx.as_ref().map(|t| t.clone().downgrade()) { + let nfc_pin_tx = self.pin_tx.clone(); + let task = tokio::spawn(async move { + while let Some(state) = stream.next().await { + if let Some(tx) = tx_weak.upgrade() { + if tx + .send(BackgroundEvent::NfcStateChanged(state.clone().into())) + .await + .is_err() + { + tracing::debug!("Closing NFC background event forwarder"); + break; + } + match state { + NfcState::NeedsPin { pin_tx, .. } => { + let mut nfc_pin_tx = nfc_pin_tx.lock().await; + let _ = nfc_pin_tx.insert(pin_tx); + } + NfcState::Completed | NfcState::Failed(_) => { + break; + } + _ => {} + }; + } + } + }) + .abort_handle(); + if let Some(prev_task) = self.nfc_event_forwarder_task.lock().unwrap().replace(task) + { + prev_task.abort(); + } + } else { + tracing::warn!(target: "DummyFlowServer", "Output stream not initialized before setting up NFC state stream; some messages may be missed."); + } + Ok(()) + } + async fn subscribe( &mut self, ) -> Result + Send + 'static>>, ()> { @@ -668,7 +794,7 @@ pub mod test { } async fn enter_client_pin(&mut self, pin: String) -> Result<(), ()> { - if let Some(pin_tx) = self.usb_pin_tx.lock().await.take() { + if let Some(pin_tx) = self.pin_tx.lock().await.take() { pin_tx.send(pin).await.unwrap(); } Ok(()) @@ -686,14 +812,19 @@ pub mod test { impl< H: HybridHandler + Debug + Send + Sync, U: UsbHandler + Debug + Send + Sync, + N: NfcHandler + Debug + Send + Sync, UC: UiController + Debug + Send + Sync, - > Drop for DummyFlowServer + > Drop for DummyFlowServer { fn drop(&mut self) { if let Some(task) = self.usb_event_forwarder_task.lock().unwrap().take() { task.abort(); } + if let Some(task) = self.nfc_event_forwarder_task.lock().unwrap().take() { + task.abort(); + } + if let Some(task) = self.hybrid_event_forwarder_task.lock().unwrap().take() { task.abort(); } diff --git a/credentialsd/src/dbus/ui_control.rs b/credentialsd/src/dbus/ui_control.rs index e43283c..f344c81 100644 --- a/credentialsd/src/dbus/ui_control.rs +++ b/credentialsd/src/dbus/ui_control.rs @@ -167,6 +167,28 @@ pub mod test { .unwrap() } + pub async fn request_nfc_credential(&self) { + tracing::debug!( + target: "DummyUiServer", + "Received request_nfc_credential() request" + ); + loop { + if !self.stream_initialized.load(Ordering::Relaxed) { + self.stream_initialized_notifier.notified().await; + } else { + break; + } + } + self.svc + .lock() + .await + .as_mut() + .unwrap() + .get_nfc_credential() + .await + .unwrap() + } + pub async fn enter_client_pin(&self, pin: String) { tracing::debug!( target: "DummyUiServer", diff --git a/credentialsd/src/main.rs b/credentialsd/src/main.rs index e80915a..4090985 100644 --- a/credentialsd/src/main.rs +++ b/credentialsd/src/main.rs @@ -7,6 +7,8 @@ mod webauthn; use std::{error::Error, sync::Arc}; +use credential_service::nfc::InProcessNfcHandler; + use crate::{ credential_service::{ hybrid::InternalHybridHandler, usb::InProcessUsbHandler, CredentialService, @@ -36,6 +38,7 @@ async fn run() -> Result<(), Box> { let credential_service = CredentialService::new( InternalHybridHandler::new(), InProcessUsbHandler {}, + InProcessNfcHandler {}, Arc::new(ui_controller), ); let (_flow_control_conn, initiator) = From 3adefe704f2bce94eb68a21025ffc43e51e20cfe Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Thu, 9 Oct 2025 10:47:26 +0200 Subject: [PATCH 2/7] Deduplicate UI components for NFC and USB --- credentialsd-ui/data/resources/ui/window.ui | 51 ++----------------- credentialsd-ui/src/gui/view_model/gtk/mod.rs | 45 +++------------- .../src/gui/view_model/gtk/window.rs | 30 +++-------- 3 files changed, 19 insertions(+), 107 deletions(-) diff --git a/credentialsd-ui/data/resources/ui/window.ui b/credentialsd-ui/data/resources/ui/window.ui index 7a80cec..e798fc5 100644 --- a/credentialsd-ui/data/resources/ui/window.ui +++ b/credentialsd-ui/data/resources/ui/window.ui @@ -68,8 +68,8 @@ - usb - Plug in security key + usb_or_nfc + Connect a security key vertical @@ -90,51 +90,10 @@ - - + + - - - CredentialsUiWindow - - - - Enter your device PIN - - - - - - - - - - nfc - Plug in security key - - - vertical - - - media-removable-symbolic - - - - - - - - CredentialsUiWindow - - - - - - - - - - + CredentialsUiWindow diff --git a/credentialsd-ui/src/gui/view_model/gtk/mod.rs b/credentialsd-ui/src/gui/view_model/gtk/mod.rs index 5224279..c0b8dd0 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/mod.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/mod.rs @@ -46,10 +46,7 @@ mod imp { pub selected_device: RefCell>, #[property(get, set)] - pub usb_pin_entry_visible: RefCell, - - #[property(get, set)] - pub nfc_pin_entry_visible: RefCell, + pub usb_nfc_pin_entry_visible: RefCell, #[property(get, set)] pub prompt: RefCell, @@ -123,7 +120,7 @@ impl ViewModel { match rx.recv().await { Ok(update) => { // TODO: hack so I don't have to unset this in every event manually. - view_model.set_usb_pin_entry_visible(false); + view_model.set_usb_nfc_pin_entry_visible(false); match update { ViewUpdate::SetTitle(title) => view_model.set_title(title), ViewUpdate::SetDevices(devices) => { @@ -136,31 +133,8 @@ impl ViewModel { ViewUpdate::WaitingForDevice(device) => { view_model.waiting_for_device(&device) } - ViewUpdate::UsbNeedsPin { attempts_left } => { - let prompt = match attempts_left { - Some(1) => { - "Enter your PIN. 1 attempt remaining.".to_string() - } - Some(attempts_left) => format!( - "Enter your PIN. {attempts_left} attempts remaining." - ), - None => "Enter your PIN.".to_string(), - }; - view_model.set_prompt(prompt); - view_model.set_usb_pin_entry_visible(true); - } - ViewUpdate::UsbNeedsUserVerification { attempts_left } => { - let prompt = match attempts_left { - Some(1) => "Touch your device again. 1 attempt remaining." - .to_string(), - Some(attempts_left) => format!( - "Touch your device again. {attempts_left} attempts remaining." - ), - None => "Touch your device.".to_string(), - }; - view_model.set_prompt(prompt); - } - ViewUpdate::NfcNeedsPin { attempts_left } => { + ViewUpdate::UsbNeedsPin { attempts_left } + | ViewUpdate::NfcNeedsPin { attempts_left } => { let prompt = match attempts_left { Some(1) => { "Enter your PIN. 1 attempt remaining.".to_string() @@ -171,9 +145,10 @@ impl ViewModel { None => "Enter your PIN.".to_string(), }; view_model.set_prompt(prompt); - view_model.set_nfc_pin_entry_visible(true); + view_model.set_usb_nfc_pin_entry_visible(true); } - ViewUpdate::NfcNeedsUserVerification { attempts_left } => { + ViewUpdate::UsbNeedsUserVerification { attempts_left } + | ViewUpdate::NfcNeedsUserVerification { attempts_left } => { let prompt = match attempts_left { Some(1) => "Touch your device again. 1 attempt remaining." .to_string(), @@ -352,11 +327,7 @@ impl ViewModel { self.set_prompt("Multiple devices found. Please select with which to proceed."); } - pub async fn send_usb_device_pin(&self, pin: String) { - self.send_event(ViewEvent::PinEntered(pin)).await; - } - - pub async fn send_nfc_device_pin(&self, pin: String) { + pub async fn send_usb_nfc_device_pin(&self, pin: String) { self.send_event(ViewEvent::PinEntered(pin)).await; } diff --git a/credentialsd-ui/src/gui/view_model/gtk/window.rs b/credentialsd-ui/src/gui/view_model/gtk/window.rs index 7864270..9992fcd 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/window.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/window.rs @@ -35,10 +35,7 @@ mod imp { pub stack: TemplateChild, #[template_child] - pub usb_pin_entry: TemplateChild, - - #[template_child] - pub nfc_pin_entry: TemplateChild, + pub usb_nfc_pin_entry: TemplateChild, #[template_child] pub qr_code_pic: TemplateChild, @@ -47,21 +44,7 @@ mod imp { #[gtk::template_callbacks] impl CredentialsUiWindow { #[template_callback] - fn handle_usb_pin_entered(&self, entry: >k::PasswordEntry) { - let view_model = &self.view_model.borrow(); - let view_model = view_model.as_ref().unwrap(); - let pin = entry.text().to_string(); - glib::spawn_future_local(clone!( - #[weak] - view_model, - async move { - view_model.send_usb_device_pin(pin).await; - } - )); - } - - #[template_callback] - fn handle_nfc_pin_entered(&self, entry: >k::PasswordEntry) { + fn handle_usb_nfc_pin_entered(&self, entry: >k::PasswordEntry) { let view_model = &self.view_model.borrow(); let view_model = view_model.as_ref().unwrap(); let pin = entry.text().to_string(); @@ -69,7 +52,7 @@ mod imp { #[weak] view_model, async move { - view_model.send_nfc_device_pin(pin).await; + view_model.send_usb_nfc_device_pin(pin).await; } )); } @@ -82,8 +65,7 @@ mod imp { settings: gio::Settings::new(APP_ID), view_model: RefCell::default(), stack: TemplateChild::default(), - usb_pin_entry: TemplateChild::default(), - nfc_pin_entry: TemplateChild::default(), + usb_nfc_pin_entry: TemplateChild::default(), qr_code_pic: TemplateChild::default(), } } @@ -180,9 +162,9 @@ impl CredentialsUiWindow { .and_downcast_ref::() .expect("selected device to exist at notify"); match d.transport().try_into() { - Ok(Transport::Usb) => stack.set_visible_child_name("usb"), + Ok(Transport::Usb) => stack.set_visible_child_name("usb_or_nfc"), Ok(Transport::HybridQr) => stack.set_visible_child_name("hybrid_qr"), - Ok(Transport::Nfc) => stack.set_visible_child_name("nfc"), + Ok(Transport::Nfc) => stack.set_visible_child_name("usb_or_nfc"), _ => {} }; } From 57b82bc8886c3f4aebba1c23d12ab2b2b1406ae0 Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Thu, 9 Oct 2025 11:50:24 +0200 Subject: [PATCH 3/7] Show NFC-entry only, if a reader is available --- credentialsd/src/credential_service/mod.rs | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/credentialsd/src/credential_service/mod.rs b/credentialsd/src/credential_service/mod.rs index ac2f14f..c490eb9 100644 --- a/credentialsd/src/credential_service/mod.rs +++ b/credentialsd/src/credential_service/mod.rs @@ -63,8 +63,6 @@ impl RequestContext { #[derive(Debug)] pub struct CredentialService { - devices: Vec, - /// Current request and channel to respond to caller. ctx: Arc>>, @@ -88,23 +86,7 @@ impl< nfc_handler: N, ui_control_client: Arc, ) -> Self { - let devices = vec![ - Device { - id: String::from("0"), - transport: Transport::Usb, - }, - Device { - id: String::from("1"), - transport: Transport::HybridQr, - }, - Device { - id: String::from("2"), - transport: Transport::Nfc, - }, - ]; Self { - devices, - ctx: Arc::new(Mutex::new(None)), hybrid_handler, @@ -184,7 +166,25 @@ impl< } pub async fn get_available_public_key_devices(&self) -> Result, ()> { - Ok(self.devices.to_owned()) + // 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 { + id: String::from("1"), + transport: Transport::HybridQr, + }, + ]; + if libwebauthn::transport::nfc::is_nfc_available() { + devices.push(Device { + id: String::from("2"), + transport: Transport::Nfc, + }); + } + Ok(devices) } pub fn get_hybrid_credential( From c3b16bcc8fe50641e5edfa2802c51e5308d07e7c Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Thu, 9 Oct 2025 13:48:36 +0200 Subject: [PATCH 4/7] Switch to github-fork for now --- credentialsd-common/Cargo.toml | 2 +- credentialsd-ui/Cargo.lock | 21 + credentialsd/Cargo.lock | 1040 +++++++++++++++++++++----------- credentialsd/Cargo.toml | 2 +- 4 files changed, 701 insertions(+), 364 deletions(-) diff --git a/credentialsd-common/Cargo.toml b/credentialsd-common/Cargo.toml index e4b561d..776956d 100644 --- a/credentialsd-common/Cargo.toml +++ b/credentialsd-common/Cargo.toml @@ -8,6 +8,6 @@ license = "LGPL-3.0-only" [dependencies] futures-lite = "2.6.0" # libwebauthn = "0.2" -libwebauthn = { path = "../../libwebauthn/libwebauthn", features = ["libnfc"] } +libwebauthn = { git = "https://github.com/msirringhaus/libwebauthn.git", branch="nfc_followup", features = ["libnfc", "pcsc"] } serde = { version = "1", features = ["derive"] } zvariant = "5.6.0" diff --git a/credentialsd-ui/Cargo.lock b/credentialsd-ui/Cargo.lock index 801392c..73d7d13 100644 --- a/credentialsd-ui/Cargo.lock +++ b/credentialsd-ui/Cargo.lock @@ -2001,6 +2001,7 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" +source = "git+https://github.com/msirringhaus/libwebauthn.git?branch=nfc_followup#055246728ecab79ee8d8422004d0a493f3c709fb" dependencies = [ "aes", "apdu", @@ -2029,6 +2030,7 @@ dependencies = [ "num-traits", "num_enum", "p256", + "pcsc", "rand 0.8.5", "rustls", "serde", @@ -2491,6 +2493,25 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "pcsc" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" +dependencies = [ + "bitflags 2.9.1", + "pcsc-sys", +] + +[[package]] +name = "pcsc-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ef017e15d2e5592a9e39a346c1dbaea5120bab7ed7106b210ef58ebd97003" +dependencies = [ + "pkg-config", +] + [[package]] name = "peeking_take_while" version = "0.1.2" diff --git a/credentialsd/Cargo.lock b/credentialsd/Cargo.lock index 67035a0..b2b1711 100644 --- a/credentialsd/Cargo.lock +++ b/credentialsd/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "apdu" @@ -108,7 +108,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] @@ -120,7 +120,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -132,7 +132,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -155,7 +155,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -177,18 +177,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -202,15 +202,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.1" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-sys", "zeroize", @@ -218,22 +218,23 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.29.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" +checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" dependencies = [ - "bindgen 0.69.5", + "bindgen 0.72.1", "cc", "cmake", "dunce", "fs_extra", + "libloading", ] [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -241,7 +242,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -267,9 +268,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bindgen" @@ -288,33 +289,30 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", - "syn 2.0.104", + "syn 2.0.106", "which", ] [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 2.1.1", "shlex", - "syn 2.0.104", - "which", + "syn 2.0.106", ] [[package]] @@ -325,9 +323,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "blake2" @@ -367,20 +365,20 @@ dependencies = [ [[package]] name = "bluez-async" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353dc0fbd494ab1d066ffdff16f07acbea46ca63f507e093c07fdf2408d84300" +checksum = "84ae4213cc2a8dc663acecac67bbdad05142be4d8ef372b6903abf878b0c690a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "bluez-generated", "dbus", "dbus-tokio", "futures", - "itertools 0.13.0", + "itertools 0.14.0", "log", "serde", "serde-xml-rs", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "uuid", ] @@ -396,12 +394,12 @@ dependencies = [ [[package]] name = "btleplug" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b668804e0728a09c83cd9b94c9e1176717ea5522e8a3cb3688c2ac9a5f6e137c" +checksum = "c9a11621cb2c8c024e444734292482b1ad86fb50ded066cf46252e46643c8748" dependencies = [ "async-trait", - "bitflags 2.9.0", + "bitflags 2.9.4", "bluez-async", "dashmap 6.1.0", "dbus", @@ -414,13 +412,20 @@ dependencies = [ "objc2-foundation", "once_cell", "static_assertions", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tokio-stream", "uuid", "windows", + "windows-future", ] +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "byteorder" version = "1.5.0" @@ -444,22 +449,23 @@ dependencies = [ [[package]] name = "cbor-smol" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087b31faa4ad4ba21c9bd0209204eef424dae6424195aafc7242006b69fc8d" +checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" dependencies = [ "delog", "heapless", "heapless-bytes", - "serde", + "serde_core", ] [[package]] name = "cc" -version = "1.2.19" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -482,9 +488,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0390889d58f934f01cd49736275b4c2da15bcfc328c78ff2349907e6cabf22" +checksum = "1a2c5f3bf25ec225351aa1c8e230d04d880d3bd89dea133537dafad4ae291e5c" dependencies = [ "smallvec", "target-lexicon", @@ -492,9 +498,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -742,7 +748,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -780,15 +786,15 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dbus" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" dependencies = [ "futures-channel", "futures-util", "libc", "libdbus-sys", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -804,18 +810,18 @@ dependencies = [ [[package]] name = "delog" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2b93368262340c9d4441251b824500d1b641a50957ecf4219a2cc41b9eac8f" +checksum = "ed991f9823b19e8a0380e198dcbb6aa6ac82727b40bfecd2c6cc634f46b7e01c" dependencies = [ "log", ] [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -838,9 +844,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -865,7 +871,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -931,9 +937,9 @@ checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -941,13 +947,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -958,19 +964,19 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1009,6 +1015,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + [[package]] name = "find-winsdk" version = "0.2.0" @@ -1103,9 +1115,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1122,7 +1134,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1168,25 +1180,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -1201,15 +1213,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "gio" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "273d64c833fbbf7cd86c4cdced893c5d3f2f5d6aeb30fd0c30d172456ce8be2e" +checksum = "ed68efc12b748a771be2dccc49480d8584004382967c98323245fc3c38b74a42" dependencies = [ "futures-channel", "futures-core", @@ -1224,24 +1236,24 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8130f5810a839d74afc3a929c34a700bf194972bb034f2ecfe639682dd13cc" +checksum = "171ed2f6dd927abbe108cfd9eebff2052c335013f5879d55bab0dc1dee19b706" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "glib" -version = "0.21.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "690e8bcf8a819b5911d6ae79879226191d01253a4f602748072603defd5b9553" +checksum = "e1f2cbc4577536c849335878552f42086bfd25a8dcd6f54a18655cf818b20c8f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "futures-channel", "futures-core", "futures-executor", @@ -1258,22 +1270,22 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e772291ebea14c28eb11bb75741f62f4a4894f25e60ce80100797b6b010ef0f9" +checksum = "55eda916eecdae426d78d274a17b48137acdca6fba89621bd3705f2835bc719f" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "glib-sys" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2be4c74454fb4a6bd3328320737d0fa3d6939e2d570f5d846da00cb222f6a0" +checksum = "d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1" dependencies = [ "libc", "system-deps", @@ -1281,15 +1293,15 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gobject-sys" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab318a786f9abd49d388013b9161fa0ef8218ea6118ee7111c95e62186f7d31f" +checksum = "538e41d8776173ec107e7b0f2aceced60abc368d7e1d81c1f0e2ecd35f59080d" dependencies = [ "glib-sys", "libc", @@ -1309,12 +1321,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "e54c115d4f30f52c67202f079c5f9d8b49db4691f460fdb0b4c2e838261b2ba5" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -1334,9 +1347,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heapless" @@ -1434,12 +1447,12 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.16.0", ] [[package]] @@ -1452,6 +1465,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + [[package]] name = "iso7816" version = "0.1.4" @@ -1463,18 +1487,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -1522,14 +1546,24 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1544,15 +1578,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libdbus-sys" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" dependencies = [ "pkg-config", ] @@ -1564,19 +1598,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.5", ] [[package]] name = "libwebauthn" version = "0.2.2" +source = "git+https://github.com/msirringhaus/libwebauthn.git?branch=nfc_followup#055246728ecab79ee8d8422004d0a493f3c709fb" dependencies = [ "aes", "apdu", "apdu-core", "async-trait", "base64-url", - "bitflags 2.9.0", + "bitflags 2.9.4", "btleplug", "byteorder", "cbc", @@ -1598,6 +1633,7 @@ dependencies = [ "num-traits", "num_enum", "p256", + "pcsc", "rand 0.8.5", "rustls", "serde", @@ -1609,7 +1645,7 @@ dependencies = [ "sha2", "snow", "text_io", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", "tokio", "tokio-stream", @@ -1628,25 +1664,24 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "maplit" @@ -1656,9 +1691,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -1677,22 +1712,22 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -1718,7 +1753,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1749,7 +1784,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -1768,12 +1803,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "overload", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1800,7 +1834,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1823,23 +1857,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1864,7 +1899,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a644b62ffb826a5277f536cf0f701493de420b13d40e700c452c36567771111" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "objc2", "objc2-foundation", ] @@ -1881,7 +1916,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2", "libc", "objc2", @@ -1889,9 +1924,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -1919,11 +1954,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -1940,7 +1975,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1951,9 +1986,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -1971,12 +2006,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "p256" version = "0.13.2" @@ -1998,9 +2027,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2008,15 +2037,34 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", +] + +[[package]] +name = "pcsc" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd833ecf8967e65934c49d3521a175929839bf6d0e497f3bd0d3a2ca08943da" +dependencies = [ + "bitflags 2.9.4", + "pcsc-sys", +] + +[[package]] +name = "pcsc-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ef017e15d2e5592a9e39a346c1dbaea5120bab7ed7106b210ef58ebd97003" +dependencies = [ + "pkg-config", ] [[package]] @@ -2128,12 +2176,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.33" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2148,36 +2196,36 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.6", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -2226,7 +2274,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2235,23 +2283,23 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -2261,9 +2309,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -2272,9 +2320,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rfc6979" @@ -2294,7 +2342,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -2302,9 +2350,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -2312,6 +2360,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2336,7 +2390,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2345,22 +2399,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", @@ -2395,9 +2449,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -2405,6 +2459,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.20" @@ -2422,11 +2482,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2452,11 +2512,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "core-foundation", "core-foundation-sys", "libc", @@ -2465,9 +2525,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2475,16 +2535,17 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -2496,7 +2557,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2507,14 +2568,14 @@ checksum = "8f68cf7478db8b81abcf71b6d195a34a4891bd3d39868731c4d73194d74ec7a3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "serde-xml-rs" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" dependencies = [ "log", "serde", @@ -2524,11 +2585,12 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -2541,27 +2603,37 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2572,7 +2644,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2607,9 +2679,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2633,9 +2705,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -2658,9 +2730,9 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "snow" @@ -2672,7 +2744,7 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "getrandom 0.3.2", + "getrandom 0.3.3", "p256", "ring", "rustc_version", @@ -2682,12 +2754,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2711,9 +2783,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -2740,9 +2812,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2751,13 +2823,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2781,15 +2853,15 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", - "rustix 1.0.8", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -2815,11 +2887,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -2830,35 +2902,34 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2871,15 +2942,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2887,21 +2958,23 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2912,14 +2985,14 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -2955,9 +3028,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -2968,35 +3041,65 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime 0.7.2", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ "winnow", ] @@ -3013,20 +3116,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -3045,9 +3148,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -3072,15 +3175,15 @@ dependencies = [ "rustls", "rustls-pki-types", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.17", "utf-8", ] [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uds_windows" @@ -3095,9 +3198,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "universal-hash" @@ -3123,12 +3226,14 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.16.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -3167,17 +3272,85 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ - "wit-bindgen-rt", + "unicode-ident", ] [[package]] @@ -3210,11 +3383,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3225,55 +3398,110 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.57.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ "windows-core", - "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", + "windows-link 0.1.3", "windows-result", - "windows-targets 0.52.6", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.57.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "windows-interface" -version = "0.57.0" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", ] [[package]] name = "windows-result" -version = "0.1.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -3303,6 +3531,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3327,13 +3573,39 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3346,6 +3618,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3358,6 +3636,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3370,12 +3654,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3388,6 +3684,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3400,6 +3702,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3412,6 +3720,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3424,11 +3738,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -3444,13 +3764,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "x509-parser" @@ -3465,21 +3782,21 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.12", + "thiserror 2.0.17", "time", ] [[package]] name = "xml-rs" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" [[package]] name = "zbus" -version = "5.9.0" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad" +checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" dependencies = [ "async-broadcast", "async-recursion", @@ -3496,7 +3813,7 @@ dependencies = [ "tokio", "tracing", "uds_windows", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "winnow", "zbus_macros", "zbus_names", @@ -3505,14 +3822,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.9.0" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659" +checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "zbus_names", "zvariant", "zvariant_utils", @@ -3532,35 +3849,35 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zvariant" -version = "5.6.0" +version = "5.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91b3680bb339216abd84714172b5138a4edac677e641ef17e1d8cb1b3ca6e6f" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" dependencies = [ "endi", "enumflags2", @@ -3572,27 +3889,26 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.6.0" +version = "5.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8c68501be459a8dbfffbe5d792acdd23b4959940fc87785fb013b32edbc208" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" dependencies = [ "proc-macro2", "quote", "serde", - "static_assertions", - "syn 2.0.104", + "syn 2.0.106", "winnow", ] diff --git a/credentialsd/Cargo.toml b/credentialsd/Cargo.toml index 6e89dc9..0fc2469 100644 --- a/credentialsd/Cargo.toml +++ b/credentialsd/Cargo.toml @@ -14,7 +14,7 @@ async-trait = "0.1.88" base64 = "0.22.1" credentialsd-common = { path = "../credentialsd-common" } futures-lite = "2.6.0" -libwebauthn = { path = "../../libwebauthn/libwebauthn", features = ["libnfc"] } +libwebauthn = { git = "https://github.com/msirringhaus/libwebauthn.git", branch="nfc_followup", features = ["libnfc","pcsc"] } # libwebauthn = "~0.2.2" openssl = "0.10.72" rand = "0.9.2" From 828337ed265153217e85aae73acae996e062b87a Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Fri, 24 Oct 2025 08:18:13 +0200 Subject: [PATCH 5/7] Also mention security cards for NFC --- credentialsd-ui/src/gui/view_model/gtk/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/credentialsd-ui/src/gui/view_model/gtk/device.rs b/credentialsd-ui/src/gui/view_model/gtk/device.rs index f90f174..bc692ac 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/device.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/device.rs @@ -57,7 +57,7 @@ fn transport_name(transport: &Transport) -> &'static str { Transport::Internal => "This device", Transport::HybridQr => "A mobile device", Transport::HybridLinked => "TODO: Linked Device", - Transport::Nfc => "A security key (NFC)", + Transport::Nfc => "A security key or card (NFC)", Transport::Usb => "A security key (USB)", // Transport::PasskeyProvider => ("symbolic-link-symbolic", "ACME Password Manager"), } From ff18e592edd2d00fce49e314da9162d65b4ea54e Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Fri, 24 Oct 2025 08:24:54 +0200 Subject: [PATCH 6/7] Install NFC-system libraries in the github-CI --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b61d542..adc3d2e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: curl git build-essential \ libgtk-4-dev gettext libdbus-1-dev libssl-dev libudev-dev \ libxml2-utils desktop-file-utils \ - python3-pip ninja-build + python3-pip ninja-build libnfc-dev libpcsclite-dev - name: Install Meson run: | # Newer version needed for --interactive flag needed below From b2e585976687fe5bd3328b7e51faf961deb606a6 Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Thu, 30 Oct 2025 09:05:17 +0100 Subject: [PATCH 7/7] Switch back to official libwebauthn repo --- credentialsd-common/Cargo.toml | 2 +- credentialsd-ui/Cargo.lock | 2 +- credentialsd/Cargo.lock | 2 +- credentialsd/Cargo.toml | 2 +- credentialsd/src/credential_service/nfc.rs | 12 +++--------- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/credentialsd-common/Cargo.toml b/credentialsd-common/Cargo.toml index 776956d..aee5050 100644 --- a/credentialsd-common/Cargo.toml +++ b/credentialsd-common/Cargo.toml @@ -8,6 +8,6 @@ license = "LGPL-3.0-only" [dependencies] futures-lite = "2.6.0" # libwebauthn = "0.2" -libwebauthn = { git = "https://github.com/msirringhaus/libwebauthn.git", branch="nfc_followup", features = ["libnfc", "pcsc"] } +libwebauthn = { git = "https://github.com/linux-credentials/libwebauthn.git", revision="604b53b", features = ["libnfc","pcsc"] } serde = { version = "1", features = ["derive"] } zvariant = "5.6.0" diff --git a/credentialsd-ui/Cargo.lock b/credentialsd-ui/Cargo.lock index 73d7d13..2396be5 100644 --- a/credentialsd-ui/Cargo.lock +++ b/credentialsd-ui/Cargo.lock @@ -2001,7 +2001,7 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" -source = "git+https://github.com/msirringhaus/libwebauthn.git?branch=nfc_followup#055246728ecab79ee8d8422004d0a493f3c709fb" +source = "git+https://github.com/linux-credentials/libwebauthn.git#604b53b6ec86f4c0239518d43cb33f9302d4fcb3" dependencies = [ "aes", "apdu", diff --git a/credentialsd/Cargo.lock b/credentialsd/Cargo.lock index b2b1711..bbe63a3 100644 --- a/credentialsd/Cargo.lock +++ b/credentialsd/Cargo.lock @@ -1604,7 +1604,7 @@ dependencies = [ [[package]] name = "libwebauthn" version = "0.2.2" -source = "git+https://github.com/msirringhaus/libwebauthn.git?branch=nfc_followup#055246728ecab79ee8d8422004d0a493f3c709fb" +source = "git+https://github.com/linux-credentials/libwebauthn.git#604b53b6ec86f4c0239518d43cb33f9302d4fcb3" dependencies = [ "aes", "apdu", diff --git a/credentialsd/Cargo.toml b/credentialsd/Cargo.toml index 0fc2469..9f2fa89 100644 --- a/credentialsd/Cargo.toml +++ b/credentialsd/Cargo.toml @@ -14,7 +14,7 @@ async-trait = "0.1.88" base64 = "0.22.1" credentialsd-common = { path = "../credentialsd-common" } futures-lite = "2.6.0" -libwebauthn = { git = "https://github.com/msirringhaus/libwebauthn.git", branch="nfc_followup", features = ["libnfc","pcsc"] } +libwebauthn = { git = "https://github.com/linux-credentials/libwebauthn.git", revision="604b53b", features = ["libnfc","pcsc"] } # libwebauthn = "~0.2.2" openssl = "0.10.72" rand = "0.9.2" diff --git a/credentialsd/src/credential_service/nfc.rs b/credentialsd/src/credential_service/nfc.rs index c6b216c..b96307a 100644 --- a/credentialsd/src/credential_service/nfc.rs +++ b/credentialsd/src/credential_service/nfc.rs @@ -35,15 +35,9 @@ impl InProcessNfcHandler { failures: &mut usize, prev_nfc_state: &NfcStateInternal, ) -> Result { - match libwebauthn::transport::nfc::list_devices().await { - Ok(mut hid_devices) => { - if hid_devices.is_empty() { - let state = NfcStateInternal::Waiting; - Ok(state) - } else { - Ok(NfcStateInternal::Connected(hid_devices.swap_remove(0))) - } - } + match libwebauthn::transport::nfc::get_nfc_device().await { + Ok(None) => Ok(NfcStateInternal::Waiting), + Ok(Some(hid_device)) => Ok(NfcStateInternal::Connected(hid_device)), Err(err) => { *failures += 1; if *failures == 5 {