passkey_authenticator/user_validation.rs
1use passkey_types::{ctap2::Ctap2Error, Passkey};
2
3#[cfg(doc)]
4use crate::Authenticator;
5
6/// The result of a user validation check.
7#[derive(Clone, Copy, PartialEq)]
8pub struct UserCheck {
9 /// Indicates whether the user was present.
10 pub presence: bool,
11
12 /// Indicates whether the user was verified.
13 pub verification: bool,
14}
15
16/// Pluggable trait for the [`Authenticator`] to do user interaction and verification.
17#[cfg_attr(any(test, feature = "testable"), mockall::automock(type PasskeyItem = Passkey;))]
18#[async_trait::async_trait]
19pub trait UserValidationMethod {
20 /// The type of the passkey item that can be used to display additional information about the operation to the user.
21 type PasskeyItem: TryInto<Passkey> + Send + Sync;
22
23 /// Check for the user's presence and obtain consent for the operation. The operation may
24 /// also require the user to be verified.
25 ///
26 /// * `crdential` - Can be used to display additional information about the operation to the user.
27 /// * `presence` - Indicates whether the user's presence is required.
28 /// * `verification` - Indicates whether the user should be verified.
29 async fn check_user<'a>(
30 &self,
31 credential: Option<&'a Self::PasskeyItem>,
32 presence: bool,
33 verification: bool,
34 ) -> Result<UserCheck, Ctap2Error>;
35
36 /// Indicates whether this type is capable of testing user presence.
37 fn is_presence_enabled(&self) -> bool;
38
39 /// Indicates that this type is capable of verifying the user within itself.
40 /// For example, devices with UI, biometrics fall into this category.
41 ///
42 /// If `Some(true)`, it indicates that the device is capable of user verification
43 /// within itself and has been configured.
44 ///
45 /// If Some(false), it indicates that the device is capable of user verification
46 /// within itself and has not been yet configured. For example, a biometric device that has not
47 /// yet been configured will return this parameter set to false.
48 ///
49 /// If `None`, it indicates that the device is not capable of user verification within itself.
50 ///
51 /// A device that can only do Client PIN will set this to `None`.
52 ///
53 /// If a device is capable of verifying the user within itself as well as able to do Client PIN,
54 /// it will return both `Some` and the Client PIN option.
55 fn is_verification_enabled(&self) -> Option<bool>;
56}
57
58#[cfg(any(test, feature = "testable"))]
59impl MockUserValidationMethod {
60 /// Sets up the mock for returning true for the verification.
61 pub fn verified_user(times: usize) -> Self {
62 let mut user_mock = MockUserValidationMethod::new();
63 user_mock.expect_is_presence_enabled().returning(|| true);
64 user_mock
65 .expect_is_verification_enabled()
66 .returning(|| Some(true))
67 .times(..);
68 user_mock.expect_is_presence_enabled().returning(|| true);
69 user_mock
70 .expect_check_user()
71 .with(
72 mockall::predicate::always(),
73 mockall::predicate::eq(true),
74 mockall::predicate::eq(true),
75 )
76 .returning(|_, _, _| {
77 Ok(UserCheck {
78 presence: true,
79 verification: true,
80 })
81 })
82 .times(times);
83 user_mock
84 }
85
86 /// Sets up the mock for returning true for the verification.
87 pub fn verified_user_with_credential(times: usize, credential: Passkey) -> Self {
88 let mut user_mock = MockUserValidationMethod::new();
89 user_mock
90 .expect_is_verification_enabled()
91 .returning(|| Some(true));
92 user_mock
93 .expect_check_user()
94 .withf(move |cred, up, uv| cred == &Some(&credential) && *up && *uv)
95 .returning(|_, _, _| {
96 Ok(UserCheck {
97 presence: true,
98 verification: true,
99 })
100 })
101 .times(times);
102 user_mock
103 }
104}