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