1use std::sync::{Arc, OnceLock, RwLock};
2
3use bitwarden_crypto::KeyStore;
4#[cfg(any(feature = "internal", feature = "secrets"))]
5use bitwarden_crypto::SymmetricCryptoKey;
6#[cfg(feature = "internal")]
7use bitwarden_crypto::{CryptoError, EncString, Kdf, MasterKey, PinKey, UnsignedSharedKey};
8#[cfg(feature = "internal")]
9use bitwarden_state::registry::StateRegistry;
10use chrono::Utc;
11
12#[cfg(any(feature = "internal", feature = "secrets"))]
13use crate::client::encryption_settings::EncryptionSettings;
14#[cfg(feature = "secrets")]
15use crate::client::login_method::ServiceAccountLoginMethod;
16use crate::{
17 auth::renew::renew_token, client::login_method::LoginMethod, error::UserIdAlreadySetError,
18 key_management::KeyIds, DeviceType, OrganizationId, UserId,
19};
20#[cfg(feature = "internal")]
21use crate::{
22 client::{
23 encryption_settings::{AccountEncryptionKeys, EncryptionSettingsError},
24 flags::Flags,
25 login_method::UserLoginMethod,
26 },
27 error::NotAuthenticatedError,
28 key_management::{
29 crypto::InitUserCryptoRequest, PasswordProtectedKeyEnvelope, SecurityState,
30 SignedSecurityState,
31 },
32};
33
34#[cfg(feature = "internal")]
36pub(crate) struct UserKeyState {
37 pub(crate) private_key: EncString,
38 pub(crate) signing_key: Option<EncString>,
39 pub(crate) security_state: Option<SignedSecurityState>,
40}
41#[cfg(feature = "internal")]
42impl From<&InitUserCryptoRequest> for UserKeyState {
43 fn from(req: &InitUserCryptoRequest) -> Self {
44 UserKeyState {
45 private_key: req.private_key.clone(),
46 signing_key: req.signing_key.clone(),
47 security_state: req.security_state.clone(),
48 }
49 }
50}
51
52#[allow(missing_docs)]
53#[derive(Debug, Clone)]
54pub struct ApiConfigurations {
55 pub identity: bitwarden_api_identity::apis::configuration::Configuration,
56 pub api: bitwarden_api_api::apis::configuration::Configuration,
57 pub device_type: DeviceType,
58}
59
60#[derive(Debug, Clone)]
62pub(crate) enum Tokens {
63 SdkManaged(SdkManagedTokens),
64 ClientManaged(Arc<dyn ClientManagedTokens>),
65}
66
67#[async_trait::async_trait]
69pub trait ClientManagedTokens: std::fmt::Debug + Send + Sync {
70 async fn get_access_token(&self) -> Option<String>;
72}
73
74#[derive(Debug, Default, Clone)]
76pub(crate) struct SdkManagedTokens {
77 #[allow(dead_code)]
80 access_token: Option<String>,
81 pub(crate) expires_on: Option<i64>,
82
83 #[cfg_attr(not(feature = "internal"), allow(dead_code))]
84 pub(crate) refresh_token: Option<String>,
85}
86
87#[allow(missing_docs)]
88#[derive(Debug)]
89pub struct InternalClient {
90 pub(crate) user_id: OnceLock<UserId>,
91 pub(crate) tokens: RwLock<Tokens>,
92 pub(crate) login_method: RwLock<Option<Arc<LoginMethod>>>,
93
94 #[cfg(feature = "internal")]
95 pub(super) flags: RwLock<Flags>,
96
97 #[doc(hidden)]
100 pub(crate) __api_configurations: RwLock<Arc<ApiConfigurations>>,
101
102 #[allow(unused)]
104 pub(crate) external_client: reqwest::Client,
105
106 pub(super) key_store: KeyStore<KeyIds>,
107 #[cfg(feature = "internal")]
108 pub(crate) security_state: RwLock<Option<SecurityState>>,
109
110 #[cfg(feature = "internal")]
111 pub(crate) repository_map: StateRegistry,
112}
113
114impl InternalClient {
115 #[cfg(feature = "internal")]
118 pub fn load_flags(&self, flags: std::collections::HashMap<String, bool>) {
119 *self.flags.write().expect("RwLock is not poisoned") = Flags::load_from_map(flags);
120 }
121
122 #[cfg(feature = "internal")]
124 pub fn get_flags(&self) -> Flags {
125 self.flags.read().expect("RwLock is not poisoned").clone()
126 }
127
128 #[cfg(feature = "internal")]
129 pub(crate) fn get_login_method(&self) -> Option<Arc<LoginMethod>> {
130 self.login_method
131 .read()
132 .expect("RwLock is not poisoned")
133 .clone()
134 }
135
136 #[allow(missing_docs)]
137 pub fn get_access_token_organization(&self) -> Option<OrganizationId> {
138 match self
139 .login_method
140 .read()
141 .expect("RwLock is not poisoned")
142 .as_deref()
143 {
144 #[cfg(feature = "secrets")]
145 Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken {
146 organization_id,
147 ..
148 })) => Some(*organization_id),
149 _ => None,
150 }
151 }
152
153 #[cfg(any(feature = "internal", feature = "secrets"))]
154 pub(crate) fn set_login_method(&self, login_method: LoginMethod) {
155 use log::debug;
156
157 debug! {"setting login method: {login_method:#?}"}
158 *self.login_method.write().expect("RwLock is not poisoned") = Some(Arc::new(login_method));
159 }
160
161 pub(crate) fn set_tokens(&self, token: String, refresh_token: Option<String>, expires_in: u64) {
162 *self.tokens.write().expect("RwLock is not poisoned") =
163 Tokens::SdkManaged(SdkManagedTokens {
164 access_token: Some(token.clone()),
165 expires_on: Some(Utc::now().timestamp() + expires_in as i64),
166 refresh_token,
167 });
168 self.set_api_tokens_internal(token);
169 }
170
171 pub(crate) fn set_api_tokens_internal(&self, token: String) {
173 let mut guard = self
174 .__api_configurations
175 .write()
176 .expect("RwLock is not poisoned");
177
178 let inner = Arc::make_mut(&mut guard);
179 inner.identity.oauth_access_token = Some(token.clone());
180 inner.api.oauth_access_token = Some(token);
181 }
182
183 #[allow(missing_docs)]
184 #[cfg(feature = "internal")]
185 pub fn get_kdf(&self) -> Result<Kdf, NotAuthenticatedError> {
186 match self
187 .login_method
188 .read()
189 .expect("RwLock is not poisoned")
190 .as_deref()
191 {
192 Some(LoginMethod::User(
193 UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. },
194 )) => Ok(kdf.clone()),
195 _ => Err(NotAuthenticatedError),
196 }
197 }
198
199 #[allow(missing_docs)]
200 pub async fn get_api_configurations(&self) -> Arc<ApiConfigurations> {
201 renew_token(self).await.ok();
204 self.__api_configurations
205 .read()
206 .expect("RwLock is not poisoned")
207 .clone()
208 }
209
210 #[allow(missing_docs)]
211 #[cfg(feature = "internal")]
212 pub fn get_http_client(&self) -> &reqwest::Client {
213 &self.external_client
214 }
215
216 #[allow(missing_docs)]
217 pub fn get_key_store(&self) -> &KeyStore<KeyIds> {
218 &self.key_store
219 }
220
221 #[cfg(feature = "internal")]
225 pub fn get_security_version(&self) -> u64 {
226 self.security_state
227 .read()
228 .expect("RwLock is not poisoned")
229 .as_ref()
230 .map_or(1, |state| state.version())
231 }
232
233 #[allow(missing_docs)]
234 pub fn init_user_id(&self, user_id: UserId) -> Result<(), UserIdAlreadySetError> {
235 let set_uuid = self.user_id.get_or_init(|| user_id);
236
237 if *set_uuid != user_id {
241 Err(UserIdAlreadySetError)
242 } else {
243 Ok(())
244 }
245 }
246
247 #[allow(missing_docs)]
248 pub fn get_user_id(&self) -> Option<UserId> {
249 self.user_id.get().copied()
250 }
251
252 #[cfg(feature = "internal")]
253 pub(crate) fn initialize_user_crypto_master_key(
254 &self,
255 master_key: MasterKey,
256 user_key: EncString,
257 key_state: UserKeyState,
258 ) -> Result<(), EncryptionSettingsError> {
259 let user_key = master_key.decrypt_user_key(user_key)?;
260 self.initialize_user_crypto_decrypted_key(user_key, key_state)
261 }
262
263 #[cfg(feature = "internal")]
264 pub(crate) fn initialize_user_crypto_decrypted_key(
265 &self,
266 user_key: SymmetricCryptoKey,
267 key_state: UserKeyState,
268 ) -> Result<(), EncryptionSettingsError> {
269 match user_key {
270 SymmetricCryptoKey::Aes256CbcHmacKey(ref user_key) => {
271 EncryptionSettings::new_decrypted_key(
272 AccountEncryptionKeys::V1 {
273 user_key: user_key.clone(),
274 private_key: key_state.private_key,
275 },
276 &self.key_store,
277 &self.security_state,
278 )?;
279 }
280 SymmetricCryptoKey::XChaCha20Poly1305Key(ref user_key) => {
281 EncryptionSettings::new_decrypted_key(
282 AccountEncryptionKeys::V2 {
283 user_key: user_key.clone(),
284 private_key: key_state.private_key,
285 signing_key: key_state
286 .signing_key
287 .ok_or(EncryptionSettingsError::InvalidSigningKey)?,
288 security_state: key_state
289 .security_state
290 .ok_or(EncryptionSettingsError::InvalidSecurityState)?,
291 },
292 &self.key_store,
293 &self.security_state,
294 )?;
295 }
296 _ => {
297 return Err(CryptoError::InvalidKey.into());
298 }
299 }
300
301 Ok(())
302 }
303
304 #[cfg(feature = "internal")]
305 pub(crate) fn initialize_user_crypto_pin(
306 &self,
307 pin_key: PinKey,
308 pin_protected_user_key: EncString,
309 key_state: UserKeyState,
310 ) -> Result<(), EncryptionSettingsError> {
311 let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?;
312 self.initialize_user_crypto_decrypted_key(decrypted_user_key, key_state)
313 }
314
315 #[cfg(feature = "internal")]
316 pub(crate) fn initialize_user_crypto_pin_envelope(
317 &self,
318 pin: String,
319 pin_protected_user_key_envelope: PasswordProtectedKeyEnvelope,
320 key_state: UserKeyState,
321 ) -> Result<(), EncryptionSettingsError> {
322 let decrypted_user_key = {
323 use crate::key_management::SymmetricKeyId;
326 let ctx = &mut self.key_store.context_mut();
327 let decrypted_user_key_id = pin_protected_user_key_envelope
328 .unseal(SymmetricKeyId::Local("tmp_unlock_pin"), &pin, ctx)
329 .map_err(|_| EncryptionSettingsError::WrongPin)?;
330
331 #[allow(deprecated)]
334 ctx.dangerous_get_symmetric_key(decrypted_user_key_id)?
335 .clone()
336 };
337 self.initialize_user_crypto_decrypted_key(decrypted_user_key, key_state)
338 }
339
340 #[cfg(feature = "secrets")]
341 pub(crate) fn initialize_crypto_single_org_key(
342 &self,
343 organization_id: OrganizationId,
344 key: SymmetricCryptoKey,
345 ) {
346 EncryptionSettings::new_single_org_key(organization_id, key, &self.key_store);
347 }
348
349 #[allow(missing_docs)]
350 #[cfg(feature = "internal")]
351 pub fn initialize_org_crypto(
352 &self,
353 org_keys: Vec<(OrganizationId, UnsignedSharedKey)>,
354 ) -> Result<(), EncryptionSettingsError> {
355 EncryptionSettings::set_org_keys(org_keys, &self.key_store)
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use crate::Client;
362
363 #[test]
364 fn initializing_user_multiple_times() {
365 use super::*;
366
367 let client = Client::new(None);
368 let user_id = UserId::new_v4();
369
370 assert!(client.internal.init_user_id(user_id).is_ok());
372 assert_eq!(client.internal.get_user_id(), Some(user_id));
373
374 assert!(client.internal.init_user_id(user_id).is_ok());
376
377 let different_user_id = UserId::new_v4();
379 assert!(client.internal.init_user_id(different_user_id).is_err());
380 }
381}