bitwarden_core/auth/login/
auth_request.rs1use bitwarden_api_api::models::{AuthRequestCreateRequestModel, AuthRequestType};
2use bitwarden_crypto::Kdf;
3use bitwarden_encoding::B64;
4use uuid::Uuid;
5
6use super::LoginError;
7use crate::{
8 Client,
9 auth::{
10 api::{request::AuthRequestTokenRequest, response::IdentityTokenResponse},
11 auth_request::new_auth_request,
12 },
13 key_management::{
14 UserDecryptionData,
15 account_cryptographic_state::WrappedAccountCryptographicState,
16 crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
17 },
18 require,
19};
20
21#[allow(missing_docs)]
22pub struct NewAuthRequestResponse {
23 pub fingerprint: String,
24 email: String,
25 device_identifier: String,
26 auth_request_id: Uuid,
27 access_code: String,
28 private_key: B64,
29}
30
31pub(crate) async fn send_new_auth_request(
32 client: &Client,
33 email: String,
34 device_identifier: String,
35) -> Result<NewAuthRequestResponse, LoginError> {
36 let config = client.internal.get_api_configurations();
37
38 let auth = new_auth_request(&email)?;
39
40 let req = AuthRequestCreateRequestModel {
41 email: email.clone(),
42 public_key: auth.public_key.to_string(),
43 device_identifier: device_identifier.clone(),
44 access_code: auth.access_code.clone(),
45 r#type: AuthRequestType::AuthenticateAndUnlock,
46 };
47
48 let res = config
49 .api_client
50 .auth_requests_api()
51 .post(Some(req))
52 .await?;
53
54 Ok(NewAuthRequestResponse {
55 fingerprint: auth.fingerprint,
56 email,
57 device_identifier,
58 auth_request_id: require!(res.id),
59 access_code: auth.access_code,
60 private_key: auth.private_key,
61 })
62}
63
64pub(crate) async fn complete_auth_request(
65 client: &Client,
66 auth_req: NewAuthRequestResponse,
67) -> Result<(), LoginError> {
68 let config = client.internal.get_api_configurations();
69 let res = config
70 .api_client
71 .auth_requests_api()
72 .get_response(auth_req.auth_request_id, Some(&auth_req.access_code))
73 .await?;
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.identity_config)
89 .await?;
90
91 if let IdentityTokenResponse::Authenticated(r) = response {
92 client
93 .internal
94 .set_tokens(
95 r.access_token.clone(),
96 r.refresh_token.clone(),
97 r.expires_in,
98 )
99 .await;
100
101 let method = match res.master_password_hash {
102 Some(_) => AuthRequestMethod::MasterKey {
103 protected_master_key: require!(res.key).parse()?,
104 auth_request_key: require!(r.key).parse()?,
105 },
106 None => AuthRequestMethod::UserKey {
107 protected_user_key: require!(res.key).parse()?,
108 },
109 };
110
111 let master_password_unlock = r
112 .user_decryption_options
113 .as_ref()
114 .map(UserDecryptionData::try_from)
115 .transpose()?
116 .and_then(|user_decryption| user_decryption.master_password_unlock);
117 let kdf = master_password_unlock
118 .as_ref()
119 .map(|mpu| mpu.kdf.clone())
120 .unwrap_or_else(Kdf::default_pbkdf2);
121 let salt = master_password_unlock
122 .as_ref()
123 .map(|mpu| mpu.salt.clone())
124 .unwrap_or_else(|| auth_req.email.clone());
125
126 client
127 .crypto()
128 .initialize_user_crypto(InitUserCryptoRequest {
129 user_id: None,
130 kdf_params: kdf,
131 email: salt,
132 account_cryptographic_state: WrappedAccountCryptographicState::V1 {
133 private_key: require!(r.private_key).parse()?,
134 },
135 method: InitUserCryptoMethod::AuthRequest {
136 request_private_key: auth_req.private_key,
137 method,
138 },
139 upgrade_token: None,
140 })
141 .await?;
142
143 Ok(())
144 } else {
145 Err(LoginError::AuthenticationFailed)
146 }
147}