1use crate::traits::private::Internal;
3use crate::{
4 AccessOptions, ClientAccountStorage, ClientBaseStorage,
5 ClientFolderStorage, ClientSecretStorage, Error, Result,
6 StorageChangeEvent,
7};
8use async_trait::async_trait;
9use sos_backend::StorageError;
10use sos_core::{
11 events::{ReadEvent, WriteEvent},
12 AuthenticationError, SecretId, VaultCommit, VaultId,
13};
14use sos_vault::secret::{Secret, SecretMeta, SecretRow};
15use sos_vault::Summary;
16
17#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
18#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
19impl<T> ClientSecretStorage for T
20where
21 T: ClientAccountStorage
22 + ClientFolderStorage
23 + ClientBaseStorage
24 + Send
25 + Sync,
26{
27 async fn create_secret(
28 &mut self,
29 secret_data: SecretRow,
30 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
31 ) -> Result<StorageChangeEvent> {
32 self.guard_authenticated(Internal)?;
33
34 let summary = if let Some(folder_id) = &options.folder {
35 self.find(|f| f.id() == folder_id)
36 .cloned()
37 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?
38 } else {
39 self.current_folder().ok_or(Error::NoOpenVault)?
40 };
41
42 #[cfg(feature = "search")]
43 let index_doc = if let Some(index) = self.search_index() {
44 let search = index.search();
45 let index = search.read().await;
46 Some(index.prepare(
47 summary.id(),
48 secret_data.id(),
49 secret_data.meta(),
50 secret_data.secret(),
51 ))
52 } else {
53 None
54 };
55
56 let event = {
57 let folder = self
58 .folders_mut()
59 .get_mut(summary.id())
60 .ok_or(StorageError::FolderNotFound(*summary.id()))?;
61 folder.create_secret(&secret_data).await?
62 };
63
64 #[cfg(feature = "files")]
65 let file_events = {
66 let (file_events, write_update) = self
67 .external_file_manager_mut()
68 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
69 .create_files(
70 &summary,
71 secret_data,
72 &mut options.file_progress,
73 )
74 .await?;
75
76 if let Some((id, secret_data)) = write_update {
77 self.write_secret(
79 &summary,
80 &id,
81 secret_data,
82 false,
83 Internal,
84 )
85 .await?;
86 }
87
88 file_events
89 };
90
91 let result = StorageChangeEvent {
92 event,
93 #[cfg(feature = "files")]
94 file_events,
95 };
96
97 #[cfg(feature = "files")]
98 self.external_file_manager_mut()
99 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
100 .append_file_mutation_events(&result.file_events)
101 .await?;
102
103 #[cfg(feature = "search")]
104 if let (Some(index), Some(index_doc)) =
105 (self.search_index(), index_doc)
106 {
107 let search = index.search();
108 let mut index = search.write().await;
109 index.commit(index_doc)
110 }
111
112 Ok(result)
113 }
114
115 async fn raw_secret(
116 &self,
117 folder_id: &VaultId,
118 secret_id: &SecretId,
119 ) -> Result<Option<(VaultCommit, ReadEvent)>> {
120 self.guard_authenticated(Internal)?;
121
122 let folder = self
123 .folders()
124 .get(folder_id)
125 .ok_or(StorageError::FolderNotFound(*folder_id))?;
126 Ok(folder.raw_secret(secret_id).await?)
127 }
128
129 async fn read_secret(
130 &self,
131 id: &SecretId,
132 options: &AccessOptions,
133 ) -> Result<(Summary, SecretMeta, Secret, ReadEvent)> {
134 self.guard_authenticated(Internal)?;
135
136 let summary = if let Some(folder_id) = &options.folder {
137 self.find(|f| f.id() == folder_id)
138 .cloned()
139 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?
140 } else {
141 self.current_folder().ok_or(Error::NoOpenVault)?
142 };
143
144 let folder = self
145 .folders()
146 .get(summary.id())
147 .ok_or(StorageError::FolderNotFound(*summary.id()))?;
148 let result = folder
149 .read_secret(id)
150 .await?
151 .ok_or(Error::SecretNotFound(*id))?;
152 Ok((summary, result.0, result.1, result.2))
153 }
154
155 async fn update_secret(
156 &mut self,
157 secret_id: &SecretId,
158 meta: SecretMeta,
159 secret: Option<Secret>,
160 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
161 ) -> Result<StorageChangeEvent> {
162 self.guard_authenticated(Internal)?;
163
164 let (folder, old_meta, old_secret, _) =
165 self.read_secret(secret_id, &options).await?;
166 let old_secret_data =
167 SecretRow::new(*secret_id, old_meta, old_secret);
168
169 let secret_data = if let Some(secret) = secret {
170 SecretRow::new(*secret_id, meta, secret)
171 } else {
172 let mut secret_data = old_secret_data.clone();
173 *secret_data.meta_mut() = meta;
174 secret_data
175 };
176
177 let event = self
178 .write_secret(
179 &folder,
180 secret_id,
181 secret_data.clone(),
182 true,
183 Internal,
184 )
185 .await?;
186
187 #[cfg(feature = "files")]
189 let file_events = {
190 let (file_events, write_update) = self
192 .external_file_manager_mut()
193 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
194 .update_files(
195 &folder,
196 &folder,
197 &old_secret_data,
198 secret_data,
199 &mut options.file_progress,
200 )
201 .await?;
202
203 if let Some((id, secret_data)) = write_update {
204 self.write_secret(&folder, &id, secret_data, false, Internal)
206 .await?;
207 }
208
209 file_events
210 };
211
212 let result = StorageChangeEvent {
213 event,
214 #[cfg(feature = "files")]
215 file_events,
216 };
217
218 #[cfg(feature = "files")]
219 self.external_file_manager_mut()
220 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
221 .append_file_mutation_events(&result.file_events)
222 .await?;
223
224 Ok(result)
225 }
226
227 async fn write_secret(
228 &mut self,
229 folder: &Summary,
230 id: &SecretId,
231 mut secret_data: SecretRow,
232 #[allow(unused_variables)] is_update: bool,
233 _: Internal,
234 ) -> Result<WriteEvent> {
235 secret_data.meta_mut().touch();
238
239 #[cfg(feature = "search")]
240 let index_doc = if let Some(index) = self.search_index() {
241 let search = index.search();
242 let mut index = search.write().await;
243
244 if is_update {
245 index.remove(folder.id(), id);
250 }
251
252 Some(index.prepare(
253 folder.id(),
254 id,
255 secret_data.meta(),
256 secret_data.secret(),
257 ))
258 } else {
259 None
260 };
261
262 let event = {
263 let folder = self
264 .folders_mut()
265 .get_mut(folder.id())
266 .ok_or(StorageError::FolderNotFound(*folder.id()))?;
267 let (_, meta, secret) = secret_data.into();
268 folder
269 .update_secret(id, meta, secret)
270 .await?
271 .ok_or(Error::SecretNotFound(*id))?
272 };
273
274 #[cfg(feature = "search")]
275 if let (Some(index), Some(index_doc)) =
276 (self.search_index(), index_doc)
277 {
278 let search = index.search();
279 let mut index = search.write().await;
280 index.commit(index_doc)
281 }
282
283 Ok(event)
284 }
285
286 async fn delete_secret(
287 &mut self,
288 secret_id: &SecretId,
289 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
290 ) -> Result<StorageChangeEvent> {
291 self.guard_authenticated(Internal)?;
292
293 #[cfg(feature = "files")]
294 let (folder, secret_data) = {
295 let (folder, meta, secret, _) =
296 self.read_secret(secret_id, &options).await?;
297 (folder, SecretRow::new(*secret_id, meta, secret))
298 };
299
300 let event = self.remove_secret(secret_id, &options).await?;
301
302 let result = StorageChangeEvent {
303 event,
304 #[cfg(feature = "files")]
307 file_events: {
308 self.external_file_manager_mut()
309 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
310 .delete_files(
311 &folder,
312 &secret_data,
313 None,
314 &mut options.file_progress,
315 )
316 .await?
317 },
318 };
319
320 #[cfg(feature = "files")]
321 self.external_file_manager_mut()
322 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
323 .append_file_mutation_events(&result.file_events)
324 .await?;
325
326 Ok(result)
327 }
328
329 async fn remove_secret(
330 &mut self,
331 id: &SecretId,
332 options: &AccessOptions,
333 ) -> Result<WriteEvent> {
334 self.guard_authenticated(Internal)?;
335
336 let summary = if let Some(folder_id) = &options.folder {
337 self.find(|f| f.id() == folder_id)
338 .cloned()
339 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?
340 } else {
341 self.current_folder().ok_or(Error::NoOpenVault)?
342 };
343
344 let event = {
345 let folder = self
346 .folders_mut()
347 .get_mut(summary.id())
348 .ok_or(StorageError::FolderNotFound(*summary.id()))?;
349 folder
350 .delete_secret(id)
351 .await?
352 .ok_or(Error::SecretNotFound(*id))?
353 };
354
355 #[cfg(feature = "search")]
356 if let Some(index) = self.search_index() {
357 let search = index.search();
358 let mut writer = search.write().await;
359 writer.remove(summary.id(), id);
360 }
361
362 Ok(event)
363 }
364}