bitwarden_core/auth/login/
auth_request.rs

1use bitwarden_api_api::{
2    apis::auth_requests_api::{auth_requests_id_response_get, auth_requests_post},
3    models::{AuthRequestCreateRequestModel, AuthRequestType},
4};
5use bitwarden_crypto::Kdf;
6use uuid::Uuid;
7
8use super::LoginError;
9use crate::{
10    auth::{
11        api::{request::AuthRequestTokenRequest, response::IdentityTokenResponse},
12        auth_request::new_auth_request,
13    },
14    client::{LoginMethod, UserLoginMethod},
15    key_management::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
16    require, ApiError, Client,
17};
18
19#[allow(missing_docs)]
20pub struct NewAuthRequestResponse {
21    pub fingerprint: String,
22    email: String,
23    device_identifier: String,
24    auth_request_id: Uuid,
25    access_code: String,
26    private_key: String,
27}
28
29pub(crate) async fn send_new_auth_request(
30    client: &Client,
31    email: String,
32    device_identifier: String,
33) -> Result<NewAuthRequestResponse, LoginError> {
34    let config = client.internal.get_api_configurations().await;
35
36    let auth = new_auth_request(&email)?;
37
38    let req = AuthRequestCreateRequestModel {
39        email: email.clone(),
40        public_key: auth.public_key,
41        device_identifier: device_identifier.clone(),
42        access_code: auth.access_code.clone(),
43        r#type: AuthRequestType::AuthenticateAndUnlock,
44    };
45
46    let res = auth_requests_post(&config.api, Some(req))
47        .await
48        .map_err(ApiError::from)?;
49
50    Ok(NewAuthRequestResponse {
51        fingerprint: auth.fingerprint,
52        email,
53        device_identifier,
54        auth_request_id: require!(res.id),
55        access_code: auth.access_code,
56        private_key: auth.private_key,
57    })
58}
59
60pub(crate) async fn complete_auth_request(
61    client: &Client,
62    auth_req: NewAuthRequestResponse,
63) -> Result<(), LoginError> {
64    let config = client.internal.get_api_configurations().await;
65
66    let res = auth_requests_id_response_get(
67        &config.api,
68        auth_req.auth_request_id,
69        Some(&auth_req.access_code),
70    )
71    .await
72    .map_err(ApiError::from)?;
73
74    let approved = res.request_approved.unwrap_or(false);
75
76    if !approved {
77        return Err(LoginError::AuthRequestNotApproved);
78    }
79
80    let response = AuthRequestTokenRequest::new(
81        &auth_req.email,
82        &auth_req.auth_request_id,
83        &auth_req.access_code,
84        config.device_type,
85        &auth_req.device_identifier,
86    )
87    .send(&config)
88    .await?;
89
90    if let IdentityTokenResponse::Authenticated(r) = response {
91        let kdf = Kdf::default();
92
93        client.internal.set_tokens(
94            r.access_token.clone(),
95            r.refresh_token.clone(),
96            r.expires_in,
97        );
98        client
99            .internal
100            .set_login_method(LoginMethod::User(UserLoginMethod::Username {
101                client_id: "web".to_owned(),
102                email: auth_req.email.to_owned(),
103                kdf: kdf.clone(),
104            }));
105
106        let method = match res.master_password_hash {
107            Some(_) => AuthRequestMethod::MasterKey {
108                protected_master_key: require!(res.key).parse()?,
109                auth_request_key: require!(r.key).parse()?,
110            },
111            None => AuthRequestMethod::UserKey {
112                protected_user_key: require!(res.key).parse()?,
113            },
114        };
115
116        client
117            .crypto()
118            .initialize_user_crypto(InitUserCryptoRequest {
119                user_id: None,
120                kdf_params: kdf,
121                email: auth_req.email,
122                private_key: require!(r.private_key).parse()?,
123                signing_key: None,
124                method: InitUserCryptoMethod::AuthRequest {
125                    request_private_key: auth_req.private_key,
126                    method,
127                },
128            })
129            .await?;
130
131        Ok(())
132    } else {
133        Err(LoginError::AuthenticationFailed)
134    }
135}