Skip to main content

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