Skip to content

Commit d7b8a73

Browse files
committed
wip: query all devices at once
1 parent 841d873 commit d7b8a73

11 files changed

Lines changed: 228 additions & 69 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

credentialsd-common/src/client.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ pub trait FlowController {
1313
&self,
1414
) -> impl Future<Output = Result<Vec<Device>, ()>> + Send;
1515

16-
fn get_hybrid_credential(&mut self) -> impl Future<Output = Result<(), ()>> + Send;
17-
fn get_usb_credential(&mut self) -> impl Future<Output = Result<(), ()>> + Send;
18-
fn get_nfc_credential(&mut self) -> impl Future<Output = Result<(), ()>> + Send;
16+
fn start_discovery(&mut self) -> impl Future<Output = Result<(), ()>> + Send;
1917
fn subscribe(
2018
&mut self,
2119
) -> impl Future<

credentialsd-common/src/model.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ pub enum NfcState {
270270
}
271271

272272
pub enum UserInteractedEvent {
273+
/// Start discovery
274+
DiscoveryRequested,
275+
/*
273276
/// Start Hybrid discovery
274277
HybridDiscoveryRequested,
275278
@@ -278,7 +281,7 @@ pub enum UserInteractedEvent {
278281
279282
/// Start USB discovery
280283
UsbDiscoveryRequested,
281-
284+
*/
282285
/// Send client PIN. Length of the PIN MUST not be greater than 63 bytes.
283286
/// File descriptor must be memory-mapped to be read.
284287
ClientPinEntered(OwnedFd),
@@ -292,17 +295,16 @@ pub enum UserInteractedEvent {
292295
impl std::fmt::Debug for UserInteractedEvent {
293296
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294297
match self {
295-
Self::HybridDiscoveryRequested => write!(f, "StartHybridDiscovery"),
296-
Self::NfcDiscoveryRequested => write!(f, "StartNfcDiscovery"),
297-
Self::UsbDiscoveryRequested => write!(f, "StartUsbDiscovery"),
298+
Self::DiscoveryRequested => write!(f, stringify!(DiscoveryRequested)),
298299
Self::ClientPinEntered(_) => f
299-
.debug_tuple("EnterClientPin")
300+
.debug_tuple(stringify!(ClientPinEntered))
300301
.field(&"******".to_string())
301302
.finish(),
302-
Self::CredentialSelected(arg0) => {
303-
f.debug_tuple("SelectCredential").field(arg0).finish()
304-
}
305-
Self::RequestCancelled => write!(f, "CancelRequest"),
303+
Self::CredentialSelected(arg0) => f
304+
.debug_tuple(stringify!(CredentialSelected))
305+
.field(arg0)
306+
.finish(),
307+
Self::RequestCancelled => write!(f, stringify!(RequestCancelled)),
306308
}
307309
}
308310
}

credentialsd-common/src/server.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ const BACKGROUND_EVENT_ERROR_CREDENTIAL_EXCLUDED: u32 = 0x80000006;
4949
const BACKGROUND_EVENT_ERROR_PIN_ATTEMPTS_EXHAUSTED: u32 = 0x80000007;
5050
const BACKGROUND_EVENT_ERROR_PIN_NOT_SET: u32 = 0x80000008;
5151

52+
/*
5253
const USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED: u32 = 0x01;
5354
const USER_INTERACTED_EVENT_NFC_DISCOVERY_REQUESTED: u32 = 0x02;
5455
const USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED: u32 = 0x03;
56+
*/
57+
const USER_INTERACTED_EVENT_DISCOVERY_REQUESTED: u32 = 0x01;
5558
const USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED: u32 = 0x04;
5659
const USER_INTERACTED_EVENT_CREDENTIAL_SELECTED: u32 = 0x05;
5760
const USER_INTERACTED_EVENT_REQUEST_CANCELLED: u32 = 0x06;
@@ -426,6 +429,10 @@ impl Type for UserInteractedEvent {
426429
impl From<&UserInteractedEvent> for Structure<'_> {
427430
fn from(value: &UserInteractedEvent) -> Self {
428431
match value {
432+
UserInteractedEvent::DiscoveryRequested => {
433+
tag_value_to_struct(USER_INTERACTED_EVENT_DISCOVERY_REQUESTED, None)
434+
}
435+
/*
429436
UserInteractedEvent::HybridDiscoveryRequested => {
430437
tag_value_to_struct(USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED, None)
431438
}
@@ -435,6 +442,7 @@ impl From<&UserInteractedEvent> for Structure<'_> {
435442
UserInteractedEvent::UsbDiscoveryRequested => {
436443
tag_value_to_struct(USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED, None)
437444
}
445+
*/
438446
UserInteractedEvent::ClientPinEntered(pin_fd) => tag_value_to_struct(
439447
USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED,
440448
Some(Value::Fd(pin_fd.into())),
@@ -457,15 +465,17 @@ impl TryFrom<&Structure<'_>> for UserInteractedEvent {
457465
let (tag, value) = parse_tag_value_struct(value)?;
458466

459467
match tag {
460-
USER_INTERACTED_EVENT_HYBRID_DISCOVERY_REQUESTED => {
461-
Ok(UserInteractedEvent::HybridDiscoveryRequested)
468+
USER_INTERACTED_EVENT_DISCOVERY_REQUESTED => {
469+
Ok(UserInteractedEvent::DiscoveryRequested)
462470
}
471+
/*
463472
USER_INTERACTED_EVENT_NFC_DISCOVERY_REQUESTED => {
464473
Ok(UserInteractedEvent::NfcDiscoveryRequested)
465474
}
466475
USER_INTERACTED_EVENT_USB_DISCOVERY_REQUESTED => {
467476
Ok(UserInteractedEvent::UsbDiscoveryRequested)
468477
}
478+
*/
469479
USER_INTERACTED_EVENT_CLIENT_PIN_ENTERED => {
470480
let fd = value.downcast_ref::<Fd>()?;
471481
let owned_fd = fd.try_to_owned()?;

credentialsd-ui/src/client.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ pub struct FlowControlClient {
2424
}
2525

2626
impl FlowControlClient {
27+
pub async fn discover_authenticators(&self) -> Result<(), ()> {
28+
self.send(UserInteractedEvent::DiscoveryRequested).await
29+
}
30+
/*
2731
pub async fn discover_hybrid_authenticators(&self) -> Result<(), ()> {
2832
self.send(UserInteractedEvent::HybridDiscoveryRequested)
2933
.await
@@ -36,6 +40,7 @@ impl FlowControlClient {
3640
pub async fn discover_usb_authenticators(&mut self) -> Result<(), ()> {
3741
self.send(UserInteractedEvent::UsbDiscoveryRequested).await
3842
}
43+
*/
3944

4045
pub async fn enter_client_pin(&mut self, pin: String) -> Result<(), ()> {
4146
let fd = match write_secret(pin) {

credentialsd-ui/src/gui/view_model/gtk/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,11 @@ impl ViewModel {
261261
button.connect_clicked(move |button| {
262262
let id = button.widget_name().to_string();
263263
let tx = tx.clone();
264+
/*
264265
glib::spawn_future_local(async move {
265266
tx.send(ViewEvent::DeviceSelected(id)).await.unwrap();
266267
});
268+
*/
267269
});
268270
button.into()
269271
});

credentialsd-ui/src/gui/view_model/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ impl ViewModel {
127127
.unwrap();
128128
}
129129

130+
pub(crate) async fn start_discovery(&self) {
131+
let cred_service = self.flow_controller.lock().await;
132+
(*cred_service).discover_authenticators().await.unwrap();
133+
}
134+
135+
/*
130136
pub(crate) async fn select_device(&mut self, id: &str) {
131137
let device = self.devices.iter().find(|d| d.id == id).unwrap();
132138
tracing::debug!("Device selected: {:?}", device);
@@ -176,6 +182,7 @@ impl ViewModel {
176182
.await
177183
.unwrap();
178184
}
185+
*/
179186

180187
pub(crate) async fn start_event_loop(&mut self) {
181188
let view_events = self.rx_event.clone().map(Event::View);
@@ -189,11 +196,14 @@ impl ViewModel {
189196
Event::View(ViewEvent::Initiated) => {
190197
self.update_title().await;
191198
self.update_devices(self.devices.clone()).await;
199+
self.start_discovery().await;
192200
}
201+
/*
193202
Event::View(ViewEvent::DeviceSelected(id)) => {
194203
self.select_device(&id).await;
195204
println!("Selected device {id}");
196205
}
206+
*/
197207
Event::View(ViewEvent::PinEntered(pin)) => {
198208
let mut cred_service = self.flow_controller.lock().await;
199209
if cred_service.enter_client_pin(pin).await.is_err() {
@@ -366,7 +376,7 @@ impl ViewModel {
366376
#[derive(Serialize, Deserialize)]
367377
pub enum ViewEvent {
368378
Initiated,
369-
DeviceSelected(String),
379+
// DeviceSelected(String),
370380
CredentialSelected(String),
371381
PinEntered(String),
372382
UserCancelled,

credentialsd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ async-stream = "0.3.6"
1010
async-trait = "0.1.89"
1111
base64 = "0.22.1"
1212
credentialsd-common = { path = "../credentialsd-common" }
13+
futures = "0.3.32"
1314
futures-lite.workspace = true
1415
libc.workspace = true
1516
libwebauthn = { version = "0.3.0", features = ["libnfc","pcsc"] }

credentialsd/src/credential_service/mod.rs

Lines changed: 109 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ use std::{
1010
};
1111

1212
use async_trait::async_trait;
13-
use futures_lite::{FutureExt, Stream, StreamExt};
13+
use futures_lite::{stream, FutureExt, Stream, StreamExt};
1414
use libwebauthn::{
1515
self,
1616
ops::webauthn::{GetAssertionResponse, MakeCredentialResponse},
1717
};
1818
use nfc::{NfcEvent, NfcHandler, NfcState, NfcStateInternal};
1919
use tokio::sync::oneshot;
2020

21-
use credentialsd_common::model::{Device, Error as CredentialServiceError, RequestId, Transport};
21+
use credentialsd_common::{
22+
model::{Device, Error as CredentialServiceError, RequestId, Transport},
23+
server::BackgroundEvent,
24+
};
2225

2326
use crate::{
2427
credential_service::{hybrid::HybridEvent, usb::UsbEvent},
@@ -59,11 +62,9 @@ pub trait ManageDevice {
5962
) -> Result<RequestId, CredentialServiceError>;
6063
async fn cancel_request(&self, request_id: RequestId);
6164
async fn get_available_public_key_devices(&self) -> Result<Vec<Device>, ()>;
62-
async fn get_hybrid_credential(
65+
async fn start_discovery(
6366
&self,
64-
) -> Pin<Box<dyn Stream<Item = HybridState> + Send + 'static>>;
65-
async fn get_nfc_credential(&self) -> Pin<Box<dyn Stream<Item = NfcState> + Send + 'static>>;
66-
async fn get_usb_credential(&self) -> Pin<Box<dyn Stream<Item = UsbState> + Send + 'static>>;
67+
) -> Pin<Box<dyn Stream<Item = DeviceStateUpdate> + Send + 'static>>;
6768
}
6869

6970
#[derive(Debug)]
@@ -90,6 +91,54 @@ impl<H: HybridHandler + Debug, N: NfcHandler + Debug, U: UsbHandler + Debug>
9091
}
9192
}
9293

94+
impl<H: HybridHandler + Send, N: NfcHandler + Send, U: UsbHandler + Send>
95+
CredentialService<H, N, U>
96+
{
97+
async fn get_hybrid_credential(
98+
&self,
99+
) -> Pin<Box<dyn Stream<Item = HybridState> + Send + 'static>> {
100+
let guard = self.ctx.lock().unwrap();
101+
if let Some(RequestContext { ref request, .. }) = *guard {
102+
let stream = self.hybrid_handler.lock().unwrap().start(request);
103+
let ctx = self.ctx.clone();
104+
Box::pin(HybridStateStream { inner: stream, ctx })
105+
} else {
106+
tracing::error!(
107+
"Attempted to start hybrid credential flow, but no request context was found."
108+
);
109+
todo!("Handle error when context is not set up.")
110+
}
111+
}
112+
113+
async fn get_usb_credential(&self) -> Pin<Box<dyn Stream<Item = UsbState> + Send + 'static>> {
114+
let guard = self.ctx.lock().unwrap();
115+
if let Some(RequestContext { ref request, .. }) = *guard {
116+
let stream = self.usb_handler.lock().unwrap().start(request);
117+
let ctx = self.ctx.clone();
118+
Box::pin(UsbStateStream { inner: stream, ctx })
119+
} else {
120+
tracing::error!(
121+
"Attempted to start usb credential flow, but no request context was found."
122+
);
123+
todo!("Handle error when context is not set up.")
124+
}
125+
}
126+
127+
async fn get_nfc_credential(&self) -> Pin<Box<dyn Stream<Item = NfcState> + Send + 'static>> {
128+
let guard = self.ctx.lock().unwrap();
129+
if let Some(RequestContext { ref request, .. }) = *guard {
130+
let stream = self.nfc_handler.lock().unwrap().start(request);
131+
let ctx = self.ctx.clone();
132+
Box::pin(NfcStateStream { inner: stream, ctx })
133+
} else {
134+
tracing::error!(
135+
"Attempted to start nfc credential flow, but no request context was found."
136+
);
137+
todo!("Handle error when context is not set up.")
138+
}
139+
}
140+
}
141+
93142
#[async_trait]
94143
impl<H: HybridHandler + Send, N: NfcHandler + Send, U: UsbHandler + Send> ManageDevice
95144
for CredentialService<H, N, U>
@@ -158,48 +207,27 @@ impl<H: HybridHandler + Send, N: NfcHandler + Send, U: UsbHandler + Send> Manage
158207
Ok(devices)
159208
}
160209

161-
async fn get_hybrid_credential(
210+
async fn start_discovery(
162211
&self,
163-
) -> Pin<Box<dyn Stream<Item = HybridState> + Send + 'static>> {
164-
let guard = self.ctx.lock().unwrap();
165-
if let Some(RequestContext { ref request, .. }) = *guard {
166-
let stream = self.hybrid_handler.lock().unwrap().start(request);
167-
let ctx = self.ctx.clone();
168-
Box::pin(HybridStateStream { inner: stream, ctx })
169-
} else {
170-
tracing::error!(
171-
"Attempted to start hybrid credential flow, but no request context was found."
172-
);
173-
todo!("Handle error when context is not set up.")
174-
}
175-
}
176-
177-
async fn get_usb_credential(&self) -> Pin<Box<dyn Stream<Item = UsbState> + Send + 'static>> {
178-
let guard = self.ctx.lock().unwrap();
179-
if let Some(RequestContext { ref request, .. }) = *guard {
180-
let stream = self.usb_handler.lock().unwrap().start(request);
181-
let ctx = self.ctx.clone();
182-
Box::pin(UsbStateStream { inner: stream, ctx })
183-
} else {
184-
tracing::error!(
185-
"Attempted to start usb credential flow, but no request context was found."
186-
);
187-
todo!("Handle error when context is not set up.")
188-
}
189-
}
190-
191-
async fn get_nfc_credential(&self) -> Pin<Box<dyn Stream<Item = NfcState> + Send + 'static>> {
192-
let guard = self.ctx.lock().unwrap();
193-
if let Some(RequestContext { ref request, .. }) = *guard {
194-
let stream = self.nfc_handler.lock().unwrap().start(request);
195-
let ctx = self.ctx.clone();
196-
Box::pin(NfcStateStream { inner: stream, ctx })
197-
} else {
198-
tracing::error!(
199-
"Attempted to start nfc credential flow, but no request context was found."
200-
);
201-
todo!("Handle error when context is not set up.")
202-
}
212+
) -> Pin<Box<dyn Stream<Item = DeviceStateUpdate> + Send + 'static>> {
213+
let usb = self
214+
.get_usb_credential()
215+
.await
216+
.map(DeviceStateUpdate::from)
217+
.boxed();
218+
/*
219+
let nfc = self
220+
.get_nfc_credential()
221+
.await
222+
.map(DeviceStateUpdate::from)
223+
.boxed();
224+
*/
225+
let hybrid = self
226+
.get_hybrid_credential()
227+
.await
228+
.map(DeviceStateUpdate::from)
229+
.boxed();
230+
futures::stream::select_all([usb, /* nfc, */ hybrid]).boxed()
203231
}
204232
}
205233

@@ -309,6 +337,40 @@ where
309337
}
310338
}
311339

340+
pub enum DeviceStateUpdate {
341+
Hybrid(HybridState),
342+
Nfc(NfcState),
343+
Usb(UsbState),
344+
}
345+
346+
impl From<DeviceStateUpdate> for BackgroundEvent {
347+
fn from(value: DeviceStateUpdate) -> Self {
348+
match value {
349+
DeviceStateUpdate::Hybrid(state) => (&state).into(),
350+
DeviceStateUpdate::Nfc(state) => (&state).into(),
351+
DeviceStateUpdate::Usb(state) => (&state).into(),
352+
}
353+
}
354+
}
355+
356+
impl From<HybridState> for DeviceStateUpdate {
357+
fn from(value: HybridState) -> Self {
358+
Self::Hybrid(value)
359+
}
360+
}
361+
362+
impl From<NfcState> for DeviceStateUpdate {
363+
fn from(value: NfcState) -> Self {
364+
Self::Nfc(value)
365+
}
366+
}
367+
368+
impl From<UsbState> for DeviceStateUpdate {
369+
fn from(value: UsbState) -> Self {
370+
Self::Usb(value)
371+
}
372+
}
373+
312374
fn complete_request(ctx: &Mutex<Option<RequestContext>>, response: CredentialResponse) {
313375
if let Some(ctx) = ctx.lock().unwrap().take() {
314376
ctx.send_response(Ok(response));

0 commit comments

Comments
 (0)