Skip to main content

bitwarden_uniffi/auth/
mod.rs

1use bitwarden_auth::AuthClientExt;
2use bitwarden_core::auth::{
3    AuthRequestResponse, KeyConnectorResponse, RegisterKeyResponse, RegisterTdeKeyResponse,
4    password::MasterPasswordPolicyOptions,
5};
6use bitwarden_crypto::{
7    EncString, HashPurpose, Kdf, TrustDeviceResponse, UnsignedSharedKey,
8    safe::PasswordProtectedKeyEnvelope,
9};
10use bitwarden_encoding::B64;
11
12use crate::{
13    auth::{login::LoginClient, registration::RegistrationClient},
14    error::Result,
15};
16
17mod login;
18mod registration;
19
20#[derive(uniffi::Object)]
21pub struct AuthClient(pub(crate) bitwarden_core::Client);
22
23#[uniffi::export(async_runtime = "tokio")]
24impl AuthClient {
25    /// Client for initializing user account cryptography and unlock methods after JIT provisioning
26    pub fn registration(&self) -> RegistrationClient {
27        RegistrationClient(self.0.clone())
28    }
29
30    /// Client for login functionality
31    pub fn login(&self) -> LoginClient {
32        LoginClient(self.0.auth_new().login())
33    }
34
35    /// Calculate Password Strength
36    pub fn password_strength(
37        &self,
38        password: String,
39        email: String,
40        additional_inputs: Vec<String>,
41    ) -> u8 {
42        self.0
43            .auth()
44            .password_strength(password, email, additional_inputs)
45    }
46
47    /// Evaluate if the provided password satisfies the provided policy
48    pub fn satisfies_policy(
49        &self,
50        password: String,
51        strength: u8,
52        policy: MasterPasswordPolicyOptions,
53    ) -> bool {
54        self.0.auth().satisfies_policy(password, strength, &policy)
55    }
56
57    /// Hash the user password
58    pub async fn hash_password(
59        &self,
60        email: String,
61        password: String,
62        kdf_params: Kdf,
63        purpose: HashPurpose,
64    ) -> Result<B64> {
65        Ok(self
66            .0
67            .kdf()
68            .hash_password(email, password, kdf_params, purpose)
69            .await?)
70    }
71
72    /// Generate keys needed for registration process
73    pub fn make_register_keys(
74        &self,
75        email: String,
76        password: String,
77        kdf: Kdf,
78    ) -> Result<RegisterKeyResponse> {
79        Ok(self.0.auth().make_register_keys(email, password, kdf)?)
80    }
81
82    /// Generate keys needed for TDE process
83    pub async fn make_register_tde_keys(
84        &self,
85        email: String,
86        org_public_key: B64,
87        remember_device: bool,
88    ) -> Result<RegisterTdeKeyResponse> {
89        Ok(self
90            .0
91            .auth()
92            .make_register_tde_keys(email, org_public_key, remember_device)
93            .await?)
94    }
95
96    /// Generate keys needed to onboard a new user without master key to key connector
97    pub fn make_key_connector_keys(&self) -> Result<KeyConnectorResponse> {
98        Ok(self.0.auth().make_key_connector_keys()?)
99    }
100
101    /// Validate the user password
102    ///
103    /// To retrieve the user's password hash, use [`AuthClient::hash_password`] with
104    /// `HashPurpose::LocalAuthentication` during login and persist it. If the login method has no
105    /// password, use the email OTP.
106    pub async fn validate_password(&self, password: String, password_hash: B64) -> Result<bool> {
107        Ok(self
108            .0
109            .auth()
110            .validate_password(password, password_hash)
111            .await?)
112    }
113
114    /// Validate the user password without knowing the password hash
115    ///
116    /// Used for accounts that we know have master passwords but that have not logged in with a
117    /// password. Some example are login with device or TDE.
118    ///
119    /// This works by comparing the provided password against the encrypted user key.
120    pub async fn validate_password_user_key(
121        &self,
122        password: String,
123        encrypted_user_key: String,
124    ) -> Result<B64> {
125        Ok(self
126            .0
127            .auth()
128            .validate_password_user_key(password, encrypted_user_key)
129            .await?)
130    }
131
132    /// Validate the user PIN
133    ///
134    /// To validate the user PIN, you need to have the user's pin_protected_user_key. This key is
135    /// obtained when enabling PIN unlock on the account with the `derive_pin_key` method.
136    ///
137    /// This works by comparing the decrypted user key with the current user key, so the client must
138    /// be unlocked.
139    pub async fn validate_pin(
140        &self,
141        pin: String,
142        pin_protected_user_key: EncString,
143    ) -> Result<bool> {
144        Ok(self
145            .0
146            .auth()
147            .validate_pin(pin, pin_protected_user_key)
148            .await?)
149    }
150
151    /// Validates a PIN against a PIN-protected user key envelope.
152    ///
153    /// The `pin_protected_user_key_envelope` key is obtained when enabling PIN unlock on the
154    /// account with the [bitwarden_core::key_management::CryptoClient::enroll_pin] method.
155    ///
156    /// Returns `false` if validation fails for any reason:
157    /// - The PIN is incorrect
158    /// - The envelope is corrupted or malformed
159    pub fn validate_pin_protected_user_key_envelope(
160        &self,
161        pin: String,
162        pin_protected_user_key_envelope: PasswordProtectedKeyEnvelope,
163    ) -> bool {
164        self.0
165            .auth()
166            .validate_pin_protected_user_key_envelope(pin, pin_protected_user_key_envelope)
167    }
168
169    /// Initialize a new auth request
170    pub fn new_auth_request(&self, email: String) -> Result<AuthRequestResponse> {
171        Ok(self.0.auth().new_auth_request(&email)?)
172    }
173
174    /// Approve an auth request
175    pub fn approve_auth_request(&self, public_key: B64) -> Result<UnsignedSharedKey> {
176        Ok(self.0.auth().approve_auth_request(public_key)?)
177    }
178
179    /// Trust the current device
180    pub fn trust_device(&self) -> Result<TrustDeviceResponse> {
181        Ok(self.0.auth().trust_device()?)
182    }
183}