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}