bitwarden_auth/login/models/
login_success_response.rs1use std::fmt::Debug;
2
3use bitwarden_core::{
4 MissingFieldError,
5 key_management::{
6 MasterPasswordError,
7 account_cryptographic_state::{
8 AccountKeysResponseParseError, WrappedAccountCryptographicState,
9 },
10 },
11 require,
12};
13use bitwarden_policies::MasterPasswordPolicyResponse;
14use thiserror::Error;
15
16use crate::login::{api::response::LoginSuccessApiResponse, models::UserDecryptionOptionsResponse};
17
18#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
21#[serde(rename_all = "camelCase")]
22#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
23#[cfg_attr(
24 feature = "wasm",
25 derive(tsify::Tsify),
26 tsify(into_wasm_abi, from_wasm_abi)
27)]
28pub struct LoginSuccessResponse {
29 pub access_token: String,
31
32 pub expires_in: u64,
34
35 pub expires_at: i64,
38
39 pub scope: String,
42
43 pub token_type: String,
47
48 pub refresh_token: Option<String>,
51
52 pub user_key_wrapped_user_private_key: Option<String>,
55
56 pub two_factor_token: Option<String>,
58
59 pub force_password_reset: Option<bool>,
62
63 pub api_use_key_connector: Option<bool>,
68
69 pub user_decryption_options: UserDecryptionOptionsResponse,
71
72 pub master_password_policy: Option<MasterPasswordPolicyResponse>,
75
76 pub wrapped_account_crypto_state: Option<WrappedAccountCryptographicState>,
78}
79
80impl TryFrom<LoginSuccessApiResponse> for LoginSuccessResponse {
81 type Error = LoginResponseError;
82 fn try_from(response: LoginSuccessApiResponse) -> Result<Self, Self::Error> {
83 let expires_at =
88 chrono::Utc::now().timestamp_millis() + (response.expires_in * 1000) as i64;
89
90 Ok(LoginSuccessResponse {
91 access_token: response.access_token,
92 expires_in: response.expires_in,
93 expires_at,
94 scope: response.scope,
95 token_type: response.token_type,
96 refresh_token: response.refresh_token,
97 user_key_wrapped_user_private_key: response.private_key,
98 two_factor_token: response.two_factor_token,
99 force_password_reset: response.force_password_reset,
100 api_use_key_connector: response.api_use_key_connector,
101 user_decryption_options: require!(response.user_decryption_options).try_into()?,
103 master_password_policy: response.master_password_policy.map(|policy| policy.into()),
104 wrapped_account_crypto_state: response
105 .account_keys
106 .as_ref()
107 .map(TryInto::try_into)
108 .transpose()?,
109 })
110 }
111}
112
113#[derive(Debug, Error)]
115pub enum LoginResponseError {
116 #[error(transparent)]
118 MasterPassword(#[from] MasterPasswordError),
119
120 #[error("Failed to parse account keys: {0}")]
122 AccountKeys(#[from] AccountKeysResponseParseError),
123}
124
125impl From<MissingFieldError> for LoginResponseError {
126 fn from(value: MissingFieldError) -> Self {
127 LoginResponseError::MasterPassword(value.into())
128 }
129}