bitwarden_core/auth/login/
two_factor.rs

1use bitwarden_api_api::models::TwoFactorEmailRequestModel;
2use bitwarden_crypto::HashPurpose;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use serde_repr::{Deserialize_repr, Serialize_repr};
6use thiserror::Error;
7
8use crate::{
9    auth::{login::PreloginError, password::determine_password_hash},
10    ApiError, Client,
11};
12
13#[allow(missing_docs)]
14#[derive(Serialize, Deserialize, Debug, JsonSchema)]
15#[serde(rename_all = "camelCase", deny_unknown_fields)]
16pub struct TwoFactorEmailRequest {
17    /// User Password
18    pub password: String,
19    /// User email
20    pub email: String,
21}
22
23#[allow(missing_docs)]
24#[derive(Debug, Error)]
25pub enum TwoFactorEmailError {
26    #[error(transparent)]
27    Prelogin(#[from] PreloginError),
28    #[error(transparent)]
29    Api(#[from] ApiError),
30    #[error(transparent)]
31    Crypto(#[from] bitwarden_crypto::CryptoError),
32}
33
34pub(crate) async fn send_two_factor_email(
35    client: &Client,
36    input: &TwoFactorEmailRequest,
37) -> Result<(), TwoFactorEmailError> {
38    // TODO: This should be resolved from the client
39    let kdf = client.auth().prelogin(input.email.clone()).await?;
40
41    let password_hash = determine_password_hash(
42        &input.email,
43        &kdf,
44        &input.password,
45        HashPurpose::ServerAuthorization,
46    )?;
47
48    let config = client.internal.get_api_configurations().await;
49    bitwarden_api_api::apis::two_factor_api::two_factor_send_email_login_post(
50        &config.api,
51        Some(TwoFactorEmailRequestModel {
52            master_password_hash: Some(password_hash),
53            otp: None,
54            auth_request_access_code: None,
55            secret: None,
56            email: input.email.to_owned(),
57            auth_request_id: None,
58            sso_email2_fa_session_token: None,
59        }),
60    )
61    .await
62    .map_err(ApiError::from)?;
63
64    Ok(())
65}
66
67#[allow(missing_docs)]
68#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, JsonSchema, Clone)]
69#[repr(u8)]
70pub enum TwoFactorProvider {
71    Authenticator = 0,
72    Email = 1,
73    Duo = 2,
74    Yubikey = 3,
75    U2f = 4,
76    Remember = 5,
77    OrganizationDuo = 6,
78    WebAuthn = 7,
79}
80
81#[allow(missing_docs)]
82#[derive(Serialize, Deserialize, Debug, JsonSchema)]
83#[serde(rename_all = "camelCase", deny_unknown_fields)]
84pub struct TwoFactorRequest {
85    /// Two-factor Token
86    pub token: String,
87    /// Two-factor provider
88    pub provider: TwoFactorProvider,
89    /// Two-factor remember
90    pub remember: bool,
91}