bitwarden_core/client/
internal.rs

1use std::sync::{Arc, RwLock};
2
3use bitwarden_crypto::KeyStore;
4#[cfg(any(feature = "internal", feature = "secrets"))]
5use bitwarden_crypto::SymmetricCryptoKey;
6#[cfg(feature = "internal")]
7use bitwarden_crypto::{EncString, Kdf, MasterKey, PinKey, UnsignedSharedKey};
8use chrono::Utc;
9use uuid::Uuid;
10
11#[cfg(feature = "secrets")]
12use super::login_method::ServiceAccountLoginMethod;
13use crate::{
14    auth::renew::renew_token,
15    client::{encryption_settings::EncryptionSettings, login_method::LoginMethod},
16    key_management::KeyIds,
17    DeviceType,
18};
19#[cfg(feature = "internal")]
20use crate::{
21    client::encryption_settings::EncryptionSettingsError,
22    client::{flags::Flags, login_method::UserLoginMethod},
23    error::NotAuthenticatedError,
24};
25
26#[derive(Debug, Clone)]
27pub struct ApiConfigurations {
28    pub identity: bitwarden_api_identity::apis::configuration::Configuration,
29    pub api: bitwarden_api_api::apis::configuration::Configuration,
30    pub device_type: DeviceType,
31}
32
33#[derive(Debug, Default, Clone)]
34pub(crate) struct Tokens {
35    // These two fields are always written to, but they are not read
36    // from the secrets manager SDK.
37    #[cfg_attr(not(feature = "internal"), allow(dead_code))]
38    access_token: Option<String>,
39    pub(crate) expires_on: Option<i64>,
40
41    #[cfg_attr(not(feature = "internal"), allow(dead_code))]
42    pub(crate) refresh_token: Option<String>,
43}
44
45#[derive(Debug)]
46pub struct InternalClient {
47    pub(crate) tokens: RwLock<Tokens>,
48    pub(crate) login_method: RwLock<Option<Arc<LoginMethod>>>,
49
50    #[cfg(feature = "internal")]
51    pub(super) flags: RwLock<Flags>,
52
53    /// Use Client::get_api_configurations().await to access this.
54    /// It should only be used directly in renew_token
55    #[doc(hidden)]
56    pub(crate) __api_configurations: RwLock<Arc<ApiConfigurations>>,
57
58    /// Reqwest client useable for external integrations like email forwarders, HIBP.
59    #[allow(unused)]
60    pub(crate) external_client: reqwest::Client,
61
62    pub(super) key_store: KeyStore<KeyIds>,
63}
64
65impl InternalClient {
66    #[cfg(feature = "internal")]
67    pub fn load_flags(&self, flags: std::collections::HashMap<String, bool>) {
68        *self.flags.write().expect("RwLock is not poisoned") = Flags::load_from_map(flags);
69    }
70
71    #[cfg(feature = "internal")]
72    pub fn get_flags(&self) -> Flags {
73        self.flags.read().expect("RwLock is not poisoned").clone()
74    }
75
76    #[cfg(feature = "internal")]
77    pub(crate) fn get_login_method(&self) -> Option<Arc<LoginMethod>> {
78        self.login_method
79            .read()
80            .expect("RwLock is not poisoned")
81            .clone()
82    }
83
84    pub fn get_access_token_organization(&self) -> Option<Uuid> {
85        match self
86            .login_method
87            .read()
88            .expect("RwLock is not poisoned")
89            .as_deref()
90        {
91            #[cfg(feature = "secrets")]
92            Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken {
93                organization_id,
94                ..
95            })) => Some(*organization_id),
96            _ => None,
97        }
98    }
99
100    #[cfg(any(feature = "internal", feature = "secrets"))]
101    pub(crate) fn set_login_method(&self, login_method: LoginMethod) {
102        use log::debug;
103
104        debug! {"setting login method: {:#?}", login_method}
105        *self.login_method.write().expect("RwLock is not poisoned") = Some(Arc::new(login_method));
106    }
107
108    pub(crate) fn set_tokens(&self, token: String, refresh_token: Option<String>, expires_in: u64) {
109        *self.tokens.write().expect("RwLock is not poisoned") = Tokens {
110            access_token: Some(token.clone()),
111            expires_on: Some(Utc::now().timestamp() + expires_in as i64),
112            refresh_token,
113        };
114        let mut guard = self
115            .__api_configurations
116            .write()
117            .expect("RwLock is not poisoned");
118
119        let inner = Arc::make_mut(&mut guard);
120        inner.identity.oauth_access_token = Some(token.clone());
121        inner.api.oauth_access_token = Some(token);
122    }
123
124    #[cfg(feature = "internal")]
125    pub fn is_authed(&self) -> bool {
126        let is_token_set = self
127            .tokens
128            .read()
129            .expect("RwLock is not poisoned")
130            .access_token
131            .is_some();
132        let is_login_method_set = self
133            .login_method
134            .read()
135            .expect("RwLock is not poisoned")
136            .is_some();
137
138        is_token_set || is_login_method_set
139    }
140
141    #[cfg(feature = "internal")]
142    pub fn get_kdf(&self) -> Result<Kdf, NotAuthenticatedError> {
143        match self
144            .login_method
145            .read()
146            .expect("RwLock is not poisoned")
147            .as_deref()
148        {
149            Some(LoginMethod::User(
150                UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. },
151            )) => Ok(kdf.clone()),
152            _ => Err(NotAuthenticatedError),
153        }
154    }
155
156    pub async fn get_api_configurations(&self) -> Arc<ApiConfigurations> {
157        // At the moment we ignore the error result from the token renewal, if it fails,
158        // the token will end up expiring and the next operation is going to fail anyway.
159        renew_token(self).await.ok();
160        self.__api_configurations
161            .read()
162            .expect("RwLock is not poisoned")
163            .clone()
164    }
165
166    #[cfg(feature = "internal")]
167    pub fn get_http_client(&self) -> &reqwest::Client {
168        &self.external_client
169    }
170
171    pub fn get_key_store(&self) -> &KeyStore<KeyIds> {
172        &self.key_store
173    }
174
175    #[cfg(feature = "internal")]
176    pub(crate) fn initialize_user_crypto_master_key(
177        &self,
178        master_key: MasterKey,
179        user_key: EncString,
180        private_key: EncString,
181    ) -> Result<(), EncryptionSettingsError> {
182        let user_key = master_key.decrypt_user_key(user_key)?;
183        EncryptionSettings::new_decrypted_key(user_key, private_key, &self.key_store)?;
184
185        Ok(())
186    }
187
188    #[cfg(feature = "internal")]
189    pub(crate) fn initialize_user_crypto_decrypted_key(
190        &self,
191        user_key: SymmetricCryptoKey,
192        private_key: EncString,
193    ) -> Result<(), EncryptionSettingsError> {
194        EncryptionSettings::new_decrypted_key(user_key, private_key, &self.key_store)?;
195
196        Ok(())
197    }
198
199    #[cfg(feature = "internal")]
200    pub(crate) fn initialize_user_crypto_pin(
201        &self,
202        pin_key: PinKey,
203        pin_protected_user_key: EncString,
204        private_key: EncString,
205    ) -> Result<(), EncryptionSettingsError> {
206        let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?;
207        self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key)
208    }
209
210    #[cfg(feature = "secrets")]
211    pub(crate) fn initialize_crypto_single_org_key(
212        &self,
213        organization_id: Uuid,
214        key: SymmetricCryptoKey,
215    ) {
216        EncryptionSettings::new_single_org_key(organization_id, key, &self.key_store);
217    }
218
219    #[cfg(feature = "internal")]
220    pub fn initialize_org_crypto(
221        &self,
222        org_keys: Vec<(Uuid, UnsignedSharedKey)>,
223    ) -> Result<(), EncryptionSettingsError> {
224        EncryptionSettings::set_org_keys(org_keys, &self.key_store)
225    }
226}