Skip to content

Commit 44e1c23

Browse files
committed
Switch to interactive PinNotSet flow, using devel-branch of libwebauthn
1 parent 6243e5f commit 44e1c23

19 files changed

Lines changed: 449 additions & 467 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ pub trait FlowController {
2222
Output = Result<Pin<Box<dyn Stream<Item = BackgroundEvent> + Send + 'static>>, ()>,
2323
> + Send;
2424
fn enter_client_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
25-
fn set_usb_device_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
26-
fn set_nfc_device_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
25+
fn set_device_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
2726
fn select_credential(
2827
&self,
2928
credential_id: String,

credentialsd-common/src/model.rs

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ pub struct Device {
4040
pub enum Operation {
4141
Create,
4242
Get,
43-
SetDevicePin,
4443
}
4544

4645
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Type)]
@@ -121,33 +120,6 @@ pub struct RequestingParty {
121120
pub origin: String,
122121
}
123122

124-
#[derive(Debug, Clone, Serialize, Deserialize)]
125-
pub enum ViewUpdateFailure {
126-
GeneralFailure(String),
127-
/// Request required UV, but it was not set on the device yet
128-
PinNotSet(String),
129-
/// User tried to set PIN, but it was too short
130-
PinPolicyViolation(String),
131-
}
132-
133-
impl ViewUpdateFailure {
134-
pub fn into_string(self) -> String {
135-
match self {
136-
ViewUpdateFailure::GeneralFailure(msg)
137-
| ViewUpdateFailure::PinNotSet(msg)
138-
| ViewUpdateFailure::PinPolicyViolation(msg) => msg,
139-
}
140-
}
141-
}
142-
143-
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
144-
pub enum ViewUpdateSuccess {
145-
/// Success that requires the window to close
146-
CloseWindow,
147-
/// Success that requires the window to stay open
148-
KeepWindowOpen(String),
149-
}
150-
151123
#[derive(Debug, Clone, Serialize, Deserialize)]
152124
pub enum ViewUpdate {
153125
SetTitle((String, String)),
@@ -160,17 +132,48 @@ pub enum ViewUpdate {
160132
UsbNeedsPin { attempts_left: Option<u32> },
161133
UsbNeedsUserVerification { attempts_left: Option<u32> },
162134
UsbNeedsUserPresence,
135+
UsbPinNotSet { error: Option<PinNotSetError> },
163136

164137
NfcNeedsPin { attempts_left: Option<u32> },
165138
NfcNeedsUserVerification { attempts_left: Option<u32> },
139+
NfcPinNotSet { error: Option<PinNotSetError> },
166140

167141
HybridNeedsQrCode(String),
168142
HybridConnecting,
169143
HybridConnected,
170144

171-
Completed(ViewUpdateSuccess),
145+
Completed,
172146
Cancelled,
173-
Failed(ViewUpdateFailure),
147+
Failed(String),
148+
}
149+
150+
#[derive(Debug, Clone, Serialize, Deserialize)]
151+
pub enum PinNotSetError {
152+
/// PIN too short
153+
PinTooShort,
154+
/// PIN too long
155+
PinTooLong,
156+
/// PIN violates PinPolicy
157+
PinPolicyViolation,
158+
}
159+
160+
impl PinNotSetError {
161+
pub fn to_string(&self) -> String {
162+
match self {
163+
PinNotSetError::PinTooShort => String::from("Pin too short"),
164+
PinNotSetError::PinTooLong => String::from("Pin too long"),
165+
PinNotSetError::PinPolicyViolation => String::from("Pin policy violation"),
166+
}
167+
}
168+
169+
pub fn from_string(error: &str) -> Option<PinNotSetError> {
170+
match error {
171+
"Pin too short" => Some(PinNotSetError::PinTooShort),
172+
"Pin too long" => Some(PinNotSetError::PinTooLong),
173+
"Pin policy violation" => Some(PinNotSetError::PinPolicyViolation),
174+
_ => None,
175+
}
176+
}
174177
}
175178

176179
#[derive(Clone, Debug, Default)]
@@ -220,6 +223,11 @@ pub enum UsbState {
220223
attempts_left: Option<u32>,
221224
},
222225

226+
/// The device needs the PIN to be entered.
227+
PinNotSet {
228+
error: Option<PinNotSetError>,
229+
},
230+
223231
/// The device needs on-device user verification.
224232
NeedsUserVerification {
225233
attempts_left: Option<u32>,
@@ -259,6 +267,9 @@ pub enum NfcState {
259267
/// The device needs the PIN to be entered.
260268
NeedsPin { attempts_left: Option<u32> },
261269

270+
/// The device needs the PIN to be entered.
271+
PinNotSet { error: Option<PinNotSetError> },
272+
262273
/// The device needs on-device user verification.
263274
NeedsUserVerification { attempts_left: Option<u32> },
264275

@@ -299,10 +310,6 @@ pub enum Error {
299310
/// Note that this is different than exhausting the PIN count that fully
300311
/// locks out the device.
301312
PinAttemptsExhausted,
302-
/// The RP requires user verification, but the device has no PIN/Biometrics set.
303-
PinNotSet,
304-
/// The device declined the entered PIN, as it violates the PIN policy (e.g. PIN too short)
305-
PinPolicyViolation,
306313
// TODO: We may want to hide the details on this variant from the public API.
307314
/// Something went wrong with the credential service itself, not the authenticator.
308315
Internal(String),
@@ -314,8 +321,6 @@ impl Display for Error {
314321
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315322
match self {
316323
Self::AuthenticatorError => f.write_str("AuthenticatorError"),
317-
Self::PinNotSet => f.write_str("PinNotSet"),
318-
Self::PinPolicyViolation => f.write_str("PinPolicyViolation"),
319324
Self::NoCredentials => f.write_str("NoCredentials"),
320325
Self::CredentialExcluded => f.write_str("CredentialExcluded"),
321326
Self::PinAttemptsExhausted => f.write_str("PinAttemptsExhausted"),

credentialsd-common/src/server.rs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use zvariant::{
1111
SerializeDict, Signature, Structure, StructureBuilder, Type, Value, signature::Fields,
1212
};
1313

14-
use crate::model::{BackgroundEvent, Device, Operation, RequestingApplication};
14+
use crate::model::{BackgroundEvent, Operation, PinNotSetError, RequestingApplication};
1515

1616
const TAG_VALUE_SIGNATURE: &Signature = &Signature::Structure(Fields::Static {
1717
fields: &[&Signature::U8, &Signature::Variant],
@@ -182,8 +182,6 @@ impl TryFrom<&Value<'_>> for crate::model::Error {
182182
let err_code: &str = value.downcast_ref()?;
183183
let err = match err_code {
184184
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
185-
"PinNotSet" => crate::model::Error::PinNotSet,
186-
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
187185
"NoCredentials" => crate::model::Error::NoCredentials,
188186
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
189187
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
@@ -347,6 +345,21 @@ impl From<&crate::model::UsbState> for Structure<'_> {
347345
let value = Value::<'_>::from(error.to_string());
348346
(0x0A, Some(value))
349347
}
348+
crate::model::UsbState::PinNotSet { error } => {
349+
let value = error.as_ref().map(|x| {
350+
Value::<'_>::from({
351+
let this = &x;
352+
match this {
353+
PinNotSetError::PinTooShort => String::from("Pin too short"),
354+
PinNotSetError::PinTooLong => String::from("Pin too long"),
355+
PinNotSetError::PinPolicyViolation => {
356+
String::from("Pin policy violation")
357+
}
358+
}
359+
})
360+
});
361+
(0x0B, value)
362+
}
350363
};
351364
tag_value_to_struct(tag, value)
352365
}
@@ -401,15 +414,20 @@ impl TryFrom<&Structure<'_>> for crate::model::UsbState {
401414
let err_code: &str = value.downcast_ref()?;
402415
let err = match err_code {
403416
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
404-
"PinNotSet" => crate::model::Error::PinNotSet,
405-
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
406417
"NoCredentials" => crate::model::Error::NoCredentials,
407418
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
408419
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
409420
s => crate::model::Error::Internal(String::from(s)),
410421
};
411422
Ok(Self::Failed(err))
412423
}
424+
0x0B => {
425+
let error = value
426+
.downcast_ref::<&str>()
427+
.ok()
428+
.and_then(PinNotSetError::from_string);
429+
Ok(Self::PinNotSet { error })
430+
}
413431
_ => Err(zvariant::Error::IncorrectType),
414432
}
415433
}
@@ -473,6 +491,21 @@ impl From<&crate::model::NfcState> for Structure<'_> {
473491
let value = Value::<'_>::from(error.to_string());
474492
(0x0A, Some(value))
475493
}
494+
crate::model::NfcState::PinNotSet { error } => {
495+
let value = error.as_ref().map(|x| {
496+
Value::<'_>::from({
497+
let this = &x;
498+
match this {
499+
PinNotSetError::PinTooShort => String::from("Pin too short"),
500+
PinNotSetError::PinTooLong => String::from("Pin too long"),
501+
PinNotSetError::PinPolicyViolation => {
502+
String::from("Pin policy violation")
503+
}
504+
}
505+
})
506+
});
507+
(0x0B, value)
508+
}
476509
};
477510
tag_value_to_struct(tag, value)
478511
}
@@ -525,15 +558,20 @@ impl TryFrom<&Structure<'_>> for crate::model::NfcState {
525558
let err_code: &str = value.downcast_ref()?;
526559
let err = match err_code {
527560
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
528-
"PinNotSet" => crate::model::Error::PinNotSet,
529-
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
530561
"NoCredentials" => crate::model::Error::NoCredentials,
531562
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
532563
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
533564
s => crate::model::Error::Internal(String::from(s)),
534565
};
535566
Ok(Self::Failed(err))
536567
}
568+
0x0B => {
569+
let error = value
570+
.downcast_ref::<&str>()
571+
.ok()
572+
.and_then(PinNotSetError::from_string);
573+
Ok(Self::PinNotSet { error })
574+
}
537575
_ => Err(zvariant::Error::IncorrectType),
538576
}
539577
}

0 commit comments

Comments
 (0)