bitwarden_core/auth/login/
password.rs

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