1use crate::{
3 AccessOptions, AccountPack, Error, NewFolderOptions, Result,
4 StorageChangeEvent,
5};
6use async_trait::async_trait;
7use futures::{pin_mut, StreamExt};
8use indexmap::IndexSet;
9use sos_backend::{
10 compact::compact_folder, extract_vault, BackendTarget, DeviceEventLog,
11 Folder, FolderEventLog,
12};
13use sos_core::{
14 commit::{CommitHash, CommitState},
15 crypto::AccessKey,
16 decode,
17 device::{DevicePublicKey, TrustedDevice},
18 encode,
19 events::{
20 patch::FolderPatch, AccountEvent, DeviceEvent, Event, EventKind,
21 EventLog, EventRecord, ReadEvent, WriteEvent,
22 },
23 AccountId, AuthenticationError, FolderRef, Paths, SecretId, StorageError,
24 UtcDateTime, VaultCommit, VaultFlags, VaultId,
25};
26use sos_login::{DelegatedAccess, FolderKeys, Identity};
27use sos_password::diceware::generate_passphrase;
28use sos_reducers::{DeviceReducer, FolderReducer};
29use sos_sync::{CreateSet, StorageEventLogs};
30use sos_vault::{
31 secret::{Secret, SecretMeta, SecretRow},
32 BuilderCredentials, ChangePassword, SecretAccess, Summary, Vault,
33 VaultBuilder,
34};
35use std::{collections::HashMap, sync::Arc};
36use tokio::sync::RwLock;
37
38#[cfg(feature = "search")]
39use sos_search::{AccountSearch, DocumentCount};
40
41#[cfg(feature = "audit")]
42use {
43 sos_audit::{AuditData, AuditEvent},
44 sos_backend::audit::append_audit_events,
45};
46
47#[cfg(feature = "files")]
48use {crate::files::ExternalFileManager, sos_backend::FileEventLog};
49
50pub(crate) mod private {
51 #[derive(Copy, Clone)]
53 pub struct Internal;
54}
55
56use private::Internal;
57
58pub trait ClientBaseStorage {
60 fn account_id(&self) -> &AccountId;
62
63 fn authenticated_user(&self) -> Option<&Identity>;
65
66 fn authenticated_user_mut(&mut self) -> Option<&mut Identity>;
68
69 fn is_authenticated(&self) -> bool {
71 self.authenticated_user().is_some()
72 }
73
74 fn paths(&self) -> Arc<Paths>;
76
77 fn backend_target(&self) -> &BackendTarget;
79
80 #[doc(hidden)]
82 fn set_authenticated_user(&mut self, user: Option<Identity>, _: Internal);
83
84 #[doc(hidden)]
85 fn guard_authenticated(&self, _: Internal) -> Result<()> {
86 if self.authenticated_user().is_none() {
87 return Err(AuthenticationError::NotAuthenticated.into());
89 }
90 Ok(())
91 }
92}
93
94#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
96#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
97pub trait ClientDeviceStorage:
98 StorageEventLogs<Error = Error> + ClientBaseStorage
99{
100 fn devices(&self) -> &IndexSet<TrustedDevice>;
102
103 #[doc(hidden)]
105 fn set_devices(&mut self, devices: IndexSet<TrustedDevice>, _: Internal);
106
107 fn list_trusted_devices(&self) -> Vec<&TrustedDevice>;
109
110 async fn patch_devices_unchecked(
112 &mut self,
113 events: &[DeviceEvent],
114 ) -> Result<()> {
115 self.guard_authenticated(Internal)?;
116
117 let device_log = self.device_log().await?;
119 let mut event_log = device_log.write().await;
120 event_log.apply(events).await?;
121
122 let reducer = DeviceReducer::new(&*event_log);
124 let devices = reducer.reduce().await?;
125 self.set_devices(devices, Internal);
126
127 #[cfg(feature = "audit")]
128 {
129 let audit_events = events
130 .iter()
131 .filter_map(|event| match event {
132 DeviceEvent::Trust(device) => Some(AuditEvent::new(
133 Default::default(),
134 EventKind::TrustDevice,
135 *self.account_id(),
136 Some(AuditData::Device(*device.public_key())),
137 )),
138 _ => None,
139 })
140 .collect::<Vec<_>>();
141 if !audit_events.is_empty() {
142 append_audit_events(audit_events.as_slice()).await?;
143 }
144 }
145
146 Ok(())
147 }
148
149 async fn revoke_device(
151 &mut self,
152 public_key: &DevicePublicKey,
153 ) -> Result<()> {
154 let device =
155 self.devices().iter().find(|d| d.public_key() == public_key);
156 if device.is_some() {
157 let event = DeviceEvent::Revoke(*public_key);
158
159 let device_log = self.device_log().await?;
160 let mut writer = device_log.write().await;
161 writer.apply(&[event]).await?;
162
163 let reducer = DeviceReducer::new(&*writer);
164 self.set_devices(reducer.reduce().await?, Internal);
165 }
166
167 Ok(())
168 }
169}
170
171#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
173#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
174pub trait ClientVaultStorage {
175 #[doc(hidden)]
177 async fn write_vault(
178 &self,
179 vault: &Vault,
180 _: Internal,
181 ) -> Result<Vec<u8>>;
182
183 #[doc(hidden)]
185 async fn write_login_vault(
186 &self,
187 vault: &Vault,
188 _: Internal,
189 ) -> Result<Vec<u8>>;
190
191 #[doc(hidden)]
193 async fn remove_vault(
194 &self,
195 folder_id: &VaultId,
196 _: Internal,
197 ) -> Result<()>;
198
199 #[doc(hidden)]
201 async fn read_vaults(&self, _: Internal) -> Result<Vec<Summary>>;
202
203 #[doc(hidden)]
206 fn summaries(&self, _: Internal) -> &Vec<Summary>;
207
208 #[doc(hidden)]
211 fn summaries_mut(&mut self, _: Internal) -> &mut Vec<Summary>;
212
213 #[doc(hidden)]
215 fn add_summary(&mut self, summary: Summary, token: Internal) {
216 let summaries = self.summaries_mut(token);
217 summaries.push(summary);
218 summaries.sort();
219 }
220
221 #[doc(hidden)]
223 fn remove_summary(&mut self, folder_id: &VaultId, token: Internal) {
224 if let Some(position) = self
225 .summaries(token)
226 .iter()
227 .position(|s| s.id() == folder_id)
228 {
229 self.summaries_mut(token).remove(position);
230 self.summaries_mut(token).sort();
231 }
232 }
233}
234
235#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
237#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
238pub trait ClientFolderStorage:
239 StorageEventLogs<Error = Error> + ClientBaseStorage + ClientVaultStorage
240{
241 fn folders(&self) -> &HashMap<VaultId, Folder>;
243
244 fn folders_mut(&mut self) -> &mut HashMap<VaultId, Folder>;
246
247 #[doc(hidden)]
249 async fn new_folder(&self, vault: &Vault, _: Internal) -> Result<Folder>;
250
251 async fn read_vault(&self, id: &VaultId) -> Result<Vault>;
253
254 async fn read_login_vault(&self) -> Result<Vault>;
256
257 async fn read_device_vault(&self) -> Result<Option<Vault>> {
259 Ok(self
260 .backend_target()
261 .read_device_vault(self.account_id())
262 .await?)
263 }
264
265 fn list_folders(&self) -> &[Summary] {
267 self.summaries(Internal).as_slice()
268 }
269
270 fn current_folder(&self) -> Option<Summary>;
272
273 fn find_folder(&self, vault: &FolderRef) -> Option<&Summary> {
275 match vault {
276 FolderRef::Name(name) => {
277 self.summaries(Internal).iter().find(|s| s.name() == name)
278 }
279 FolderRef::Id(id) => {
280 self.summaries(Internal).iter().find(|s| s.id() == id)
281 }
282 }
283 }
284
285 fn find<F>(&self, predicate: F) -> Option<&Summary>
287 where
288 F: FnMut(&&Summary) -> bool,
289 {
290 self.summaries(Internal).iter().find(predicate)
291 }
292
293 #[doc(hidden)]
301 async fn initialize_folder(
302 &mut self,
303 records: Vec<EventRecord>,
305 _: Internal,
306 ) -> Result<(Folder, Vault)> {
307 let vault = {
309 let vault = extract_vault(records.as_slice())
310 .await?
311 .ok_or(Error::NoVaultEvent)?;
312
313 let folder = self.new_folder(&vault, Internal).await?;
314 let event_log = folder.event_log();
315 let mut event_log = event_log.write().await;
316 event_log.clear().await?;
317 event_log.apply_records(records).await?;
318
319 let vault = FolderReducer::new()
320 .reduce(&*event_log)
321 .await?
322 .build(true)
323 .await?;
324
325 self.write_vault(&vault, Internal).await?;
326
327 vault
328 };
329
330 let folder = self.new_folder(&vault, Internal).await?;
338 let event_log = folder.event_log();
339 let mut event_log = event_log.write().await;
340 event_log.load_tree().await?;
341
342 Ok((folder, vault))
343 }
344
345 #[doc(hidden)]
347 async fn create_folder_entry(
348 &mut self,
349 vault: Vault,
350 reset_events: bool,
351 creation_time: Option<&UtcDateTime>,
352 _: Internal,
353 ) -> Result<()> {
354 let folder_id = *vault.id();
355 let mut folder = self.new_folder(&vault, Internal).await?;
356
357 if reset_events {
362 let (_, events) = FolderReducer::split::<Error>(vault).await?;
363 let mut records = Vec::with_capacity(events.len());
364 for event in events.iter() {
365 records.push(EventRecord::encode_event(event).await?);
366 }
367 if let (Some(creation_time), Some(event)) =
368 (creation_time, records.get_mut(0))
369 {
370 event.set_time(creation_time.to_owned());
371 }
372
373 folder.clear().await?;
376 folder.apply_records(records).await?;
377 }
378
379 self.folders_mut().insert(folder_id, folder);
380
381 Ok(())
382 }
383
384 #[doc(hidden)]
387 async fn load_caches(
388 &mut self,
389 folders: &[Summary],
390 _: Internal,
391 ) -> Result<()> {
392 for folder in folders {
393 let folder_id = folder.id();
395 if self.folders().get(folder_id).is_none() {
396 let folder = Folder::new(
397 self.backend_target().clone(),
398 self.account_id(),
399 folder.id(),
400 )
401 .await?;
402 self.folders_mut().insert(*folder_id, folder);
403 }
404 }
405 Ok(())
406 }
407
408 #[doc(hidden)]
410 fn remove_folder_entry(
411 &mut self,
412 folder_id: &VaultId,
413 _: Internal,
414 ) -> Result<()> {
415 let current_id = self.current_folder().map(|c| *c.id());
416
417 if let Some(id) = ¤t_id {
420 if id == folder_id {
421 self.close_folder();
422 }
423 }
424
425 self.folders_mut().remove(folder_id);
427
428 self.remove_summary(folder_id, Internal);
430
431 Ok(())
432 }
433
434 async fn update_vault(
436 &mut self,
437 vault: &Vault,
438 events: Vec<WriteEvent>,
439 ) -> Result<Vec<u8>> {
440 self.guard_authenticated(Internal)?;
441
442 let buffer = self.write_vault(vault, Internal).await?;
443
444 let folder = self
446 .folders_mut()
447 .get_mut(vault.id())
448 .ok_or(StorageError::FolderNotFound(*vault.id()))?;
449 folder.clear().await?;
450 folder.apply(events.as_slice()).await?;
451
452 Ok(buffer)
453 }
454
455 #[doc(hidden)]
457 async fn reduce_event_log(
458 &mut self,
459 folder_id: &VaultId,
460 _: Internal,
461 ) -> Result<Vault> {
462 let event_log = self.folder_log(folder_id).await?;
463 let log_file = event_log.read().await;
464 Ok(FolderReducer::new()
465 .reduce(&*log_file)
466 .await?
467 .build(true)
468 .await?)
469 }
470
471 #[doc(hidden)]
478 async fn refresh_vault(
479 &mut self,
480 folder_id: &VaultId,
481 key: &AccessKey,
482 _: Internal,
483 ) -> Result<Vec<u8>> {
484 let vault = self.reduce_event_log(folder_id, Internal).await?;
485 let buffer = self.write_vault(&vault, Internal).await?;
486
487 if let Some(folder) = self.folders_mut().get_mut(folder_id) {
488 let access_point = folder.access_point();
489 let mut access_point = access_point.lock().await;
490
491 access_point.lock();
492 access_point.replace_vault(vault.clone(), false).await?;
493 access_point.unlock(key).await?;
494 }
495
496 Ok(buffer)
497 }
498
499 async fn load_folders(&mut self) -> Result<&[Summary]> {
502 let summaries = self.read_vaults(Internal).await?;
503 self.load_caches(&summaries, Internal).await?;
504 *self.summaries_mut(Internal) = summaries;
505 Ok(self.list_folders())
506 }
507
508 async fn remove_folder(&mut self, folder_id: &VaultId) -> Result<bool> {
510 self.guard_authenticated(Internal)?;
511
512 Ok(if self.find(|s| s.id() == folder_id).is_some() {
513 self.remove_folder_entry(folder_id, Internal)?;
514 true
515 } else {
516 false
517 })
518 }
519
520 fn open_folder(&self, folder_id: &VaultId) -> Result<ReadEvent>;
522
523 fn close_folder(&self);
525
526 async fn import_folder_patches(
530 &mut self,
531 patches: HashMap<VaultId, FolderPatch>,
532 ) -> Result<()> {
533 self.guard_authenticated(Internal)?;
534
535 for (folder_id, patch) in patches {
536 let records: Vec<EventRecord> = patch.into();
537 let (folder, vault) =
538 self.initialize_folder(records, Internal).await?;
539
540 {
541 let event_log = folder.event_log();
542 let event_log = event_log.read().await;
543 tracing::info!(
544 folder_id = %folder_id,
545 root = ?event_log.tree().root().map(|c| c.to_string()),
546 "import_folder_patch");
547 }
548
549 self.folders_mut().insert(folder_id, folder);
550 let summary = vault.summary().to_owned();
551 self.remove_summary(summary.id(), Internal);
552 self.add_summary(summary, Internal);
553 }
554 Ok(())
555 }
556
557 async fn compact_folder(
559 &mut self,
560 folder_id: &VaultId,
561 key: &AccessKey,
562 ) -> Result<AccountEvent> {
563 self.guard_authenticated(Internal)?;
564
565 {
566 let folder = self
567 .folders_mut()
568 .get_mut(folder_id)
569 .ok_or(StorageError::FolderNotFound(*folder_id))?;
570 let event_log = folder.event_log();
571 let mut log_file = event_log.write().await;
572
573 compact_folder(self.account_id(), folder_id, &mut *log_file)
574 .await?;
575 }
576
577 let buffer = self.refresh_vault(folder_id, key, Internal).await?;
579
580 let account_event = AccountEvent::CompactFolder(*folder_id, buffer);
581
582 let account_log = self.account_log().await?;
583 let mut account_log = account_log.write().await;
584 account_log.apply(&[account_event.clone()]).await?;
585
586 Ok(account_event)
587 }
588
589 async fn rename_folder(
591 &mut self,
592 folder_id: &VaultId,
593 name: impl AsRef<str> + Send,
594 ) -> Result<Event> {
595 self.guard_authenticated(Internal)?;
596
597 self.set_folder_name(folder_id, name.as_ref(), Internal)?;
599
600 let folder = self
601 .folders_mut()
602 .get_mut(folder_id)
603 .ok_or(StorageError::FolderNotFound(*folder_id))?;
604
605 folder.rename_folder(name.as_ref()).await?;
606
607 let account_event =
608 AccountEvent::RenameFolder(*folder_id, name.as_ref().to_owned());
609
610 let account_log = self.account_log().await?;
611 let mut account_log = account_log.write().await;
612 account_log.apply(&[account_event.clone()]).await?;
613
614 #[cfg(feature = "audit")]
615 {
616 let audit_event: AuditEvent =
617 (self.account_id(), &account_event).into();
618 append_audit_events(&[audit_event]).await?;
619 }
620
621 Ok(Event::Account(account_event))
622 }
623
624 async fn update_folder_flags(
626 &mut self,
627 folder_id: &VaultId,
628 flags: VaultFlags,
629 ) -> Result<Event> {
630 self.guard_authenticated(Internal)?;
631
632 self.set_folder_flags(folder_id, flags.clone(), Internal)?;
634
635 let folder = self
636 .folders_mut()
637 .get_mut(folder_id)
638 .ok_or(StorageError::FolderNotFound(*folder_id))?;
639
640 let event = folder.update_folder_flags(flags).await?;
641 let event = Event::Write(*folder_id, event);
642
643 #[cfg(feature = "audit")]
644 {
645 let audit_event: AuditEvent = (self.account_id(), &event).into();
646 append_audit_events(&[audit_event]).await?;
647 }
648
649 Ok(event)
650 }
651
652 #[doc(hidden)]
654 fn set_folder_name(
655 &mut self,
656 folder_id: &VaultId,
657 name: impl AsRef<str>,
658 _: Internal,
659 ) -> Result<()> {
660 if let Some(summary) = self
661 .summaries_mut(Internal)
662 .iter_mut()
663 .find(|f| f.id() == folder_id)
664 {
665 summary.set_name(name.as_ref().to_owned());
666 }
667 Ok(())
668 }
669
670 #[doc(hidden)]
672 fn set_folder_flags(
673 &mut self,
674 folder_id: &VaultId,
675 flags: VaultFlags,
676 _: Internal,
677 ) -> Result<()> {
678 if let Some(summary) = self
679 .summaries_mut(Internal)
680 .iter_mut()
681 .find(|f| f.id() == folder_id)
682 {
683 *summary.flags_mut() = flags;
684 }
685 Ok(())
686 }
687
688 async fn description(&self, folder_id: &VaultId) -> Result<String> {
690 self.guard_authenticated(Internal)?;
691
692 let folder = self
693 .folders()
694 .get(folder_id)
695 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
696 Ok(folder.description().await?)
697 }
698
699 async fn set_description(
701 &mut self,
702 folder_id: &VaultId,
703 description: impl AsRef<str> + Send,
704 ) -> Result<WriteEvent> {
705 self.guard_authenticated(Internal)?;
706
707 let folder = self
708 .folders_mut()
709 .get_mut(folder_id)
710 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
711 Ok(folder.set_description(description).await?)
712 }
713}
714
715#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
717#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
718pub trait ClientSecretStorage {
719 async fn create_secret(
721 &mut self,
722 secret_data: SecretRow,
723 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
724 ) -> Result<StorageChangeEvent>;
725
726 async fn raw_secret(
728 &self,
729 folder_id: &VaultId,
730 secret_id: &SecretId,
731 ) -> Result<Option<(VaultCommit, ReadEvent)>>;
732
733 async fn read_secret(
735 &self,
736 id: &SecretId,
737 options: &AccessOptions,
738 ) -> Result<(Summary, SecretMeta, Secret, ReadEvent)>;
739
740 async fn update_secret(
742 &mut self,
743 secret_id: &SecretId,
744 meta: SecretMeta,
745 secret: Option<Secret>,
746 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
747 ) -> Result<StorageChangeEvent>;
748
749 #[doc(hidden)]
756 async fn write_secret(
757 &mut self,
758 folder: &Summary,
759 id: &SecretId,
760 mut secret_data: SecretRow,
761 #[allow(unused_variables)] is_update: bool,
762 _: Internal,
763 ) -> Result<WriteEvent>;
764
765 async fn delete_secret(
767 &mut self,
768 secret_id: &SecretId,
769 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
770 ) -> Result<StorageChangeEvent>;
771
772 async fn remove_secret(
776 &mut self,
777 id: &SecretId,
778 options: &AccessOptions,
779 ) -> Result<WriteEvent>;
780}
781
782#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
784#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
785#[doc(hidden)]
786pub trait ClientEventLogStorage {
787 #[doc(hidden)]
789 async fn initialize_device_log(
790 &self,
791 device: TrustedDevice,
792 _: Internal,
793 ) -> Result<(DeviceEventLog, IndexSet<TrustedDevice>)>;
794
795 #[cfg(feature = "files")]
797 #[doc(hidden)]
798 async fn initialize_file_log(&self, _: Internal) -> Result<FileEventLog>;
799
800 #[doc(hidden)]
802 fn set_identity_log(
803 &mut self,
804 log: Arc<RwLock<FolderEventLog>>,
805 _: Internal,
806 );
807
808 #[doc(hidden)]
810 fn set_device_log(
811 &mut self,
812 log: Arc<RwLock<DeviceEventLog>>,
813 _: Internal,
814 );
815
816 #[cfg(feature = "files")]
818 #[doc(hidden)]
819 fn set_file_log(&mut self, log: Arc<RwLock<FileEventLog>>, _: Internal);
820}
821
822#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
824#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
825pub trait ClientAccountStorage:
826 StorageEventLogs<Error = Error>
827 + ClientBaseStorage
828 + ClientDeviceStorage
829 + ClientFolderStorage
830 + ClientSecretStorage
831 + ClientEventLogStorage
832{
833 async fn rename_account(&mut self, account_name: String) -> Result<()> {
835 let authenticated_user = self
836 .authenticated_user_mut()
837 .ok_or(AuthenticationError::NotAuthenticated)?;
838 authenticated_user.rename_account(account_name).await?;
839 Ok(())
840 }
841
842 async fn import_account(
851 &mut self,
852 account_data: &CreateSet,
853 ) -> Result<()>;
854
855 async fn list_secret_ids(
857 &self,
858 folder_id: &VaultId,
859 ) -> Result<Vec<SecretId>>;
860
861 async fn create_device_vault(
870 &mut self,
871 device_vault: &[u8],
872 ) -> Result<()>;
873
874 async fn delete_account(&self) -> Result<Event>;
876
877 async fn authenticate(
879 &mut self,
880 authenticated_user: Identity,
881 ) -> Result<()> {
882 let identity_log = authenticated_user.identity()?.event_log();
885 let device = authenticated_user
886 .identity()?
887 .devices()?
888 .current_device(None);
889 self.set_identity_log(identity_log, Internal);
890
891 let (device_log, devices) =
892 self.initialize_device_log(device, Internal).await?;
893 self.set_device_log(Arc::new(RwLock::new(device_log)), Internal);
894 self.set_devices(devices, Internal);
895
896 #[cfg(feature = "files")]
897 {
898 let file_log = self.initialize_file_log(Internal).await?;
899 let file_log = Arc::new(RwLock::new(file_log));
900 let file_password =
901 authenticated_user.find_file_encryption_password().await?;
902
903 self.set_external_file_manager(
904 Some(ExternalFileManager::new(
905 self.paths().clone(),
906 file_log.clone(),
907 file_password,
908 )),
909 Internal,
910 );
911 self.set_file_log(file_log, Internal);
912 }
913
914 #[cfg(feature = "search")]
915 {
916 self.set_search_index(Some(AccountSearch::new()), Internal);
917 }
918 self.set_authenticated_user(Some(authenticated_user), Internal);
919
920 Ok(())
921 }
922
923 async fn change_password(
929 &mut self,
930 vault: &Vault,
931 current_key: AccessKey,
932 new_key: AccessKey,
933 ) -> Result<()> {
934 self.guard_authenticated(Internal)?;
935
936 let folder_id = vault.id();
937 let (new_key, new_vault, event_log_events) =
938 ChangePassword::new(vault, current_key, new_key, None)
939 .build()
940 .await?;
941
942 let buffer = self.update_vault(&new_vault, event_log_events).await?;
943
944 let account_event =
945 AccountEvent::ChangeFolderPassword(*folder_id, buffer);
946
947 self.refresh_vault(vault.id(), &new_key, Internal).await?;
949
950 if let Some(folder) = self.folders_mut().get_mut(vault.id()) {
951 let access_point = folder.access_point();
952 let mut access_point = access_point.lock().await;
953 access_point.unlock(&new_key).await?;
954 }
955
956 self.authenticated_user_mut()
958 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
959 .save_folder_password(folder_id, new_key)
960 .await?;
961
962 let account_log = self.account_log().await?;
963 let mut account_log = account_log.write().await;
964 account_log.apply(&[account_event]).await?;
965
966 Ok(())
967 }
968
969 async fn sign_out(&mut self) -> Result<()> {
971 if let Some(authenticated) = self.authenticated_user_mut() {
972 tracing::debug!("client_storage::sign_out_identity");
973 authenticated.sign_out().await?;
975 }
976
977 #[cfg(feature = "search")]
978 {
979 tracing::debug!("client_storage::drop_search_index");
980 self.set_search_index(None, Internal);
981 }
982
983 #[cfg(feature = "files")]
984 {
985 tracing::debug!("client_storage::drop_external_file_manager");
986 self.set_external_file_manager(None, Internal);
987 }
988
989 tracing::debug!("client_storage::drop_authenticated_user");
990 self.set_authenticated_user(None, Internal);
991
992 Ok(())
993 }
994
995 #[doc(hidden)]
1005 async fn import_login_vault(
1006 &mut self,
1007 vault: Vault,
1008 ) -> Result<AccountEvent> {
1009 self.guard_authenticated(Internal)?;
1010
1011 let user = self
1012 .authenticated_user()
1013 .ok_or(AuthenticationError::NotAuthenticated)?;
1014
1015 vault
1016 .summary()
1017 .flags()
1018 .contains(VaultFlags::IDENTITY)
1019 .then_some(())
1020 .ok_or_else(|| sos_login::Error::NotIdentityFolder)?;
1021
1022 let buffer = self.write_login_vault(&vault, Internal).await?;
1024
1025 let identity = user.identity()?;
1027 let event_log = identity.event_log();
1028 let mut event_log = event_log.write().await;
1029 event_log.clear().await?;
1030
1031 let (_, events) = FolderReducer::split::<Error>(vault).await?;
1032 event_log.apply(events.as_slice()).await?;
1033
1034 Ok(AccountEvent::UpdateIdentity(buffer))
1035 }
1036
1037 async fn unlock(&mut self, keys: &FolderKeys) -> Result<()> {
1039 self.guard_authenticated(Internal)?;
1040
1041 for (id, folder) in self.folders_mut().iter_mut() {
1042 if let Some(key) = keys.find(id) {
1043 folder.unlock(key).await?;
1044 } else {
1045 tracing::error!(
1046 folder_id = %id,
1047 "unlock::no_folder_key",
1048 );
1049 }
1050 }
1051 Ok(())
1052 }
1053
1054 async fn lock(&mut self) {
1060 for (_, folder) in self.folders_mut().iter_mut() {
1061 folder.lock().await;
1062 }
1063 }
1064
1065 async fn unlock_folder(
1067 &mut self,
1068 folder_id: &VaultId,
1069 key: &AccessKey,
1070 ) -> Result<()> {
1071 self.guard_authenticated(Internal)?;
1072
1073 let folder = self
1074 .folders_mut()
1075 .get_mut(folder_id)
1076 .ok_or(StorageError::FolderNotFound(*folder_id))?;
1077 folder.unlock(key).await?;
1078 Ok(())
1079 }
1080
1081 async fn lock_folder(&mut self, id: &VaultId) -> Result<()> {
1087 let folder = self
1088 .folders_mut()
1089 .get_mut(id)
1090 .ok_or(StorageError::FolderNotFound(*id))?;
1091 folder.lock().await;
1092 Ok(())
1093 }
1094
1095 async fn create_account(
1101 &mut self,
1102 account: &AccountPack,
1103 ) -> Result<Vec<Event>> {
1104 let mut events = Vec::new();
1105
1106 let create_account = Event::CreateAccount(account.account_id.into());
1107
1108 #[cfg(feature = "audit")]
1112 {
1113 let audit_event: AuditEvent =
1114 (self.account_id(), &create_account).into();
1115 append_audit_events(&[audit_event]).await?;
1116 }
1117
1118 for folder in &account.folders {
1120 let buffer = encode(folder).await?;
1121 let (event, _) =
1122 self.import_folder(buffer, None, true, None).await?;
1123 events.push(event);
1124 }
1125
1126 events.insert(0, create_account);
1127
1128 Ok(events)
1129 }
1130
1131 #[doc(hidden)]
1133 async fn prepare_folder(
1134 &mut self,
1135 mut options: NewFolderOptions,
1136 _: Internal,
1137 ) -> Result<(Vec<u8>, AccessKey, Summary)> {
1138 let key = if let Some(key) = options.key.take() {
1139 key
1140 } else {
1141 let (passphrase, _) = generate_passphrase()?;
1142 AccessKey::Password(passphrase)
1143 };
1144
1145 let builder = VaultBuilder::new()
1146 .flags(options.flags.unwrap_or_default())
1147 .cipher(options.cipher.unwrap_or_default())
1148 .kdf(options.kdf.unwrap_or_default())
1149 .public_name(options.name);
1150
1151 let vault = match &key {
1152 AccessKey::Password(password) => {
1153 builder
1154 .build(BuilderCredentials::Password(
1155 password.clone(),
1156 None,
1157 ))
1158 .await?
1159 }
1160 AccessKey::Identity(id) => {
1161 builder
1162 .build(BuilderCredentials::Shared {
1163 owner: id,
1164 recipients: vec![],
1165 read_only: true,
1166 })
1167 .await?
1168 }
1169 };
1170
1171 let summary = vault.summary().clone();
1172 let buffer = self.write_vault(&vault, Internal).await?;
1173
1174 self.add_summary(summary.clone(), Internal);
1176
1177 self.create_folder_entry(vault, true, None, Internal)
1179 .await?;
1180
1181 self.unlock_folder(summary.id(), &key).await?;
1182
1183 Ok((buffer, key, summary))
1184 }
1185
1186 async fn create_folder(
1188 &mut self,
1189 options: NewFolderOptions,
1190 ) -> Result<(Vec<u8>, AccessKey, Summary, AccountEvent)> {
1191 self.guard_authenticated(Internal)?;
1192
1193 let (buf, key, summary) =
1194 self.prepare_folder(options, Internal).await?;
1195
1196 let account_event =
1197 AccountEvent::CreateFolder(*summary.id(), buf.clone());
1198 let account_log = self.account_log().await?;
1199 let mut account_log = account_log.write().await;
1200 account_log.apply(&[account_event.clone()]).await?;
1201
1202 self.authenticated_user_mut()
1204 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1205 .save_folder_password(summary.id(), key.clone())
1206 .await?;
1207
1208 #[cfg(feature = "audit")]
1209 {
1210 let audit_event: AuditEvent =
1211 (self.account_id(), &account_event).into();
1212 append_audit_events(&[audit_event]).await?;
1213 }
1214
1215 Ok((buf, key, summary, account_event))
1216 }
1217
1218 async fn delete_folder(
1220 &mut self,
1221 folder_id: &VaultId,
1222 apply_event: bool,
1223 ) -> Result<Vec<Event>> {
1224 self.guard_authenticated(Internal)?;
1225
1226 self.remove_vault(folder_id, Internal).await?;
1228
1229 self.remove_folder_entry(folder_id, Internal)?;
1231
1232 let mut events = Vec::new();
1233
1234 #[cfg(feature = "files")]
1235 {
1236 let mut file_events = self
1237 .external_file_manager_mut()
1238 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1239 .delete_folder_files(folder_id)
1240 .await?;
1241
1242 let file_log = self.file_log().await?;
1243 let mut writer = file_log.write().await;
1244 writer.apply(file_events.as_slice()).await?;
1245 for event in file_events.drain(..) {
1246 events.push(Event::File(event));
1247 }
1248 }
1249
1250 #[cfg(feature = "search")]
1252 if let Some(index) = self.search_index_mut() {
1253 index.remove_folder(folder_id).await;
1254 }
1255
1256 self.authenticated_user_mut()
1257 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1258 .remove_folder_password(folder_id)
1259 .await?;
1260
1261 let account_event = AccountEvent::DeleteFolder(*folder_id);
1262
1263 if apply_event {
1264 let account_log = self.account_log().await?;
1265 let mut account_log = account_log.write().await;
1266 account_log.apply(&[account_event.clone()]).await?;
1267 }
1268
1269 #[cfg(feature = "audit")]
1270 {
1271 let audit_event: AuditEvent =
1272 (self.account_id(), &account_event).into();
1273 append_audit_events(&[audit_event]).await?;
1274 }
1275
1276 events.insert(0, Event::Account(account_event));
1277
1278 Ok(events)
1279 }
1280
1281 async fn restore_folder(
1283 &mut self,
1284 records: Vec<EventRecord>,
1285 key: &AccessKey,
1286 ) -> Result<Summary> {
1287 self.guard_authenticated(Internal)?;
1288
1289 let (mut folder, vault) =
1290 self.initialize_folder(records, Internal).await?;
1291
1292 folder.unlock(key).await?;
1294 self.folders_mut().insert(*vault.id(), folder);
1295
1296 let summary = vault.summary().to_owned();
1297 self.add_summary(summary.clone(), Internal);
1298
1299 #[cfg(feature = "search")]
1300 if let Some(index) = self.search_index_mut() {
1301 index.add_vault(vault, key).await?;
1303 }
1304
1305 Ok(summary)
1306 }
1307
1308 #[doc(hidden)]
1310 async fn upsert_vault_buffer(
1311 &mut self,
1312 buffer: impl AsRef<[u8]> + Send,
1313 key: Option<&AccessKey>,
1314 creation_time: Option<&UtcDateTime>,
1315 _: Internal,
1316 ) -> Result<(bool, WriteEvent, Summary)> {
1317 let vault: Vault = decode(buffer.as_ref()).await?;
1318 let exists = self.find(|s| s.id() == vault.id()).is_some();
1319 let summary = vault.summary().clone();
1320
1321 #[cfg(feature = "search")]
1322 if exists {
1323 if let Some(index) = self.search_index_mut() {
1324 index.remove_folder(summary.id()).await;
1326 }
1327 }
1328
1329 self.write_vault(&vault, Internal).await?;
1330
1331 if !exists {
1332 self.add_summary(summary.clone(), Internal);
1334 } else {
1335 if let Some(existing) = self
1337 .summaries_mut(Internal)
1338 .iter_mut()
1339 .find(|s| s.id() == summary.id())
1340 {
1341 *existing = summary.clone();
1342 }
1343 }
1344
1345 #[cfg(feature = "search")]
1346 if let Some(key) = key {
1347 if let Some(index) = self.search_index_mut() {
1348 index.add_vault(vault.clone(), key).await?;
1350 }
1351 }
1352
1353 let event = vault.into_event().await?;
1354
1355 self.create_folder_entry(vault, true, creation_time, Internal)
1357 .await?;
1358
1359 if let Some(key) = key {
1361 self.unlock_folder(summary.id(), key).await?;
1362 }
1363
1364 Ok((exists, event, summary))
1365 }
1366
1367 async fn import_folder(
1378 &mut self,
1379 buffer: impl AsRef<[u8]> + Send,
1380 key: Option<&AccessKey>,
1381 apply_event: bool,
1382 creation_time: Option<&UtcDateTime>,
1383 ) -> Result<(Event, Summary)> {
1384 let (exists, write_event, summary) = self
1385 .upsert_vault_buffer(
1386 buffer.as_ref(),
1387 key,
1388 creation_time,
1389 Internal,
1390 )
1391 .await?;
1392
1393 let account_event = if exists {
1397 AccountEvent::UpdateFolder(
1398 *summary.id(),
1399 buffer.as_ref().to_owned(),
1400 )
1401 } else {
1403 AccountEvent::CreateFolder(
1404 *summary.id(),
1405 buffer.as_ref().to_owned(),
1406 )
1407 };
1408
1409 if apply_event {
1410 let account_log = self.account_log().await?;
1411 let mut account_log = account_log.write().await;
1412 account_log.apply(&[account_event.clone()]).await?;
1413 }
1414
1415 #[cfg(feature = "audit")]
1416 {
1417 let audit_event: AuditEvent =
1418 (self.account_id(), &account_event).into();
1419 append_audit_events(&[audit_event]).await?;
1420 }
1421
1422 Ok((Event::Folder(account_event, write_event), summary))
1423 }
1424
1425 async fn history(
1427 &self,
1428 folder_id: &VaultId,
1429 ) -> Result<Vec<(CommitHash, UtcDateTime, WriteEvent)>> {
1430 self.guard_authenticated(Internal)?;
1431
1432 let folder = self
1433 .folders()
1434 .get(folder_id)
1435 .ok_or(StorageError::FolderNotFound(*folder_id))?;
1436 let event_log = folder.event_log();
1437 let log_file = event_log.read().await;
1438 let mut records = Vec::new();
1439
1440 let stream = log_file.event_stream(false).await;
1441 pin_mut!(stream);
1442
1443 while let Some(result) = stream.next().await {
1444 let (record, event) = result?;
1445 let commit = *record.commit();
1446 let time = record.time().clone();
1447 records.push((commit, time, event));
1448 }
1449
1450 Ok(records)
1451 }
1452
1453 async fn identity_state(&self) -> Result<CommitState> {
1459 let identity_log = self.identity_log().await?;
1460 let reader = identity_log.read().await;
1461 Ok(reader.tree().commit_state()?)
1462 }
1463
1464 async fn commit_state(&self, folder_id: &VaultId) -> Result<CommitState> {
1472 let folder = self
1473 .folders()
1474 .get(folder_id)
1475 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
1476 let event_log = folder.event_log();
1477 let log_file = event_log.read().await;
1478 Ok(log_file.tree().commit_state()?)
1479 }
1480
1481 #[cfg(feature = "files")]
1483 fn external_file_manager(&self) -> Option<&ExternalFileManager>;
1484
1485 #[cfg(feature = "files")]
1487 fn external_file_manager_mut(
1488 &mut self,
1489 ) -> Option<&mut ExternalFileManager>;
1490
1491 #[cfg(feature = "files")]
1493 #[doc(hidden)]
1494 fn set_external_file_manager(
1495 &mut self,
1496 file_manager: Option<ExternalFileManager>,
1497 _: Internal,
1498 );
1499
1500 #[cfg(feature = "search")]
1502 fn search_index(&self) -> Option<&AccountSearch>;
1503
1504 #[cfg(feature = "search")]
1506 fn search_index_mut(&mut self) -> Option<&mut AccountSearch>;
1507
1508 #[cfg(feature = "search")]
1510 #[doc(hidden)]
1511 fn set_search_index(&mut self, user: Option<AccountSearch>, _: Internal);
1512
1513 #[cfg(feature = "search")]
1518 async fn initialize_search_index(
1519 &mut self,
1520 keys: &FolderKeys,
1521 ) -> Result<(DocumentCount, Vec<Summary>)> {
1522 self.guard_authenticated(Internal)?;
1523
1524 let summaries = {
1526 let summaries = self.list_folders();
1527 let mut archive: Option<VaultId> = None;
1528 for summary in summaries {
1529 if summary.flags().is_archive() {
1530 archive = Some(*summary.id());
1531 break;
1532 }
1533 }
1534 if let Some(index) = self.search_index() {
1535 let mut writer = index.search_index.write().await;
1536 writer.set_archive_id(archive);
1537 }
1538 summaries
1539 };
1540 let folders = summaries.to_vec();
1541 Ok((self.build_search_index(keys).await?, folders))
1542 }
1543
1544 #[cfg(feature = "search")]
1546 async fn build_search_index(
1547 &mut self,
1548 keys: &FolderKeys,
1549 ) -> Result<DocumentCount> {
1550 self.guard_authenticated(Internal)?;
1551
1552 use sos_core::AuthenticationError;
1553
1554 {
1555 let index = self
1556 .search_index()
1557 .ok_or_else(|| AuthenticationError::NotAuthenticated)?;
1558 let search_index = index.search();
1559 let mut writer = search_index.write().await;
1560
1561 writer.remove_all();
1563
1564 for (folder_id, key) in &keys.0 {
1565 if let Some(folder) = self.folders_mut().get_mut(folder_id) {
1566 let access_point = folder.access_point();
1567 let mut access_point = access_point.lock().await;
1568 access_point.unlock(key).await?;
1569 writer.add_folder(&*access_point).await?;
1570 }
1571 }
1572 }
1573
1574 let count = if let Some(index) = self.search_index() {
1575 index.document_count().await
1576 } else {
1577 Default::default()
1578 };
1579
1580 Ok(count)
1581 }
1582}