diff --git a/credentialsd-common/src/model.rs b/credentialsd-common/src/model.rs index ff7f1c58..7b4a8a80 100644 --- a/credentialsd-common/src/model.rs +++ b/credentialsd-common/src/model.rs @@ -266,37 +266,39 @@ pub enum NfcState { Failed(Error), } -pub enum BackendRequest { +pub enum UserInteractedEvent { /// Start Hybrid discovery - StartHybridDiscovery, + HybridDiscoveryRequested, /// Start NFC discovery - StartNfcDiscovery, + NfcDiscoveryRequested, /// Start USB discovery - StartUsbDiscovery, + UsbDiscoveryRequested, /// Send client PIN - EnterClientPin(String), + ClientPinEntered(String), /// Select a credential by credential ID - SelectCredential(String), + CredentialSelected(String), - CancelRequest, + RequestCancelled, } -impl std::fmt::Debug for BackendRequest { +impl std::fmt::Debug for UserInteractedEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::StartHybridDiscovery => write!(f, "StartHybridDiscovery"), - Self::StartNfcDiscovery => write!(f, "StartNfcDiscovery"), - Self::StartUsbDiscovery => write!(f, "StartUsbDiscovery"), - Self::EnterClientPin(_) => f + Self::HybridDiscoveryRequested => write!(f, "StartHybridDiscovery"), + Self::NfcDiscoveryRequested => write!(f, "StartNfcDiscovery"), + Self::UsbDiscoveryRequested => write!(f, "StartUsbDiscovery"), + Self::ClientPinEntered(_) => f .debug_tuple("EnterClientPin") .field(&"******".to_string()) .finish(), - Self::SelectCredential(arg0) => f.debug_tuple("SelectCredential").field(arg0).finish(), - Self::CancelRequest => write!(f, "CancelRequest"), + Self::CredentialSelected(arg0) => { + f.debug_tuple("SelectCredential").field(arg0).finish() + } + Self::RequestCancelled => write!(f, "CancelRequest"), } } } diff --git a/credentialsd-common/src/server.rs b/credentialsd-common/src/server.rs index f05d999d..5d25925b 100644 --- a/credentialsd-common/src/server.rs +++ b/credentialsd-common/src/server.rs @@ -11,7 +11,7 @@ use zvariant::{ SerializeDict, Signature, Str, Structure, StructureBuilder, Type, Value, signature::Fields, }; -use crate::model::{BackendRequest, Device, Operation, RequestId, RequestingApplication}; +use crate::model::{Device, Operation, RequestId, RequestingApplication, UserInteractedEvent}; const TAG_VALUE_SIGNATURE: &Signature = &Signature::Structure(Fields::Static { fields: &[&Signature::U32, &Signature::Variant], @@ -49,12 +49,12 @@ const BACKGROUND_EVENT_ERROR_CREDENTIAL_EXCLUDED: u32 = 0x80000006; const BACKGROUND_EVENT_ERROR_PIN_ATTEMPTS_EXHAUSTED: u32 = 0x80000007; const BACKGROUND_EVENT_ERROR_PIN_NOT_SET: u32 = 0x80000008; -const BACKEND_REQUEST_START_HYBRID_DISCOVERY: u32 = 0x01; -const BACKEND_REQUEST_START_USB_DISCOVERY: u32 = 0x02; -const BACKEND_REQUEST_START_NFC_DISCOVERY: u32 = 0x03; -const BACKEND_REQUEST_ENTER_CLIENT_PIN: u32 = 0x04; -const BACKEND_REQUEST_SELECT_CREDENTIAL: u32 = 0x05; -const BACKEND_REQUEST_CANCEL_REQUEST: u32 = 0x06; +const USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED: u32 = 0x01; +const USER_INTERACTED_EVENT_NFC_DISCOVERY_REQUESTED: u32 = 0x02; +const USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED: u32 = 0x03; +const USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED: u32 = 0x04; +const USER_INTERACTED_EVENT_CREDENTIAL_SELECTED: u32 = 0x05; +const USER_INTERACTED_EVENT_REQUEST_CANCELLED: u32 = 0x06; /// Flattened enum BackgroundEvent for sending across D-Bus. #[derive(Debug, Clone, PartialEq)] @@ -274,94 +274,6 @@ impl<'de> Deserialize<'de> for BackgroundEvent { } } -impl Type for BackendRequest { - const SIGNATURE: &'static Signature = TAG_VALUE_SIGNATURE; -} - -impl From<&BackendRequest> for Structure<'_> { - fn from(value: &BackendRequest) -> Self { - match value { - BackendRequest::StartHybridDiscovery => tag_value_to_struct(0x01, None), - BackendRequest::StartNfcDiscovery => tag_value_to_struct(0x02, None), - BackendRequest::StartUsbDiscovery => tag_value_to_struct(0x03, None), - BackendRequest::EnterClientPin(pin) => { - tag_value_to_struct(0x04, Some(Value::Str(pin.into()))) - } - BackendRequest::SelectCredential(credential_id) => { - tag_value_to_struct(0x05, Some(Value::Str(credential_id.into()))) - } - BackendRequest::CancelRequest => tag_value_to_struct(0x06, None), - } - } -} - -impl TryFrom<&Structure<'_>> for BackendRequest { - type Error = zvariant::Error; - - fn try_from(value: &Structure<'_>) -> Result { - let (tag, value) = parse_tag_value_struct(value)?; - - match tag { - 0x01 => Ok(BackendRequest::StartHybridDiscovery), - 0x02 => Ok(BackendRequest::StartNfcDiscovery), - 0x03 => Ok(BackendRequest::StartUsbDiscovery), - 0x04 => { - let s: Str = value.downcast_ref()?; - if s.is_empty() { - return Err(zvariant::Error::invalid_length( - s.len(), - &"a non-empty string", - )); - } - Ok(BackendRequest::EnterClientPin(s.as_str().to_string())) - } - 0x05 => { - let s: Str = value.downcast_ref()?; - if s.is_empty() { - return Err(zvariant::Error::invalid_length( - s.len(), - &"a non-empty string", - )); - } - Ok(BackendRequest::SelectCredential(s.as_str().to_string())) - } - 0x06 => Ok(BackendRequest::CancelRequest), - _ => Err(zvariant::Error::Message(format!( - "Unknown BackendRequest tag : {tag}" - ))), - } - } -} - -impl Serialize for BackendRequest { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let structure: Structure = self.into(); - structure.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for BackendRequest { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let d = Structure::deserializer_for_signature(TAG_VALUE_SIGNATURE).map_err(|err| { - D::Error::custom(format!( - "could not create deserializer for tag-value struct: {err}" - )) - })?; - let structure = d.deserialize(deserializer)?; - (&structure).try_into().map_err(|err| { - D::Error::custom(format!( - "could not deserialize structure into BackendRequest: {err}" - )) - }) - } -} - #[derive(Clone, Debug, DeserializeDict, Type)] #[zvariant(signature = "dict")] pub struct CreateCredentialRequest { @@ -507,6 +419,116 @@ impl From for GetCredentialResponse { } } +impl Type for UserInteractedEvent { + const SIGNATURE: &'static Signature = TAG_VALUE_SIGNATURE; +} + +impl From<&UserInteractedEvent> for Structure<'_> { + fn from(value: &UserInteractedEvent) -> Self { + match value { + UserInteractedEvent::HybridDiscoveryRequested => { + tag_value_to_struct(USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED, None) + } + UserInteractedEvent::NfcDiscoveryRequested => { + tag_value_to_struct(USER_INTERACTED_EVENT_NFC_DISCOVERY_REQUESTED, None) + } + UserInteractedEvent::UsbDiscoveryRequested => { + tag_value_to_struct(USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED, None) + } + UserInteractedEvent::ClientPinEntered(pin) => tag_value_to_struct( + USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED, + Some(Value::Str(pin.into())), + ), + UserInteractedEvent::CredentialSelected(credential_id) => tag_value_to_struct( + USER_INTERACTED_EVENT_CREDENTIAL_SELECTED, + Some(Value::Str(credential_id.into())), + ), + UserInteractedEvent::RequestCancelled => { + tag_value_to_struct(USER_INTERACTED_EVENT_REQUEST_CANCELLED, None) + } + } + } +} + +impl TryFrom<&Structure<'_>> for UserInteractedEvent { + type Error = zvariant::Error; + + fn try_from(value: &Structure<'_>) -> Result { + let (tag, value) = parse_tag_value_struct(value)?; + + match tag { + USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED => { + Ok(UserInteractedEvent::HybridDiscoveryRequested) + } + USER_INTERACTED_EVENT_NFC_DISCOVERY_REQUESTED => { + Ok(UserInteractedEvent::NfcDiscoveryRequested) + } + USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED => { + Ok(UserInteractedEvent::UsbDiscoveryRequested) + } + USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED => { + let s: Str = value.downcast_ref()?; + if s.is_empty() { + return Err(zvariant::Error::invalid_length( + s.len(), + &"a non-empty string", + )); + } + Ok(UserInteractedEvent::ClientPinEntered( + s.as_str().to_string(), + )) + } + USER_INTERACTED_EVENT_CREDENTIAL_SELECTED => { + let s: Str = value.downcast_ref()?; + if s.is_empty() { + return Err(zvariant::Error::invalid_length( + s.len(), + &"a non-empty string", + )); + } + Ok(UserInteractedEvent::CredentialSelected( + s.as_str().to_string(), + )) + } + USER_INTERACTED_EVENT_REQUEST_CANCELLED => Ok(UserInteractedEvent::RequestCancelled), + _ => Err(zvariant::Error::Message(format!( + "Unknown {} tag : {tag}", + stringify!(UserInteractedEvent) + ))), + } + } +} + +impl Serialize for UserInteractedEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let structure: Structure = self.into(); + structure.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for UserInteractedEvent { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let d = Structure::deserializer_for_signature(TAG_VALUE_SIGNATURE).map_err(|err| { + D::Error::custom(format!( + "could not create deserializer for tag-value struct: {err}" + )) + })?; + let structure = d.deserialize(deserializer)?; + (&structure).try_into().map_err(|err| { + D::Error::custom(format!( + "could not deserialize structure into {}: {err}", + stringify!(UserInteractedEvent) + )) + }) + } +} + #[derive(Clone, Debug, Serialize, Deserialize, Type)] pub struct ViewRequest { pub operation: Operation, diff --git a/credentialsd-ui/src/client.rs b/credentialsd-ui/src/client.rs index ed05c430..56726838 100644 --- a/credentialsd-ui/src/client.rs +++ b/credentialsd-ui/src/client.rs @@ -5,7 +5,7 @@ use async_std::{ }; use credentialsd_common::{ client::FlowController, - model::{BackendRequest, RequestId}, + model::{RequestId, UserInteractedEvent}, server::BackgroundEvent, }; use futures_lite::StreamExt; @@ -129,34 +129,35 @@ impl FlowController for DbusCredentialClient { #[derive(Debug)] pub struct FlowControlClient { - pub tx: Sender, + pub tx: Sender, pub rx: AsyncMutex>>, } impl FlowControlClient { pub async fn discover_hybrid_authenticators(&self) -> Result<(), ()> { - self.send(BackendRequest::StartHybridDiscovery).await + self.send(UserInteractedEvent::HybridDiscoveryRequested) + .await } pub async fn discover_nfc_authenticators(&mut self) -> Result<(), ()> { - self.send(BackendRequest::StartNfcDiscovery).await + self.send(UserInteractedEvent::NfcDiscoveryRequested).await } pub async fn discover_usb_authenticators(&mut self) -> Result<(), ()> { - self.send(BackendRequest::StartUsbDiscovery).await + self.send(UserInteractedEvent::UsbDiscoveryRequested).await } pub async fn enter_client_pin(&mut self, pin: String) -> Result<(), ()> { - self.send(BackendRequest::EnterClientPin(pin)).await + self.send(UserInteractedEvent::ClientPinEntered(pin)).await } pub async fn select_credential(&self, credential_id: String) -> Result<(), ()> { - self.send(BackendRequest::SelectCredential(credential_id)) + self.send(UserInteractedEvent::CredentialSelected(credential_id)) .await } pub async fn cancel_request(&self) -> Result<(), ()> { - self.send(BackendRequest::CancelRequest).await + self.send(UserInteractedEvent::RequestCancelled).await } /// Returns a channel for background events. @@ -167,7 +168,7 @@ impl FlowControlClient { }) } - async fn send(&self, request: BackendRequest) -> Result<(), ()> { + async fn send(&self, request: UserInteractedEvent) -> Result<(), ()> { match self.tx.send(request).await { Ok(_) => Ok(()), Err(_) => Err(()), diff --git a/credentialsd-ui/src/dbus.rs b/credentialsd-ui/src/dbus.rs index 37b278b6..5c2045ab 100644 --- a/credentialsd-ui/src/dbus.rs +++ b/credentialsd-ui/src/dbus.rs @@ -18,7 +18,8 @@ use zbus::{ use credentialsd_common::{ client::FlowController, model::{ - BackendRequest, Device, Operation, PortalBackendOptions, RequestId, RequestingApplication, + Device, Operation, PortalBackendOptions, RequestId, RequestingApplication, + UserInteractedEvent, }, server::{BackgroundEvent, ViewRequest, WindowHandle}, }; @@ -89,16 +90,20 @@ impl UiControlService { while let Ok(msg) = fc_rx.recv().await { // UI doesn't get an error if these fail... let result = match &msg { - BackendRequest::StartHybridDiscovery => client.get_hybrid_credential().await, - BackendRequest::StartNfcDiscovery => client.get_nfc_credential().await, - BackendRequest::StartUsbDiscovery => client.get_usb_credential().await, - BackendRequest::EnterClientPin(pin) => { + UserInteractedEvent::HybridDiscoveryRequested => { + client.get_hybrid_credential().await + } + UserInteractedEvent::NfcDiscoveryRequested => client.get_nfc_credential().await, + UserInteractedEvent::UsbDiscoveryRequested => client.get_usb_credential().await, + UserInteractedEvent::ClientPinEntered(pin) => { client.enter_client_pin(pin.to_string()).await } - BackendRequest::SelectCredential(cred_id) => { + UserInteractedEvent::CredentialSelected(cred_id) => { client.select_credential(cred_id.to_string()).await } - BackendRequest::CancelRequest => client.cancel_request(request.id).await, + UserInteractedEvent::RequestCancelled => { + client.cancel_request(request.id).await + } }; if let Err(err) = result { tracing::error!("Failed to send {msg:?} to frontend: {err:?}"); @@ -292,6 +297,6 @@ impl CeremonyObject { #[zbus(signal)] async fn user_interacted( emitter: SignalEmitter<'_>, - event: &BackendRequest, + event: &UserInteractedEvent, ) -> zbus::Result<()>; } diff --git a/credentialsd/src/dbus/flow_control.rs b/credentialsd/src/dbus/flow_control.rs index 74341a07..f71e7c90 100644 --- a/credentialsd/src/dbus/flow_control.rs +++ b/credentialsd/src/dbus/flow_control.rs @@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt::Debug, sync::Arc}; use async_trait::async_trait; use credentialsd_common::model::{ - BackendRequest, Device, Error as CredentialServiceError, Operation, PortalBackendOptions, - RequestId, RequestingApplication, WebAuthnError, + Device, Error as CredentialServiceError, Operation, PortalBackendOptions, RequestId, + RequestingApplication, UserInteractedEvent, WebAuthnError, }; use credentialsd_common::server::{BackgroundEvent, ViewRequest, WindowHandle}; use futures_lite::{Stream, StreamExt}; @@ -164,7 +164,7 @@ async fn handle { + UserInteractedEvent::HybridDiscoveryRequested => { let stream = svc .lock() .await @@ -174,7 +174,7 @@ async fn handle { + UserInteractedEvent::NfcDiscoveryRequested => { let stream = svc .lock() .await @@ -184,7 +184,7 @@ async fn handle { + UserInteractedEvent::UsbDiscoveryRequested => { let client_pin_tx = client_pin_tx.clone(); let cred_selector_tx = cred_selector_tx.clone(); let stream = @@ -207,7 +207,7 @@ async fn handle { + UserInteractedEvent::ClientPinEntered(pin) => { let tx = { client_pin_tx.lock().unwrap().take() }; if let Some(tx) = tx { if tx.send(pin).await.is_err() { @@ -219,7 +219,7 @@ async fn handle { + UserInteractedEvent::CredentialSelected(id) => { let tx = { cred_selector_tx.lock().unwrap().take() }; if let Some(tx) = tx { if tx.send(id).await.is_err() { @@ -231,7 +231,7 @@ async fn handle { + UserInteractedEvent::RequestCancelled => { tracing::debug!(%request_id, "Cancelling request"); svc.lock().await.cancel_request(request_id).await; } diff --git a/credentialsd/src/dbus/ui_control.rs b/credentialsd/src/dbus/ui_control.rs index c55dc1db..2d9cd7db 100644 --- a/credentialsd/src/dbus/ui_control.rs +++ b/credentialsd/src/dbus/ui_control.rs @@ -14,7 +14,7 @@ use zbus::{ }; use credentialsd_common::{ - model::{BackendRequest, Device, Operation, PortalBackendOptions, RequestId}, + model::{Device, Operation, PortalBackendOptions, RequestId, UserInteractedEvent}, server::{BackgroundEvent, ViewRequest, WindowHandle}, }; @@ -76,11 +76,11 @@ trait UiControlService2 { #[derive(Clone, Debug)] pub struct Ceremony { proxy: Arc>, - ui_events_rx: Arc>>, + ui_events_rx: Arc>>, } impl Ceremony { - pub async fn receive_ui_event(&self) -> Option { + pub async fn receive_ui_event(&self) -> Option { self.ui_events_rx.lock().await.recv().await } @@ -109,7 +109,7 @@ trait CeremonyObject { async fn cancel(&self) -> fdo::Result<()>; #[zbus(signal)] - async fn user_interacted(&self, update: BackendRequest) -> zbus::Result<()>; + async fn user_interacted(&self, update: UserInteractedEvent) -> zbus::Result<()>; } #[derive(Debug)] @@ -198,7 +198,7 @@ impl UiController for UiControlServiceClient { async fn forward_ui_events( mut ui_event_stream: UserInteractedStream, - tx: mpsc::Sender, + tx: mpsc::Sender, ) -> Result<(), Box> { tracing::debug!("Listening for events from UI"); while let Some(signal) = ui_event_stream.next().await {