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