bitwarden_core/auth/
auth_client.rs

1#[cfg(feature = "internal")]
2use bitwarden_crypto::{
3    CryptoError, DeviceKey, EncString, Kdf, TrustDeviceResponse, UnsignedSharedKey,
4    safe::PasswordProtectedKeyEnvelope,
5};
6#[cfg(feature = "internal")]
7use bitwarden_encoding::B64;
8
9#[cfg(feature = "secrets")]
10use crate::auth::login::{AccessTokenLoginRequest, AccessTokenLoginResponse, login_access_token};
11use crate::{
12    Client,
13    auth::{login::LoginError, renew::renew_token},
14};
15#[cfg(feature = "internal")]
16use crate::{
17    auth::{
18        AuthRequestResponse, AuthValidateError, RegisterKeyResponse,
19        auth_request::{ApproveAuthRequestError, approve_auth_request, new_auth_request},
20        key_connector::{KeyConnectorResponse, make_key_connector_keys},
21        login::{
22            ApiKeyLoginRequest, ApiKeyLoginResponse, NewAuthRequestResponse, PasswordLoginRequest,
23            PasswordLoginResponse, PreloginError, TwoFactorEmailError, TwoFactorEmailRequest,
24            login_api_key, login_password, send_two_factor_email,
25        },
26        password::{
27            MasterPasswordPolicyOptions, password_strength, satisfies_policy, validate_password,
28            validate_password_user_key,
29        },
30        pin::{validate_pin, validate_pin_protected_user_key_envelope},
31        register::make_register_keys,
32        tde::{RegisterTdeKeyResponse, make_register_tde_keys},
33    },
34    client::encryption_settings::EncryptionSettingsError,
35};
36
37#[allow(missing_docs)]
38pub struct AuthClient {
39    pub(crate) client: crate::Client,
40}
41
42impl AuthClient {
43    #[allow(missing_docs)]
44    pub async fn renew_token(&self) -> Result<(), LoginError> {
45        renew_token(&self.client.internal).await
46    }
47
48    #[allow(missing_docs)]
49    #[cfg(feature = "secrets")]
50    pub async fn login_access_token(
51        &self,
52        input: &AccessTokenLoginRequest,
53    ) -> Result<AccessTokenLoginResponse, LoginError> {
54        login_access_token(&self.client, input).await
55    }
56}
57
58#[cfg(feature = "internal")]
59impl AuthClient {
60    #[allow(missing_docs)]
61    pub fn password_strength(
62        &self,
63        password: String,
64        email: String,
65        additional_inputs: Vec<String>,
66    ) -> u8 {
67        password_strength(password, email, additional_inputs)
68    }
69
70    #[allow(missing_docs)]
71    pub fn satisfies_policy(
72        &self,
73        password: String,
74        strength: u8,
75        policy: &MasterPasswordPolicyOptions,
76    ) -> bool {
77        satisfies_policy(password, strength, policy)
78    }
79
80    #[allow(missing_docs)]
81    pub fn make_register_keys(
82        &self,
83        email: String,
84        password: String,
85        kdf: Kdf,
86    ) -> Result<RegisterKeyResponse, CryptoError> {
87        make_register_keys(email, password, kdf)
88    }
89
90    #[allow(missing_docs)]
91    pub fn make_register_tde_keys(
92        &self,
93        email: String,
94        org_public_key: B64,
95        remember_device: bool,
96    ) -> Result<RegisterTdeKeyResponse, EncryptionSettingsError> {
97        make_register_tde_keys(&self.client, email, org_public_key, remember_device)
98    }
99
100    #[allow(missing_docs)]
101    pub fn make_key_connector_keys(&self) -> Result<KeyConnectorResponse, CryptoError> {
102        let mut rng = rand::thread_rng();
103        make_key_connector_keys(&mut rng)
104    }
105
106    #[allow(missing_docs)]
107    pub async fn prelogin(&self, email: String) -> Result<Kdf, PreloginError> {
108        use crate::auth::login::prelogin;
109
110        prelogin(&self.client, email).await
111    }
112
113    #[allow(missing_docs)]
114    pub async fn login_password(
115        &self,
116        input: &PasswordLoginRequest,
117    ) -> Result<PasswordLoginResponse, LoginError> {
118        login_password(&self.client, input).await
119    }
120
121    #[allow(missing_docs)]
122    pub async fn login_api_key(
123        &self,
124        input: &ApiKeyLoginRequest,
125    ) -> Result<ApiKeyLoginResponse, LoginError> {
126        login_api_key(&self.client, input).await
127    }
128
129    #[allow(missing_docs)]
130    pub async fn send_two_factor_email(
131        &self,
132        tf: &TwoFactorEmailRequest,
133    ) -> Result<(), TwoFactorEmailError> {
134        send_two_factor_email(&self.client, tf).await
135    }
136
137    #[allow(missing_docs)]
138    pub fn validate_password(
139        &self,
140        password: String,
141        password_hash: B64,
142    ) -> Result<bool, AuthValidateError> {
143        validate_password(&self.client, password, password_hash)
144    }
145
146    #[allow(missing_docs)]
147    pub fn validate_password_user_key(
148        &self,
149        password: String,
150        encrypted_user_key: String,
151    ) -> Result<B64, AuthValidateError> {
152        validate_password_user_key(&self.client, password, encrypted_user_key)
153    }
154
155    #[allow(missing_docs)]
156    pub fn validate_pin(
157        &self,
158        pin: String,
159        pin_protected_user_key: EncString,
160    ) -> Result<bool, AuthValidateError> {
161        validate_pin(&self.client, pin, pin_protected_user_key)
162    }
163
164    /// Validates a PIN against a PIN-protected user key envelope.
165    ///
166    /// Returns `false` if validation fails for any reason:
167    /// - The PIN is incorrect
168    /// - The envelope is corrupted or malformed
169    pub fn validate_pin_protected_user_key_envelope(
170        &self,
171        pin: String,
172        pin_protected_user_key_envelope: PasswordProtectedKeyEnvelope,
173    ) -> bool {
174        validate_pin_protected_user_key_envelope(&self.client, pin, pin_protected_user_key_envelope)
175    }
176
177    #[allow(missing_docs)]
178    pub fn new_auth_request(&self, email: &str) -> Result<AuthRequestResponse, CryptoError> {
179        new_auth_request(email)
180    }
181
182    #[allow(missing_docs)]
183    pub fn approve_auth_request(
184        &self,
185        public_key: B64,
186    ) -> Result<UnsignedSharedKey, ApproveAuthRequestError> {
187        approve_auth_request(&self.client, public_key)
188    }
189
190    #[allow(missing_docs)]
191    pub fn trust_device(&self) -> Result<TrustDeviceResponse, TrustDeviceError> {
192        trust_device(&self.client)
193    }
194}
195
196#[cfg(feature = "internal")]
197impl AuthClient {
198    #[allow(missing_docs)]
199    pub async fn login_device(
200        &self,
201        email: String,
202        device_identifier: String,
203    ) -> Result<NewAuthRequestResponse, LoginError> {
204        use crate::auth::login::send_new_auth_request;
205
206        send_new_auth_request(&self.client, email, device_identifier).await
207    }
208
209    #[allow(missing_docs)]
210    pub async fn login_device_complete(
211        &self,
212        auth_req: NewAuthRequestResponse,
213    ) -> Result<(), LoginError> {
214        use crate::auth::login::complete_auth_request;
215
216        complete_auth_request(&self.client, auth_req).await
217    }
218}
219
220#[allow(missing_docs)]
221#[cfg(feature = "internal")]
222#[derive(Debug, thiserror::Error)]
223#[cfg_attr(feature = "uniffi", derive(uniffi::Error), uniffi(flat_error))]
224pub enum TrustDeviceError {
225    #[error(transparent)]
226    Crypto(#[from] bitwarden_crypto::CryptoError),
227}
228
229#[cfg(feature = "internal")]
230fn trust_device(client: &Client) -> Result<TrustDeviceResponse, TrustDeviceError> {
231    use crate::key_management::SymmetricKeyId;
232
233    let key_store = client.internal.get_key_store();
234    let ctx = key_store.context();
235    // FIXME: [PM-18099] Once DeviceKey deals with KeyIds, this should be updated
236    #[allow(deprecated)]
237    let user_key = ctx.dangerous_get_symmetric_key(SymmetricKeyId::User)?;
238
239    Ok(DeviceKey::trust_device(user_key)?)
240}
241
242impl Client {
243    #[allow(missing_docs)]
244    pub fn auth(&self) -> AuthClient {
245        AuthClient {
246            client: self.clone(),
247        }
248    }
249}