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(folder_id, &mut *log_file).await?;
574 }
575
576 let buffer = self.refresh_vault(folder_id, key, Internal).await?;
578
579 let account_event = AccountEvent::CompactFolder(*folder_id, buffer);
580
581 let account_log = self.account_log().await?;
582 let mut account_log = account_log.write().await;
583 account_log.apply(&[account_event.clone()]).await?;
584
585 Ok(account_event)
586 }
587
588 async fn rename_folder(
590 &mut self,
591 folder_id: &VaultId,
592 name: impl AsRef<str> + Send,
593 ) -> Result<Event> {
594 self.guard_authenticated(Internal)?;
595
596 self.set_folder_name(folder_id, name.as_ref(), Internal)?;
598
599 let folder = self
600 .folders_mut()
601 .get_mut(folder_id)
602 .ok_or(StorageError::FolderNotFound(*folder_id))?;
603
604 folder.rename_folder(name.as_ref()).await?;
605
606 let account_event =
607 AccountEvent::RenameFolder(*folder_id, name.as_ref().to_owned());
608
609 let account_log = self.account_log().await?;
610 let mut account_log = account_log.write().await;
611 account_log.apply(&[account_event.clone()]).await?;
612
613 #[cfg(feature = "audit")]
614 {
615 let audit_event: AuditEvent =
616 (self.account_id(), &account_event).into();
617 append_audit_events(&[audit_event]).await?;
618 }
619
620 Ok(Event::Account(account_event))
621 }
622
623 async fn update_folder_flags(
625 &mut self,
626 folder_id: &VaultId,
627 flags: VaultFlags,
628 ) -> Result<Event> {
629 self.guard_authenticated(Internal)?;
630
631 self.set_folder_flags(folder_id, flags.clone(), Internal)?;
633
634 let folder = self
635 .folders_mut()
636 .get_mut(folder_id)
637 .ok_or(StorageError::FolderNotFound(*folder_id))?;
638
639 let event = folder.update_folder_flags(flags).await?;
640 let event = Event::Write(*folder_id, event);
641
642 #[cfg(feature = "audit")]
643 {
644 let audit_event: AuditEvent = (self.account_id(), &event).into();
645 append_audit_events(&[audit_event]).await?;
646 }
647
648 Ok(event)
649 }
650
651 #[doc(hidden)]
653 fn set_folder_name(
654 &mut self,
655 folder_id: &VaultId,
656 name: impl AsRef<str>,
657 _: Internal,
658 ) -> Result<()> {
659 if let Some(summary) = self
660 .summaries_mut(Internal)
661 .iter_mut()
662 .find(|f| f.id() == folder_id)
663 {
664 summary.set_name(name.as_ref().to_owned());
665 }
666 Ok(())
667 }
668
669 #[doc(hidden)]
671 fn set_folder_flags(
672 &mut self,
673 folder_id: &VaultId,
674 flags: VaultFlags,
675 _: Internal,
676 ) -> Result<()> {
677 if let Some(summary) = self
678 .summaries_mut(Internal)
679 .iter_mut()
680 .find(|f| f.id() == folder_id)
681 {
682 *summary.flags_mut() = flags;
683 }
684 Ok(())
685 }
686
687 async fn description(&self, folder_id: &VaultId) -> Result<String> {
689 self.guard_authenticated(Internal)?;
690
691 let folder = self
692 .folders()
693 .get(folder_id)
694 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
695 Ok(folder.description().await?)
696 }
697
698 async fn set_description(
700 &mut self,
701 folder_id: &VaultId,
702 description: impl AsRef<str> + Send,
703 ) -> Result<WriteEvent> {
704 self.guard_authenticated(Internal)?;
705
706 let folder = self
707 .folders_mut()
708 .get_mut(folder_id)
709 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
710 Ok(folder.set_description(description).await?)
711 }
712}
713
714#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
716#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
717pub trait ClientSecretStorage {
718 async fn create_secret(
720 &mut self,
721 secret_data: SecretRow,
722 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
723 ) -> Result<StorageChangeEvent>;
724
725 async fn raw_secret(
727 &self,
728 folder_id: &VaultId,
729 secret_id: &SecretId,
730 ) -> Result<Option<(VaultCommit, ReadEvent)>>;
731
732 async fn read_secret(
734 &self,
735 id: &SecretId,
736 options: &AccessOptions,
737 ) -> Result<(Summary, SecretMeta, Secret, ReadEvent)>;
738
739 async fn update_secret(
741 &mut self,
742 secret_id: &SecretId,
743 meta: SecretMeta,
744 secret: Option<Secret>,
745 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
746 ) -> Result<StorageChangeEvent>;
747
748 #[doc(hidden)]
755 async fn write_secret(
756 &mut self,
757 folder: &Summary,
758 id: &SecretId,
759 mut secret_data: SecretRow,
760 #[allow(unused_variables)] is_update: bool,
761 _: Internal,
762 ) -> Result<WriteEvent>;
763
764 async fn delete_secret(
766 &mut self,
767 secret_id: &SecretId,
768 #[allow(unused_mut, unused_variables)] mut options: AccessOptions,
769 ) -> Result<StorageChangeEvent>;
770
771 async fn remove_secret(
775 &mut self,
776 id: &SecretId,
777 options: &AccessOptions,
778 ) -> Result<WriteEvent>;
779}
780
781#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
783#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
784#[doc(hidden)]
785pub trait ClientEventLogStorage {
786 #[doc(hidden)]
788 async fn initialize_device_log(
789 &self,
790 device: TrustedDevice,
791 _: Internal,
792 ) -> Result<(DeviceEventLog, IndexSet<TrustedDevice>)>;
793
794 #[cfg(feature = "files")]
796 #[doc(hidden)]
797 async fn initialize_file_log(&self, _: Internal) -> Result<FileEventLog>;
798
799 #[doc(hidden)]
801 fn set_identity_log(
802 &mut self,
803 log: Arc<RwLock<FolderEventLog>>,
804 _: Internal,
805 );
806
807 #[doc(hidden)]
809 fn set_device_log(
810 &mut self,
811 log: Arc<RwLock<DeviceEventLog>>,
812 _: Internal,
813 );
814
815 #[cfg(feature = "files")]
817 #[doc(hidden)]
818 fn set_file_log(&mut self, log: Arc<RwLock<FileEventLog>>, _: Internal);
819}
820
821#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
823#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
824pub trait ClientAccountStorage:
825 StorageEventLogs<Error = Error>
826 + ClientBaseStorage
827 + ClientDeviceStorage
828 + ClientFolderStorage
829 + ClientSecretStorage
830 + ClientEventLogStorage
831{
832 async fn rename_account(&mut self, account_name: String) -> Result<()> {
834 let authenticated_user = self
835 .authenticated_user_mut()
836 .ok_or(AuthenticationError::NotAuthenticated)?;
837 authenticated_user.rename_account(account_name).await?;
838 Ok(())
839 }
840
841 async fn import_account(
850 &mut self,
851 account_data: &CreateSet,
852 ) -> Result<()>;
853
854 async fn list_secret_ids(
856 &self,
857 folder_id: &VaultId,
858 ) -> Result<Vec<SecretId>>;
859
860 async fn create_device_vault(
869 &mut self,
870 device_vault: &[u8],
871 ) -> Result<()>;
872
873 async fn delete_account(&self) -> Result<Event>;
875
876 async fn authenticate(
878 &mut self,
879 authenticated_user: Identity,
880 ) -> Result<()> {
881 let identity_log = authenticated_user.identity()?.event_log();
884 let device = authenticated_user
885 .identity()?
886 .devices()?
887 .current_device(None);
888 self.set_identity_log(identity_log, Internal);
889
890 let (device_log, devices) =
891 self.initialize_device_log(device, Internal).await?;
892 self.set_device_log(Arc::new(RwLock::new(device_log)), Internal);
893 self.set_devices(devices, Internal);
894
895 #[cfg(feature = "files")]
896 {
897 let file_log = self.initialize_file_log(Internal).await?;
898 let file_log = Arc::new(RwLock::new(file_log));
899 let file_password =
900 authenticated_user.find_file_encryption_password().await?;
901
902 self.set_external_file_manager(
903 Some(ExternalFileManager::new(
904 self.paths().clone(),
905 file_log.clone(),
906 file_password,
907 )),
908 Internal,
909 );
910 self.set_file_log(file_log, Internal);
911 }
912
913 #[cfg(feature = "search")]
914 {
915 self.set_search_index(Some(AccountSearch::new()), Internal);
916 }
917 self.set_authenticated_user(Some(authenticated_user), Internal);
918
919 Ok(())
920 }
921
922 async fn change_password(
928 &mut self,
929 vault: &Vault,
930 current_key: AccessKey,
931 new_key: AccessKey,
932 ) -> Result<()> {
933 self.guard_authenticated(Internal)?;
934
935 let folder_id = vault.id();
936 let (new_key, new_vault, event_log_events) =
937 ChangePassword::new(vault, current_key, new_key, None)
938 .build()
939 .await?;
940
941 let buffer = self.update_vault(&new_vault, event_log_events).await?;
942
943 let account_event =
944 AccountEvent::ChangeFolderPassword(*folder_id, buffer);
945
946 self.refresh_vault(vault.id(), &new_key, Internal).await?;
948
949 if let Some(folder) = self.folders_mut().get_mut(vault.id()) {
950 let access_point = folder.access_point();
951 let mut access_point = access_point.lock().await;
952 access_point.unlock(&new_key).await?;
953 }
954
955 self.authenticated_user_mut()
957 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
958 .save_folder_password(folder_id, new_key)
959 .await?;
960
961 let account_log = self.account_log().await?;
962 let mut account_log = account_log.write().await;
963 account_log.apply(&[account_event]).await?;
964
965 Ok(())
966 }
967
968 async fn sign_out(&mut self) -> Result<()> {
970 if let Some(authenticated) = self.authenticated_user_mut() {
971 tracing::debug!("client_storage::sign_out_identity");
972 authenticated.sign_out().await?;
974 }
975
976 #[cfg(feature = "search")]
977 {
978 tracing::debug!("client_storage::drop_search_index");
979 self.set_search_index(None, Internal);
980 }
981
982 #[cfg(feature = "files")]
983 {
984 tracing::debug!("client_storage::drop_external_file_manager");
985 self.set_external_file_manager(None, Internal);
986 }
987
988 tracing::debug!("client_storage::drop_authenticated_user");
989 self.set_authenticated_user(None, Internal);
990
991 Ok(())
992 }
993
994 #[doc(hidden)]
1004 async fn import_login_vault(
1005 &mut self,
1006 vault: Vault,
1007 ) -> Result<AccountEvent> {
1008 self.guard_authenticated(Internal)?;
1009
1010 let user = self
1011 .authenticated_user()
1012 .ok_or(AuthenticationError::NotAuthenticated)?;
1013
1014 vault
1015 .summary()
1016 .flags()
1017 .contains(VaultFlags::IDENTITY)
1018 .then_some(())
1019 .ok_or_else(|| sos_login::Error::NotIdentityFolder)?;
1020
1021 let buffer = self.write_login_vault(&vault, Internal).await?;
1023
1024 let identity = user.identity()?;
1026 let event_log = identity.event_log();
1027 let mut event_log = event_log.write().await;
1028 event_log.clear().await?;
1029
1030 let (_, events) = FolderReducer::split::<Error>(vault).await?;
1031 event_log.apply(events.as_slice()).await?;
1032
1033 Ok(AccountEvent::UpdateIdentity(buffer))
1034 }
1035
1036 async fn unlock(&mut self, keys: &FolderKeys) -> Result<()> {
1038 self.guard_authenticated(Internal)?;
1039
1040 for (id, folder) in self.folders_mut().iter_mut() {
1041 if let Some(key) = keys.find(id) {
1042 folder.unlock(key).await?;
1043 } else {
1044 tracing::error!(
1045 folder_id = %id,
1046 "unlock::no_folder_key",
1047 );
1048 }
1049 }
1050 Ok(())
1051 }
1052
1053 async fn lock(&mut self) {
1059 for (_, folder) in self.folders_mut().iter_mut() {
1060 folder.lock().await;
1061 }
1062 }
1063
1064 async fn unlock_folder(
1066 &mut self,
1067 folder_id: &VaultId,
1068 key: &AccessKey,
1069 ) -> Result<()> {
1070 self.guard_authenticated(Internal)?;
1071
1072 let folder = self
1073 .folders_mut()
1074 .get_mut(folder_id)
1075 .ok_or(StorageError::FolderNotFound(*folder_id))?;
1076 folder.unlock(key).await?;
1077 Ok(())
1078 }
1079
1080 async fn lock_folder(&mut self, id: &VaultId) -> Result<()> {
1086 let folder = self
1087 .folders_mut()
1088 .get_mut(id)
1089 .ok_or(StorageError::FolderNotFound(*id))?;
1090 folder.lock().await;
1091 Ok(())
1092 }
1093
1094 async fn create_account(
1100 &mut self,
1101 account: &AccountPack,
1102 ) -> Result<Vec<Event>> {
1103 let mut events = Vec::new();
1104
1105 let create_account = Event::CreateAccount(account.account_id.into());
1106
1107 #[cfg(feature = "audit")]
1111 {
1112 let audit_event: AuditEvent =
1113 (self.account_id(), &create_account).into();
1114 append_audit_events(&[audit_event]).await?;
1115 }
1116
1117 for folder in &account.folders {
1119 let buffer = encode(folder).await?;
1120 let (event, _) =
1121 self.import_folder(buffer, None, true, None).await?;
1122 events.push(event);
1123 }
1124
1125 events.insert(0, create_account);
1126
1127 Ok(events)
1128 }
1129
1130 #[doc(hidden)]
1132 async fn prepare_folder(
1133 &mut self,
1134 mut options: NewFolderOptions,
1135 _: Internal,
1136 ) -> Result<(Vec<u8>, AccessKey, Summary)> {
1137 let key = if let Some(key) = options.key.take() {
1138 key
1139 } else {
1140 let (passphrase, _) = generate_passphrase()?;
1141 AccessKey::Password(passphrase)
1142 };
1143
1144 let builder = VaultBuilder::new()
1145 .flags(options.flags.unwrap_or_default())
1146 .cipher(options.cipher.unwrap_or_default())
1147 .kdf(options.kdf.unwrap_or_default())
1148 .public_name(options.name);
1149
1150 let vault = match &key {
1151 AccessKey::Password(password) => {
1152 builder
1153 .build(BuilderCredentials::Password(
1154 password.clone(),
1155 None,
1156 ))
1157 .await?
1158 }
1159 AccessKey::Identity(id) => {
1160 builder
1161 .build(BuilderCredentials::Shared {
1162 owner: id,
1163 recipients: vec![],
1164 read_only: true,
1165 })
1166 .await?
1167 }
1168 };
1169
1170 let summary = vault.summary().clone();
1171 let buffer = self.write_vault(&vault, Internal).await?;
1172
1173 self.add_summary(summary.clone(), Internal);
1175
1176 self.create_folder_entry(vault, true, None, Internal)
1178 .await?;
1179
1180 self.unlock_folder(summary.id(), &key).await?;
1181
1182 Ok((buffer, key, summary))
1183 }
1184
1185 async fn create_folder(
1187 &mut self,
1188 options: NewFolderOptions,
1189 ) -> Result<(Vec<u8>, AccessKey, Summary, AccountEvent)> {
1190 self.guard_authenticated(Internal)?;
1191
1192 let (buf, key, summary) =
1193 self.prepare_folder(options, Internal).await?;
1194
1195 let account_event =
1196 AccountEvent::CreateFolder(*summary.id(), buf.clone());
1197 let account_log = self.account_log().await?;
1198 let mut account_log = account_log.write().await;
1199 account_log.apply(&[account_event.clone()]).await?;
1200
1201 self.authenticated_user_mut()
1203 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1204 .save_folder_password(summary.id(), key.clone())
1205 .await?;
1206
1207 #[cfg(feature = "audit")]
1208 {
1209 let audit_event: AuditEvent =
1210 (self.account_id(), &account_event).into();
1211 append_audit_events(&[audit_event]).await?;
1212 }
1213
1214 Ok((buf, key, summary, account_event))
1215 }
1216
1217 async fn delete_folder(
1219 &mut self,
1220 folder_id: &VaultId,
1221 apply_event: bool,
1222 ) -> Result<Vec<Event>> {
1223 self.guard_authenticated(Internal)?;
1224
1225 self.remove_vault(folder_id, Internal).await?;
1227
1228 self.remove_folder_entry(folder_id, Internal)?;
1230
1231 let mut events = Vec::new();
1232
1233 #[cfg(feature = "files")]
1234 {
1235 let mut file_events = self
1236 .external_file_manager_mut()
1237 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1238 .delete_folder_files(folder_id)
1239 .await?;
1240
1241 let file_log = self.file_log().await?;
1242 let mut writer = file_log.write().await;
1243 writer.apply(file_events.as_slice()).await?;
1244 for event in file_events.drain(..) {
1245 events.push(Event::File(event));
1246 }
1247 }
1248
1249 #[cfg(feature = "search")]
1251 if let Some(index) = self.search_index_mut() {
1252 index.remove_folder(folder_id).await;
1253 }
1254
1255 self.authenticated_user_mut()
1256 .ok_or_else(|| AuthenticationError::NotAuthenticated)?
1257 .remove_folder_password(folder_id)
1258 .await?;
1259
1260 let account_event = AccountEvent::DeleteFolder(*folder_id);
1261
1262 if apply_event {
1263 let account_log = self.account_log().await?;
1264 let mut account_log = account_log.write().await;
1265 account_log.apply(&[account_event.clone()]).await?;
1266 }
1267
1268 #[cfg(feature = "audit")]
1269 {
1270 let audit_event: AuditEvent =
1271 (self.account_id(), &account_event).into();
1272 append_audit_events(&[audit_event]).await?;
1273 }
1274
1275 events.insert(0, Event::Account(account_event));
1276
1277 Ok(events)
1278 }
1279
1280 async fn restore_folder(
1282 &mut self,
1283 records: Vec<EventRecord>,
1284 key: &AccessKey,
1285 ) -> Result<Summary> {
1286 self.guard_authenticated(Internal)?;
1287
1288 let (mut folder, vault) =
1289 self.initialize_folder(records, Internal).await?;
1290
1291 folder.unlock(key).await?;
1293 self.folders_mut().insert(*vault.id(), folder);
1294
1295 let summary = vault.summary().to_owned();
1296 self.add_summary(summary.clone(), Internal);
1297
1298 #[cfg(feature = "search")]
1299 if let Some(index) = self.search_index_mut() {
1300 index.add_vault(vault, key).await?;
1302 }
1303
1304 Ok(summary)
1305 }
1306
1307 #[doc(hidden)]
1309 async fn upsert_vault_buffer(
1310 &mut self,
1311 buffer: impl AsRef<[u8]> + Send,
1312 key: Option<&AccessKey>,
1313 creation_time: Option<&UtcDateTime>,
1314 _: Internal,
1315 ) -> Result<(bool, WriteEvent, Summary)> {
1316 let vault: Vault = decode(buffer.as_ref()).await?;
1317 let exists = self.find(|s| s.id() == vault.id()).is_some();
1318 let summary = vault.summary().clone();
1319
1320 #[cfg(feature = "search")]
1321 if exists {
1322 if let Some(index) = self.search_index_mut() {
1323 index.remove_folder(summary.id()).await;
1325 }
1326 }
1327
1328 self.write_vault(&vault, Internal).await?;
1329
1330 if !exists {
1331 self.add_summary(summary.clone(), Internal);
1333 } else {
1334 if let Some(existing) = self
1336 .summaries_mut(Internal)
1337 .iter_mut()
1338 .find(|s| s.id() == summary.id())
1339 {
1340 *existing = summary.clone();
1341 }
1342 }
1343
1344 #[cfg(feature = "search")]
1345 if let Some(key) = key {
1346 if let Some(index) = self.search_index_mut() {
1347 index.add_vault(vault.clone(), key).await?;
1349 }
1350 }
1351
1352 let event = vault.into_event().await?;
1353
1354 self.create_folder_entry(vault, true, creation_time, Internal)
1356 .await?;
1357
1358 if let Some(key) = key {
1360 self.unlock_folder(summary.id(), key).await?;
1361 }
1362
1363 Ok((exists, event, summary))
1364 }
1365
1366 async fn import_folder(
1377 &mut self,
1378 buffer: impl AsRef<[u8]> + Send,
1379 key: Option<&AccessKey>,
1380 apply_event: bool,
1381 creation_time: Option<&UtcDateTime>,
1382 ) -> Result<(Event, Summary)> {
1383 let (exists, write_event, summary) = self
1384 .upsert_vault_buffer(
1385 buffer.as_ref(),
1386 key,
1387 creation_time,
1388 Internal,
1389 )
1390 .await?;
1391
1392 let account_event = if exists {
1396 AccountEvent::UpdateFolder(
1397 *summary.id(),
1398 buffer.as_ref().to_owned(),
1399 )
1400 } else {
1402 AccountEvent::CreateFolder(
1403 *summary.id(),
1404 buffer.as_ref().to_owned(),
1405 )
1406 };
1407
1408 if apply_event {
1409 let account_log = self.account_log().await?;
1410 let mut account_log = account_log.write().await;
1411 account_log.apply(&[account_event.clone()]).await?;
1412 }
1413
1414 #[cfg(feature = "audit")]
1415 {
1416 let audit_event: AuditEvent =
1417 (self.account_id(), &account_event).into();
1418 append_audit_events(&[audit_event]).await?;
1419 }
1420
1421 Ok((Event::Folder(account_event, write_event), summary))
1422 }
1423
1424 async fn history(
1426 &self,
1427 folder_id: &VaultId,
1428 ) -> Result<Vec<(CommitHash, UtcDateTime, WriteEvent)>> {
1429 self.guard_authenticated(Internal)?;
1430
1431 let folder = self
1432 .folders()
1433 .get(folder_id)
1434 .ok_or(StorageError::FolderNotFound(*folder_id))?;
1435 let event_log = folder.event_log();
1436 let log_file = event_log.read().await;
1437 let mut records = Vec::new();
1438
1439 let stream = log_file.event_stream(false).await;
1440 pin_mut!(stream);
1441
1442 while let Some(result) = stream.next().await {
1443 let (record, event) = result?;
1444 let commit = *record.commit();
1445 let time = record.time().clone();
1446 records.push((commit, time, event));
1447 }
1448
1449 Ok(records)
1450 }
1451
1452 async fn identity_state(&self) -> Result<CommitState> {
1458 let identity_log = self.identity_log().await?;
1459 let reader = identity_log.read().await;
1460 Ok(reader.tree().commit_state()?)
1461 }
1462
1463 async fn commit_state(&self, folder_id: &VaultId) -> Result<CommitState> {
1471 let folder = self
1472 .folders()
1473 .get(folder_id)
1474 .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
1475 let event_log = folder.event_log();
1476 let log_file = event_log.read().await;
1477 Ok(log_file.tree().commit_state()?)
1478 }
1479
1480 #[cfg(feature = "files")]
1482 fn external_file_manager(&self) -> Option<&ExternalFileManager>;
1483
1484 #[cfg(feature = "files")]
1486 fn external_file_manager_mut(
1487 &mut self,
1488 ) -> Option<&mut ExternalFileManager>;
1489
1490 #[cfg(feature = "files")]
1492 #[doc(hidden)]
1493 fn set_external_file_manager(
1494 &mut self,
1495 file_manager: Option<ExternalFileManager>,
1496 _: Internal,
1497 );
1498
1499 #[cfg(feature = "search")]
1501 fn search_index(&self) -> Option<&AccountSearch>;
1502
1503 #[cfg(feature = "search")]
1505 fn search_index_mut(&mut self) -> Option<&mut AccountSearch>;
1506
1507 #[cfg(feature = "search")]
1509 #[doc(hidden)]
1510 fn set_search_index(&mut self, user: Option<AccountSearch>, _: Internal);
1511
1512 #[cfg(feature = "search")]
1517 async fn initialize_search_index(
1518 &mut self,
1519 keys: &FolderKeys,
1520 ) -> Result<(DocumentCount, Vec<Summary>)> {
1521 self.guard_authenticated(Internal)?;
1522
1523 let summaries = {
1525 let summaries = self.list_folders();
1526 let mut archive: Option<VaultId> = None;
1527 for summary in summaries {
1528 if summary.flags().is_archive() {
1529 archive = Some(*summary.id());
1530 break;
1531 }
1532 }
1533 if let Some(index) = self.search_index() {
1534 let mut writer = index.search_index.write().await;
1535 writer.set_archive_id(archive);
1536 }
1537 summaries
1538 };
1539 let folders = summaries.to_vec();
1540 Ok((self.build_search_index(keys).await?, folders))
1541 }
1542
1543 #[cfg(feature = "search")]
1545 async fn build_search_index(
1546 &mut self,
1547 keys: &FolderKeys,
1548 ) -> Result<DocumentCount> {
1549 self.guard_authenticated(Internal)?;
1550
1551 use sos_core::AuthenticationError;
1552
1553 {
1554 let index = self
1555 .search_index()
1556 .ok_or_else(|| AuthenticationError::NotAuthenticated)?;
1557 let search_index = index.search();
1558 let mut writer = search_index.write().await;
1559
1560 writer.remove_all();
1562
1563 for (folder_id, key) in &keys.0 {
1564 if let Some(folder) = self.folders_mut().get_mut(folder_id) {
1565 let access_point = folder.access_point();
1566 let mut access_point = access_point.lock().await;
1567 access_point.unlock(key).await?;
1568 writer.add_folder(&*access_point).await?;
1569 }
1570 }
1571 }
1572
1573 let count = if let Some(index) = self.search_index() {
1574 index.document_count().await
1575 } else {
1576 Default::default()
1577 };
1578
1579 Ok(count)
1580 }
1581}