bitwarden_core/auth/login/
two_factor.rs1use bitwarden_api_api::models::TwoFactorEmailLoginRequestModel;
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 ApiError, Client,
10 auth::{login::PreloginError, password::determine_password_hash},
11};
12
13#[allow(missing_docs)]
14#[derive(Serialize, Deserialize, Debug, JsonSchema)]
15#[serde(rename_all = "camelCase", deny_unknown_fields)]
16pub struct TwoFactorEmailRequest {
17 pub password: String,
19 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 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();
49 config
50 .api_client
51 .two_factor_api()
52 .send_email_login(Some(TwoFactorEmailLoginRequestModel {
53 master_password_hash: Some(password_hash.to_string()),
54 otp: None,
55 auth_request_access_code: None,
56 secret: None,
57 email: input.email.to_owned(),
58 auth_request_id: None,
59 sso_email2_fa_session_token: None,
60 }))
61 .await?;
62
63 Ok(())
64}
65
66#[allow(missing_docs)]
67#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, JsonSchema, Clone)]
68#[repr(u8)]
69pub enum TwoFactorProvider {
70 Authenticator = 0,
71 Email = 1,
72 Duo = 2,
73 Yubikey = 3,
74 U2f = 4,
75 Remember = 5,
76 OrganizationDuo = 6,
77 WebAuthn = 7,
78}
79
80#[allow(missing_docs)]
81#[derive(Serialize, Deserialize, Debug, JsonSchema)]
82#[serde(rename_all = "camelCase", deny_unknown_fields)]
83pub struct TwoFactorRequest {
84 pub token: String,
86 pub provider: TwoFactorProvider,
88 pub remember: bool,
90}