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