@@ -38,20 +38,33 @@ impl InProcessUsbHandler {
3838 let ( signal_tx, mut signal_rx) = mpsc:: channel ( 256 ) ;
3939 let ( cred_tx, mut cred_rx) = mpsc:: channel ( 1 ) ;
4040 debug ! ( "polling for USB status" ) ;
41+ let mut failures = 0 ;
4142 loop {
4243 tracing:: debug!( "current usb state: {:?}" , state) ;
4344 let prev_usb_state = state;
4445 let next_usb_state = match prev_usb_state {
4546 UsbStateInternal :: Idle | UsbStateInternal :: Waiting => {
46- let mut hid_devices =
47- libwebauthn:: transport:: hid:: list_devices ( ) . await . unwrap ( ) ;
48- if hid_devices. is_empty ( ) {
49- let state = UsbStateInternal :: Waiting ;
50- Ok ( state)
51- } else if hid_devices. len ( ) == 1 {
52- Ok ( UsbStateInternal :: Connected ( hid_devices. swap_remove ( 0 ) ) )
53- } else {
54- Ok ( UsbStateInternal :: SelectingDevice ( hid_devices) )
47+ match libwebauthn:: transport:: hid:: list_devices ( ) . await {
48+ Ok ( mut hid_devices) => {
49+ if hid_devices. is_empty ( ) {
50+ let state = UsbStateInternal :: Waiting ;
51+ Ok ( state)
52+ } else if hid_devices. len ( ) == 1 {
53+ Ok ( UsbStateInternal :: Connected ( hid_devices. swap_remove ( 0 ) ) )
54+ } else {
55+ Ok ( UsbStateInternal :: SelectingDevice ( hid_devices) )
56+ }
57+ }
58+ Err ( err) => {
59+ failures += 1 ;
60+ if failures == 5 {
61+ Err ( format ! ( "Failed to list USB authenticators: {:?}. Cancelling USB state updates." , err) )
62+ } else {
63+ tracing:: warn!( "Failed to list USB authenticators: {:?}. Throttling USB state updates" , err) ;
64+ tokio:: time:: sleep ( Duration :: from_secs ( 1 ) ) . await ;
65+ Ok ( prev_usb_state)
66+ }
67+ }
5568 }
5669 }
5770 UsbStateInternal :: SelectingDevice ( hid_devices) => {
@@ -265,54 +278,79 @@ async fn handle_events(
265278 mut device : HidDevice ,
266279 signal_tx : & Sender < Result < UsbUvMessage , String > > ,
267280) {
268- let ( mut channel, state_rx) = device. channel ( ) . await . unwrap ( ) ;
269- let signal_tx2 = signal_tx. clone ( ) . downgrade ( ) ;
270- tokio:: spawn ( async move {
271- handle_usb_updates ( & signal_tx2, state_rx) . await ;
272- debug ! ( "Reached end of USB update task" ) ;
273- } ) ;
274- match cred_request {
275- CredentialRequest :: CreatePublicKeyCredentialRequest ( make_cred_request) => loop {
276- match channel. webauthn_make_credential ( make_cred_request) . await {
277- Ok ( response) => {
278- notify_ceremony_completed (
279- signal_tx,
280- AuthenticatorResponse :: CredentialCreated ( response) ,
281- )
282- . await ;
283- break ;
284- }
285- Err ( WebAuthnError :: Ctap ( ctap_error) ) if ctap_error. is_retryable_user_error ( ) => {
286- warn ! ( "Retrying WebAuthn make credential operation" ) ;
287- continue ;
288- }
289- Err ( err) => {
290- notify_ceremony_failed ( signal_tx, err. to_string ( ) ) . await ;
291- break ;
292- }
293- } ;
294- } ,
295- CredentialRequest :: GetPublicKeyCredentialRequest ( get_cred_request) => loop {
296- match channel. webauthn_get_assertion ( get_cred_request) . await {
297- Ok ( response) => {
298- notify_ceremony_completed (
299- signal_tx,
300- AuthenticatorResponse :: CredentialsAsserted ( response) ,
301- )
302- . await ;
303- break ;
304- }
305- Err ( WebAuthnError :: Ctap ( ctap_error) ) if ctap_error. is_retryable_user_error ( ) => {
306- warn ! ( "Retrying WebAuthn get credential operation" ) ;
307- continue ;
308- }
309- Err ( err) => {
310- notify_ceremony_failed ( signal_tx, err. to_string ( ) ) . await ;
311- break ;
312- }
281+ let device_debug = device. to_string ( ) ;
282+ match device. channel ( ) . await {
283+ Err ( err) => {
284+ tracing:: error!( "Failed to open channel to USB authenticator, cannot receive user verification events: {:?}" , err) ;
285+ }
286+ Ok ( ( mut channel, state_rx) ) => {
287+ let signal_tx2 = signal_tx. clone ( ) . downgrade ( ) ;
288+ tokio:: spawn ( async move {
289+ handle_usb_updates ( & signal_tx2, state_rx) . await ;
290+ debug ! ( "Reached end of USB update task" ) ;
291+ } ) ;
292+ match cred_request {
293+ CredentialRequest :: CreatePublicKeyCredentialRequest ( make_cred_request) => loop {
294+ tracing:: debug!(
295+ "Polling for credential from USB authenticator {}" ,
296+ & device_debug
297+ ) ;
298+ match channel. webauthn_make_credential ( make_cred_request) . await {
299+ Ok ( response) => {
300+ tracing:: debug!( "Received attestation from USB authenticator" ) ;
301+ notify_ceremony_completed (
302+ signal_tx,
303+ AuthenticatorResponse :: CredentialCreated ( response) ,
304+ )
305+ . await ;
306+ break ;
307+ }
308+ Err ( WebAuthnError :: Ctap ( ctap_error) )
309+ if ctap_error. is_retryable_user_error ( ) =>
310+ {
311+ warn ! ( "Retrying WebAuthn make credential operation" ) ;
312+ continue ;
313+ }
314+ Err ( err) => {
315+ tracing:: warn!(
316+ "Failed to create credential with USB authenticator: {:?}" ,
317+ err
318+ ) ;
319+ notify_ceremony_failed ( signal_tx, err. to_string ( ) ) . await ;
320+ break ;
321+ }
322+ } ;
323+ } ,
324+ CredentialRequest :: GetPublicKeyCredentialRequest ( get_cred_request) => loop {
325+ match channel. webauthn_get_assertion ( get_cred_request) . await {
326+ Ok ( response) => {
327+ tracing:: debug!( "Received assertion from USB authenticator" ) ;
328+ notify_ceremony_completed (
329+ signal_tx,
330+ AuthenticatorResponse :: CredentialsAsserted ( response) ,
331+ )
332+ . await ;
333+ break ;
334+ }
335+ Err ( WebAuthnError :: Ctap ( ctap_error) )
336+ if ctap_error. is_retryable_user_error ( ) =>
337+ {
338+ tracing:: warn!( "Retrying WebAuthn get credential operation" ) ;
339+ continue ;
340+ }
341+ Err ( err) => {
342+ tracing:: warn!(
343+ "Failed to get credential from USB authenticator: {:?}" ,
344+ err
345+ ) ;
346+ notify_ceremony_failed ( signal_tx, err. to_string ( ) ) . await ;
347+ break ;
348+ }
349+ } ;
350+ } ,
313351 } ;
314- } ,
315- } ;
352+ }
353+ }
316354}
317355
318356async fn notify_ceremony_completed (
@@ -326,7 +364,9 @@ async fn notify_ceremony_completed(
326364}
327365
328366async fn notify_ceremony_failed ( signal_tx : & Sender < Result < UsbUvMessage , String > > , err : String ) {
329- signal_tx. send ( Err ( err) ) . await . unwrap ( ) ;
367+ if let Err ( tx_err) = signal_tx. send ( Err ( err) ) . await {
368+ tracing:: error!( "Failed to notify that ceremony failed: {:?}" , tx_err) ;
369+ }
330370}
331371
332372impl UsbHandler for InProcessUsbHandler {
@@ -511,25 +551,31 @@ async fn handle_usb_updates(
511551 } ;
512552 match msg {
513553 UxUpdate :: UvRetry { attempts_left } => {
514- signal_tx
554+ if let Err ( err ) = signal_tx
515555 . send ( Ok ( UsbUvMessage :: NeedsUserVerification { attempts_left } ) )
516556 . await
517- . unwrap ( ) ;
557+ {
558+ tracing:: error!( "Authenticator requested user verficiation, but we cannot relay the message to credential service: {:?}" , err) ;
559+ }
518560 }
519561 UxUpdate :: PinRequired ( pin_update) => {
520562 if pin_update. attempts_left . is_some_and ( |num| num <= 1 ) {
521563 // TODO: cancel authenticator operation
522- signal_tx. send ( Err ( "No more PIN attempts allowed. Select a different authenticator or try again later." . to_string ( ) ) ) . await . unwrap ( ) ;
564+ if let Err ( err) = signal_tx. send ( Err ( "No more PIN attempts allowed. Select a different authenticator or try again later." . to_string ( ) ) ) . await {
565+ tracing:: error!( "Authenticator cannot process anymore PIN requests, but we cannot relay the message to credential service: {:?}" , err) ;
566+ }
523567 continue ;
524568 }
525569 let ( pin_tx, mut pin_rx) = mpsc:: channel ( 1 ) ;
526- signal_tx
570+ if let Err ( err ) = signal_tx
527571 . send ( Ok ( UsbUvMessage :: NeedsPin {
528572 pin_tx,
529573 attempts_left : pin_update. attempts_left ,
530574 } ) )
531575 . await
532- . unwrap ( ) ;
576+ {
577+ tracing:: error!( "Authenticator requested a PIN from the user, but we cannot relay the message to the credential service: {:?}" , err) ;
578+ }
533579 match pin_rx. recv ( ) . await {
534580 Some ( pin) => match pin_update. send_pin ( & pin) {
535581 Ok ( ( ) ) => { }
@@ -539,10 +585,9 @@ async fn handle_usb_updates(
539585 }
540586 }
541587 UxUpdate :: PresenceRequired => {
542- signal_tx
543- . send ( Ok ( UsbUvMessage :: NeedsUserPresence ) )
544- . await
545- . unwrap ( ) ;
588+ if let Err ( err) = signal_tx. send ( Ok ( UsbUvMessage :: NeedsUserPresence ) ) . await {
589+ tracing:: error!( "Authenticator requested user presence, but we cannot relay the message to the credential service: {:?}" , err) ;
590+ }
546591 }
547592 }
548593 }
0 commit comments