Skip to main content

bitwarden_core/auth/login/
password.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3#[cfg(feature = "internal")]
4use tracing::info;
5
6use crate::auth::{
7    api::response::IdentityTokenResponse, login::response::two_factor::TwoFactorProviders,
8};
9#[cfg(feature = "internal")]
10use crate::{
11    Client,
12    auth::{api::request::PasswordTokenRequest, login::LoginError, login::TwoFactorRequest},
13    client::LoginMethod,
14    key_management::{MasterPasswordAuthenticationData, UserDecryptionData},
15};
16
17#[cfg(feature = "internal")]
18pub(crate) async fn login_password(
19    client: &Client,
20    input: &PasswordLoginRequest,
21) -> Result<PasswordLoginResponse, LoginError> {
22    use bitwarden_crypto::EncString;
23
24    use crate::{client::UserLoginMethod, require};
25
26    info!("password logging in");
27
28    let kdf = client.auth().prelogin(input.email.clone()).await?;
29
30    let master_password_authentication =
31        MasterPasswordAuthenticationData::derive(&input.password, &kdf, &input.email)?;
32
33    let password_hash = master_password_authentication
34        .master_password_authentication_hash
35        .to_string();
36
37    let response = request_identity_tokens(client, input, &password_hash).await?;
38
39    if let IdentityTokenResponse::Authenticated(r) = &response {
40        use crate::key_management::account_cryptographic_state::WrappedAccountCryptographicState;
41
42        client.internal.set_tokens(
43            r.access_token.clone(),
44            r.refresh_token.clone(),
45            r.expires_in,
46        );
47
48        let private_key: EncString = require!(&r.private_key).parse()?;
49
50        let user_key_state = WrappedAccountCryptographicState::V1 { private_key };
51
52        let master_password_unlock = r
53            .user_decryption_options
54            .as_ref()
55            .map(UserDecryptionData::try_from)
56            .transpose()?
57            .and_then(|user_decryption| user_decryption.master_password_unlock);
58        if let Some(master_password_unlock) = master_password_unlock {
59            client
60                .internal
61                .initialize_user_crypto_master_password_unlock(
62                    input.password.clone(),
63                    master_password_unlock.clone(),
64                    user_key_state,
65                    &None,
66                )?;
67
68            client
69                .internal
70                .set_login_method(LoginMethod::User(UserLoginMethod::Username {
71                    client_id: "web".to_owned(),
72                    email: master_password_unlock.salt,
73                    kdf: master_password_unlock.kdf,
74                }));
75        }
76    }
77
78    Ok(PasswordLoginResponse::process_response(response))
79}
80
81#[cfg(feature = "internal")]
82async fn request_identity_tokens(
83    client: &Client,
84    input: &PasswordLoginRequest,
85    password_hash: &str,
86) -> Result<IdentityTokenResponse, LoginError> {
87    use crate::DeviceType;
88
89    let config = client.internal.get_api_configurations();
90    PasswordTokenRequest::new(
91        &input.email,
92        password_hash,
93        DeviceType::ChromeBrowser,
94        "b86dd6ab-4265-4ddf-a7f1-eb28d5677f33",
95        &input.two_factor,
96    )
97    .send(&config.identity_config)
98    .await
99}
100
101/// Login to Bitwarden with Username and Password
102#[cfg(feature = "internal")]
103#[derive(Serialize, Deserialize, Debug, JsonSchema)]
104#[serde(rename_all = "camelCase", deny_unknown_fields)]
105pub struct PasswordLoginRequest {
106    /// Bitwarden account email address
107    pub email: String,
108    /// Bitwarden account master password
109    pub password: String,
110    /// Two-factor authentication
111    pub two_factor: Option<TwoFactorRequest>,
112}
113
114#[allow(missing_docs)]
115#[derive(Serialize, Deserialize, Debug, JsonSchema)]
116#[serde(rename_all = "camelCase", deny_unknown_fields)]
117pub struct PasswordLoginResponse {
118    pub authenticated: bool,
119    /// TODO: What does this do?
120    pub reset_master_password: bool,
121    /// Whether or not the user is required to update their master password
122    pub force_password_reset: bool,
123    /// The available two factor authentication options. Present only when authentication fails due
124    /// to requiring a second authentication factor.
125    pub two_factor: Option<TwoFactorProviders>,
126}
127
128impl PasswordLoginResponse {
129    pub(crate) fn process_response(response: IdentityTokenResponse) -> PasswordLoginResponse {
130        match response {
131            IdentityTokenResponse::Authenticated(success) => PasswordLoginResponse {
132                authenticated: true,
133                reset_master_password: success.reset_master_password,
134                force_password_reset: success.force_password_reset,
135                two_factor: None,
136            },
137            IdentityTokenResponse::Payload(_) => PasswordLoginResponse {
138                authenticated: true,
139                reset_master_password: false,
140                force_password_reset: false,
141                two_factor: None,
142            },
143            IdentityTokenResponse::TwoFactorRequired(two_factor) => PasswordLoginResponse {
144                authenticated: false,
145                reset_master_password: false,
146                force_password_reset: false,
147                two_factor: Some(two_factor.two_factor_providers.into()),
148            },
149            IdentityTokenResponse::Refreshed(_) => {
150                unreachable!("Got a `refresh_token` answer to a login request")
151            }
152        }
153    }
154}