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::{EncString, Kdf, MasterKey, PinKey, UnsignedSharedKey};
8use chrono::Utc;
9use uuid::Uuid;
10
11#[cfg(feature = "secrets")]
12use super::login_method::ServiceAccountLoginMethod;
13#[cfg(any(feature = "internal", feature = "secrets"))]
14use crate::client::encryption_settings::EncryptionSettings;
15use crate::{
16 auth::renew::renew_token, client::login_method::LoginMethod, error::UserIdAlreadySetError,
17 key_management::KeyIds, 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 #[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) user_id: OnceLock<Uuid>,
48 pub(crate) tokens: RwLock<Tokens>,
49 pub(crate) login_method: RwLock<Option<Arc<LoginMethod>>>,
50
51 #[cfg(feature = "internal")]
52 pub(super) flags: RwLock<Flags>,
53
54 #[doc(hidden)]
57 pub(crate) __api_configurations: RwLock<Arc<ApiConfigurations>>,
58
59 #[allow(unused)]
61 pub(crate) external_client: reqwest::Client,
62
63 pub(super) key_store: KeyStore<KeyIds>,
64}
65
66impl InternalClient {
67 #[cfg(feature = "internal")]
68 pub fn load_flags(&self, flags: std::collections::HashMap<String, bool>) {
69 *self.flags.write().expect("RwLock is not poisoned") = Flags::load_from_map(flags);
70 }
71
72 #[cfg(feature = "internal")]
73 pub fn get_flags(&self) -> Flags {
74 self.flags.read().expect("RwLock is not poisoned").clone()
75 }
76
77 #[cfg(feature = "internal")]
78 pub(crate) fn get_login_method(&self) -> Option<Arc<LoginMethod>> {
79 self.login_method
80 .read()
81 .expect("RwLock is not poisoned")
82 .clone()
83 }
84
85 pub fn get_access_token_organization(&self) -> Option<Uuid> {
86 match self
87 .login_method
88 .read()
89 .expect("RwLock is not poisoned")
90 .as_deref()
91 {
92 #[cfg(feature = "secrets")]
93 Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken {
94 organization_id,
95 ..
96 })) => Some(*organization_id),
97 _ => None,
98 }
99 }
100
101 #[cfg(any(feature = "internal", feature = "secrets"))]
102 pub(crate) fn set_login_method(&self, login_method: LoginMethod) {
103 use log::debug;
104
105 debug! {"setting login method: {:#?}", login_method}
106 *self.login_method.write().expect("RwLock is not poisoned") = Some(Arc::new(login_method));
107 }
108
109 pub(crate) fn set_tokens(&self, token: String, refresh_token: Option<String>, expires_in: u64) {
110 *self.tokens.write().expect("RwLock is not poisoned") = Tokens {
111 access_token: Some(token.clone()),
112 expires_on: Some(Utc::now().timestamp() + expires_in as i64),
113 refresh_token,
114 };
115 let mut guard = self
116 .__api_configurations
117 .write()
118 .expect("RwLock is not poisoned");
119
120 let inner = Arc::make_mut(&mut guard);
121 inner.identity.oauth_access_token = Some(token.clone());
122 inner.api.oauth_access_token = Some(token);
123 }
124
125 #[cfg(feature = "internal")]
126 pub fn is_authed(&self) -> bool {
127 let is_token_set = self
128 .tokens
129 .read()
130 .expect("RwLock is not poisoned")
131 .access_token
132 .is_some();
133 let is_login_method_set = self
134 .login_method
135 .read()
136 .expect("RwLock is not poisoned")
137 .is_some();
138
139 is_token_set || is_login_method_set
140 }
141
142 #[cfg(feature = "internal")]
143 pub fn get_kdf(&self) -> Result<Kdf, NotAuthenticatedError> {
144 match self
145 .login_method
146 .read()
147 .expect("RwLock is not poisoned")
148 .as_deref()
149 {
150 Some(LoginMethod::User(
151 UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. },
152 )) => Ok(kdf.clone()),
153 _ => Err(NotAuthenticatedError),
154 }
155 }
156
157 pub async fn get_api_configurations(&self) -> Arc<ApiConfigurations> {
158 renew_token(self).await.ok();
161 self.__api_configurations
162 .read()
163 .expect("RwLock is not poisoned")
164 .clone()
165 }
166
167 #[cfg(feature = "internal")]
168 pub fn get_http_client(&self) -> &reqwest::Client {
169 &self.external_client
170 }
171
172 pub fn get_key_store(&self) -> &KeyStore<KeyIds> {
173 &self.key_store
174 }
175
176 pub fn init_user_id(&self, user_id: Uuid) -> Result<(), UserIdAlreadySetError> {
177 self.user_id.set(user_id).map_err(|_| UserIdAlreadySetError)
178 }
179
180 pub fn get_user_id(&self) -> Option<Uuid> {
181 self.user_id.get().copied()
182 }
183
184 #[cfg(feature = "internal")]
185 pub(crate) fn initialize_user_crypto_master_key(
186 &self,
187 master_key: MasterKey,
188 user_key: EncString,
189 private_key: EncString,
190 ) -> Result<(), EncryptionSettingsError> {
191 let user_key = master_key.decrypt_user_key(user_key)?;
192 EncryptionSettings::new_decrypted_key(user_key, private_key, &self.key_store)?;
193
194 Ok(())
195 }
196
197 #[cfg(feature = "internal")]
198 pub(crate) fn initialize_user_crypto_decrypted_key(
199 &self,
200 user_key: SymmetricCryptoKey,
201 private_key: EncString,
202 ) -> Result<(), EncryptionSettingsError> {
203 EncryptionSettings::new_decrypted_key(user_key, private_key, &self.key_store)?;
204
205 Ok(())
206 }
207
208 #[cfg(feature = "internal")]
209 pub(crate) fn initialize_user_crypto_pin(
210 &self,
211 pin_key: PinKey,
212 pin_protected_user_key: EncString,
213 private_key: EncString,
214 ) -> Result<(), EncryptionSettingsError> {
215 let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?;
216 self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key)
217 }
218
219 #[cfg(feature = "secrets")]
220 pub(crate) fn initialize_crypto_single_org_key(
221 &self,
222 organization_id: Uuid,
223 key: SymmetricCryptoKey,
224 ) {
225 EncryptionSettings::new_single_org_key(organization_id, key, &self.key_store);
226 }
227
228 #[cfg(feature = "internal")]
229 pub fn initialize_org_crypto(
230 &self,
231 org_keys: Vec<(Uuid, UnsignedSharedKey)>,
232 ) -> Result<(), EncryptionSettingsError> {
233 EncryptionSettings::set_org_keys(org_keys, &self.key_store)
234 }
235}