sos_net/account/
network_account.rs

1//! Network aware account.
2use crate::{Error, RemoteBridge, Result};
3use async_trait::async_trait;
4use secrecy::SecretString;
5use sha2::{Digest, Sha256};
6use sos_account::{
7    Account, AccountBuilder, AccountChange, AccountData, CipherComparison,
8    FolderChange, FolderCreate, FolderDelete, LocalAccount, SecretChange,
9    SecretDelete, SecretInsert, SecretMove,
10};
11use sos_backend::{BackendTarget, Folder, ServerOrigins};
12use sos_client_storage::{AccessOptions, NewFolderOptions};
13use sos_core::{
14    commit::{CommitHash, CommitState},
15    crypto::{AccessKey, Cipher, KeyDerivation},
16    device::{DevicePublicKey, TrustedDevice},
17    events::{
18        AccountEvent, DeviceEvent, EventLog, EventLogType, EventRecord,
19        ReadEvent, WriteEvent,
20    },
21    AccountId, AccountRef, AuthenticationError, FolderRef, Origin, Paths,
22    PublicIdentity, RemoteOrigins, SecretId, StorageError, UtcDateTime,
23    VaultCommit, VaultFlags, VaultId,
24};
25use sos_login::{
26    device::{DeviceManager, DeviceSigner},
27    DelegatedAccess,
28};
29use sos_protocol::{
30    is_offline, AccountSync, DiffRequest, RemoteResult, RemoteSync,
31    SyncClient, SyncOptions, SyncResult,
32};
33use sos_remote_sync::RemoteSyncHandler;
34use sos_sync::{CreateSet, StorageEventLogs, UpdateSet};
35use sos_vault::{
36    secret::{Secret, SecretMeta, SecretRow, SecretType},
37    Summary, Vault,
38};
39use std::{
40    collections::{HashMap, HashSet},
41    path::Path,
42    sync::Arc,
43};
44use tokio::sync::{Mutex, RwLock};
45
46#[cfg(feature = "clipboard")]
47use {
48    sos_account::{xclipboard::Clipboard, ClipboardCopyRequest},
49    sos_core::SecretPath,
50};
51
52#[cfg(feature = "search")]
53use sos_search::{
54    AccountStatistics, ArchiveFilter, Document, DocumentCount, DocumentView,
55    QueryFilter, SearchIndex,
56};
57
58use indexmap::IndexSet;
59
60#[cfg(feature = "contacts")]
61use sos_account::ContactImportProgress;
62
63#[cfg(feature = "migrate")]
64use sos_migrate::import::ImportTarget;
65
66#[cfg(feature = "listen")]
67use sos_protocol::network_client::WebSocketHandle;
68
69#[cfg(feature = "audit")]
70use {
71    sos_audit::{AuditData, AuditEvent},
72    sos_backend::audit::append_audit_events,
73    sos_core::events::EventKind,
74};
75
76/*
77#[cfg(feature = "security-report")]
78use crate::sdk::account::security_report::{
79    SecurityReport, SecurityReportOptions,
80};
81*/
82
83use super::remote::Remotes;
84
85#[cfg(feature = "files")]
86use {
87    crate::account::file_transfers::{
88        FileTransferSettings, FileTransfers, FileTransfersHandle,
89        InflightTransfers,
90    },
91    sos_external_files::FileMutationEvent,
92    sos_protocol::{network_client::HttpClient, transfer::FileOperation},
93};
94
95/// Options for network account creation.
96#[derive(Debug, Default)]
97pub struct NetworkAccountOptions {
98    /// Disable network traffic.
99    pub offline: bool,
100    /// File transfer settings.
101    #[cfg(feature = "files")]
102    pub file_transfer_settings: FileTransferSettings,
103}
104
105/// Account with networking capability.
106pub struct NetworkAccount {
107    /// Account identifier.
108    account_id: AccountId,
109
110    /// Paths for the account.
111    paths: Arc<Paths>,
112
113    /// Local account.
114    pub(super) account: Arc<Mutex<LocalAccount>>,
115
116    /// Remote targets for synchronization.
117    pub(super) remotes: Arc<RwLock<Remotes>>,
118
119    /// Server origins for this account.
120    server_origins: Option<ServerOrigins>,
121
122    /// Lock to prevent write to local storage
123    /// whilst a sync operation is in progress.
124    pub(super) sync_lock: Arc<Mutex<()>>,
125
126    /// Websocket change listeners.
127    #[cfg(feature = "listen")]
128    pub(super) listeners: Mutex<HashMap<Origin, WebSocketHandle>>,
129
130    /// Identifier for this client connection.
131    ///
132    /// When listening for changes use the same identifier
133    /// so the server can filter out broadcast messages
134    /// made by this client.
135    connection_id: Option<String>,
136
137    /// File transfer event loop.
138    #[cfg(feature = "files")]
139    file_transfers: Option<FileTransfers<HttpClient>>,
140
141    /// Handle to a file transfers event loop.
142    #[cfg(feature = "files")]
143    file_transfer_handle: Option<FileTransfersHandle>,
144
145    /// Disable networking.
146    pub(crate) offline: bool,
147
148    /// Options for the network account.
149    #[allow(dead_code)]
150    options: NetworkAccountOptions,
151}
152
153impl NetworkAccount {
154    async fn login(&mut self, key: &AccessKey) -> Result<Vec<Summary>> {
155        let folders = {
156            let mut account = self.account.lock().await;
157            let folders = account.sign_in(key).await?;
158            self.paths = account.paths();
159            self.account_id = *account.account_id();
160            folders
161        };
162
163        // Without an explicit connection id use the inferred
164        // connection identifier
165        if self.connection_id.is_none() {
166            self.connection_id = self.client_connection_id().await.ok();
167        }
168
169        let server_origins =
170            ServerOrigins::new(self.backend_target().await, &self.account_id);
171        let servers = server_origins.list_servers().await?;
172
173        // Initialize remote bridges for each server origin
174        if !servers.is_empty() {
175            let mut remotes: Remotes = Default::default();
176            for origin in servers {
177                let remote = self.remote_bridge(&origin).await?;
178                remotes.insert(origin, remote);
179            }
180            self.remotes = Arc::new(RwLock::new(remotes));
181        }
182
183        self.server_origins = Some(server_origins);
184        self.activate().await?;
185
186        Ok(folders)
187    }
188
189    /// Deactive this account by closing down long-running tasks.
190    ///
191    /// Does not sign out of the account so is similar to moving
192    /// this account to the background so the data is still accessible.
193    ///
194    /// This can be used when implementing quick account switching
195    /// to shutdown the websocket and file transfers.
196    ///
197    /// Server remotes are left intact so that making changes
198    /// will still sync with server(s).
199    pub async fn deactivate(&mut self) {
200        #[cfg(feature = "listen")]
201        {
202            tracing::debug!("net_sign_out::shutdown_websockets");
203            self.shutdown_websockets().await;
204        }
205
206        #[cfg(feature = "files")]
207        {
208            tracing::debug!("net_sign_out::stop_file_transfers");
209            self.stop_file_transfers().await;
210        }
211    }
212
213    /// Activate this account by resuming websocket connections
214    /// and file transfers.
215    pub async fn activate(&mut self) -> Result<()> {
216        #[cfg(feature = "files")]
217        {
218            let clients = {
219                let mut clients = Vec::new();
220                let remotes = self.remotes.read().await;
221                for (_, remote) in &*remotes {
222                    clients.push(remote.client().clone());
223                }
224                clients
225            };
226
227            let file_transfers = FileTransfers::new(
228                clients,
229                self.options.file_transfer_settings.clone(),
230            );
231            self.file_transfers = Some(file_transfers);
232            self.start_file_transfers().await?;
233        }
234
235        Ok(())
236    }
237
238    /// Set the connection identifier.
239    pub fn set_connection_id(&mut self, value: Option<String>) {
240        self.connection_id = value;
241    }
242
243    /// Connection identifier.
244    pub fn connection_id(&self) -> Option<&str> {
245        self.connection_id.as_ref().map(|x| x.as_str())
246    }
247
248    /// Connection identifier either explicitly set
249    /// or inferred by convention.
250    ///
251    /// The convention is to use an Sha256 hash of the path
252    /// to the documents directory for the account and when
253    /// the account is authenticated include the device signing
254    /// public key in the computed hash.
255    async fn client_connection_id(&self) -> Result<String> {
256        Ok(if let Some(conn_id) = &self.connection_id {
257            conn_id.to_owned()
258        } else {
259            let mut hasher = Sha256::new();
260            let docs_dir = self.paths.documents_dir();
261            let docs_path = docs_dir.to_string_lossy().into_owned();
262
263            if !self.is_authenticated().await {
264                hasher.update(docs_path.as_bytes());
265            } else {
266                {
267                    let device_signer = self.device_signer().await?;
268                    let device_public_key = device_signer.public_key();
269
270                    hasher.update(docs_path.as_bytes());
271                    hasher.update(device_public_key.as_ref());
272                }
273            }
274
275            let result = hasher.finalize();
276            hex::encode(&result)
277        })
278    }
279
280    /// Add a server.
281    ///
282    /// An initial sync is performed with the server and the result
283    /// includes a possible error encountered during the initial sync.
284    ///
285    /// If a server with the given origin already exists it is
286    /// overwritten.
287    pub async fn add_server(
288        &mut self,
289        origin: Origin,
290    ) -> Result<Option<RemoteResult<Error>>> {
291        let remote = self.remote_bridge(&origin).await?;
292
293        #[cfg(feature = "files")]
294        {
295            if let Some(file_transfers) = self.file_transfers.as_mut() {
296                file_transfers.add_client(remote.client().clone()).await;
297            };
298
299            if let Some(handle) = &self.file_transfer_handle {
300                self.proxy_remote_file_queue(handle, &remote).await;
301            }
302        }
303
304        {
305            let mut remotes = self.remotes.write().await;
306            remotes.insert(origin.clone(), remote);
307            self.server_origins
308                .as_mut()
309                .unwrap()
310                .add_server(origin.clone())
311                .await?;
312            tracing::debug!(url = %origin.url(), "server::added");
313        }
314
315        let mut sync_result = None;
316        if !is_offline() {
317            let remotes = self.remotes.read().await;
318            if let Some(remote) = remotes.get(&origin) {
319                let options = SyncOptions {
320                    origins: vec![origin.clone()],
321                    ..Default::default()
322                };
323
324                let res = remote.sync_with_options(&options).await;
325                if let Some(sync_error) = res.result.as_ref().err() {
326                    tracing::warn!(
327                        sync_error = ?sync_error,
328                        "server::initial_sync_failed");
329                }
330                sync_result = Some(res);
331            }
332        } else {
333            tracing::warn!(
334                "offline mode active, ignoring initial server sync"
335            );
336        }
337
338        Ok(sync_result)
339    }
340
341    /// Replace a server origin with updated origin information.
342    pub async fn replace_server(
343        &mut self,
344        old_origin: &Origin,
345        new_origin: Origin,
346    ) -> Result<bool> {
347        // Note that this works because Origin only includes
348        // the url for it's Hash implementation
349        let mut remotes = self.remotes.write().await;
350        if let Some(remote) = remotes.remove(&old_origin) {
351            remotes.insert(new_origin.clone(), remote);
352            self.server_origins
353                .as_mut()
354                .unwrap()
355                .replace_server(old_origin, new_origin)
356                .await?;
357            Ok(true)
358        } else {
359            Ok(false)
360        }
361    }
362
363    /// Remove a server.
364    pub async fn remove_server(
365        &mut self,
366        origin: &Origin,
367    ) -> Result<Option<RemoteBridge>> {
368        let remote = {
369            let mut remotes = self.remotes.write().await;
370            let remote = remotes.remove(origin);
371            #[allow(unused_variables)]
372            if let Some(remote) = &remote {
373                #[cfg(feature = "files")]
374                if let Some(file_transfers) = self.file_transfers.as_mut() {
375                    file_transfers.remove_client(remote.client()).await;
376                }
377                self.server_origins
378                    .as_mut()
379                    .unwrap()
380                    .remove_server(origin)
381                    .await?;
382            }
383            remote
384        };
385
386        tracing::debug!(url = %origin.url(), "server::removed");
387        Ok(remote)
388    }
389
390    /// Create a remote bridge between this account and the origin server.
391    async fn remote_bridge(&self, origin: &Origin) -> Result<RemoteBridge> {
392        let device = self.device_signer().await?;
393        let conn_id = if let Some(conn_id) = &self.connection_id {
394            conn_id.to_string()
395        } else {
396            self.client_connection_id().await?
397        };
398        let provider = RemoteBridge::new(
399            *self.account_id(),
400            Arc::clone(&self.account),
401            origin.clone(),
402            device.into(),
403            conn_id,
404        )?;
405        Ok(provider)
406    }
407
408    /// List the origin servers.
409    ///
410    /// Derived from the currently configuted in-memory remotes.
411    pub async fn servers(&self) -> HashSet<Origin> {
412        let remotes = self.remotes.read().await;
413        remotes.keys().cloned().collect()
414    }
415
416    /// Try to recover a folder from a remote origin; it is an
417    /// error if the folder exists in memory or on disc.
418    pub async fn recover_remote_folder(
419        &mut self,
420        origin: &Origin,
421        folder_id: &VaultId,
422    ) -> Result<Summary> {
423        let folders = self.list_folders().await?;
424        if folders.iter().find(|f| f.id() == folder_id).is_some() {
425            return Err(Error::FolderExists(*folder_id));
426        }
427
428        self.recover_remote_folder_unchecked(origin, folder_id)
429            .await
430    }
431
432    /// Try to recover a folder from a remote origin.
433    ///
434    /// If the folder already exists on disc it is overwritten.
435    async fn recover_remote_folder_unchecked(
436        &mut self,
437        origin: &Origin,
438        folder_id: &VaultId,
439    ) -> Result<Summary> {
440        let _ = self.sync_lock.lock().await;
441        let remote = self.remote_bridge(origin).await?;
442        let request = DiffRequest {
443            log_type: EventLogType::Folder(*folder_id),
444            from_hash: None,
445        };
446        let response = remote.client().diff(request).await?;
447        self.restore_folder(folder_id, response.patch).await
448    }
449
450    /// Spawn a task to handle file transfers.
451    #[cfg(feature = "files")]
452    async fn start_file_transfers(&mut self) -> Result<()> {
453        if !self.is_authenticated().await {
454            return Err(AuthenticationError::NotAuthenticated.into());
455        }
456
457        if self.offline {
458            tracing::warn!("offline mode active, ignoring file transfers");
459            return Ok(());
460        }
461
462        // Stop any existing transfers task
463        self.stop_file_transfers().await;
464
465        let paths = self.paths();
466        if let Some(file_transfers) = &mut self.file_transfers {
467            tracing::debug!("file_transfers::start");
468
469            let handle = file_transfers.run(paths);
470
471            {
472                // Proxy file transfer queue events from the
473                // remote bridges to the file transfer event loop
474                let remotes = self.remotes.read().await;
475                for (_, remote) in &*remotes {
476                    self.proxy_remote_file_queue(&handle, remote).await;
477                }
478            }
479
480            self.file_transfer_handle = Some(handle);
481        }
482
483        Ok(())
484    }
485
486    #[cfg(feature = "files")]
487    async fn proxy_remote_file_queue(
488        &self,
489        handle: &FileTransfersHandle,
490        remote: &RemoteBridge,
491    ) {
492        let mut rx = remote.file_transfer_queue.subscribe();
493        let tx = handle.queue_tx.clone();
494        tokio::task::spawn(async move {
495            while let Ok(event) = rx.recv().await {
496                let res = tx.send(event).await;
497                if let Err(error) = res {
498                    tracing::error!(error = ?error);
499                }
500            }
501            Ok::<_, Error>(())
502        });
503    }
504
505    /// Stop a file transfers task.
506    #[cfg(feature = "files")]
507    async fn stop_file_transfers(&mut self) {
508        if let Some(handle) = self.file_transfer_handle.take() {
509            handle.shutdown().await;
510        }
511    }
512}
513
514impl From<&NetworkAccount> for AccountRef {
515    fn from(value: &NetworkAccount) -> Self {
516        Self::Id(*value.account_id())
517    }
518}
519
520impl NetworkAccount {
521    /// Prepare an account for sign in.
522    ///
523    /// After preparing an account call `sign_in`
524    /// to authenticate a user.
525    pub async fn new_unauthenticated(
526        account_id: AccountId,
527        target: BackendTarget,
528        options: NetworkAccountOptions,
529    ) -> Result<Self> {
530        let account =
531            LocalAccount::new_unauthenticated(account_id, target).await?;
532
533        Ok(Self {
534            account_id,
535            paths: account.paths(),
536            account: Arc::new(Mutex::new(account)),
537            remotes: Arc::new(RwLock::new(Default::default())),
538            server_origins: None,
539            sync_lock: Arc::new(Mutex::new(())),
540            #[cfg(feature = "listen")]
541            listeners: Mutex::new(Default::default()),
542            connection_id: None,
543            #[cfg(feature = "files")]
544            file_transfers: None,
545            #[cfg(feature = "files")]
546            file_transfer_handle: None,
547            offline: options.offline,
548            options,
549        })
550    }
551
552    /// Create a new account with the given
553    /// name, passphrase and provider.
554    ///
555    /// Uses standard flags for the account builder for
556    /// more control of the created account use
557    /// `new_account_with_builder()`.
558    pub async fn new_account(
559        account_name: String,
560        passphrase: SecretString,
561        target: BackendTarget,
562        options: NetworkAccountOptions,
563    ) -> Result<Self> {
564        Self::new_account_with_builder(
565            account_name,
566            passphrase,
567            target,
568            options,
569            |builder| {
570                builder
571                    .save_passphrase(false)
572                    .create_archive(false)
573                    .create_authenticator(false)
574                    .create_contacts(false)
575                    .create_file_password(true)
576            },
577        )
578        .await
579    }
580
581    /// Create a new account with the given
582    /// name, passphrase and provider and modify the
583    /// account builder.
584    pub async fn new_account_with_builder(
585        account_name: String,
586        passphrase: SecretString,
587        target: BackendTarget,
588        options: NetworkAccountOptions,
589        builder: impl Fn(AccountBuilder) -> AccountBuilder + Send,
590    ) -> Result<Self> {
591        let account = LocalAccount::new_account_with_builder(
592            account_name,
593            passphrase.clone(),
594            target,
595            builder,
596        )
597        .await?;
598
599        let owner = Self {
600            account_id: *account.account_id(),
601            paths: account.paths(),
602            account: Arc::new(Mutex::new(account)),
603            remotes: Arc::new(RwLock::new(Default::default())),
604            server_origins: None,
605            sync_lock: Arc::new(Mutex::new(())),
606            #[cfg(feature = "listen")]
607            listeners: Mutex::new(Default::default()),
608            connection_id: None,
609            #[cfg(feature = "files")]
610            file_transfers: None,
611            #[cfg(feature = "files")]
612            file_transfer_handle: None,
613            offline: options.offline,
614            options,
615        };
616
617        Ok(owner)
618    }
619
620    /// Inflight file transfers.
621    #[cfg(feature = "files")]
622    pub fn inflight_transfers(&self) -> Result<Arc<InflightTransfers>> {
623        Ok(self
624            .file_transfers
625            .as_ref()
626            .map(|t| Arc::clone(&t.inflight))
627            .ok_or_else(|| AuthenticationError::NotAuthenticated)?)
628    }
629
630    /// Convert file mutation events into file transfer queue entries.
631    #[cfg(feature = "files")]
632    async fn queue_file_mutation_events(
633        &self,
634        events: &[FileMutationEvent],
635    ) -> Result<()> {
636        if let Some(handle) = &self.file_transfer_handle {
637            let mut items = Vec::with_capacity(events.len());
638            for event in events {
639                let item: FileOperation = event.into();
640                items.push(item);
641            }
642
643            handle.send(items).await;
644        }
645
646        Ok(())
647    }
648}
649
650#[async_trait]
651impl Account for NetworkAccount {
652    type Error = Error;
653    type NetworkResult = SyncResult<Self::Error>;
654
655    fn account_id(&self) -> &AccountId {
656        &self.account_id
657    }
658
659    fn paths(&self) -> Arc<Paths> {
660        Arc::clone(&self.paths)
661    }
662
663    async fn backend_target(&self) -> BackendTarget {
664        let account = self.account.lock().await;
665        account.backend_target().await
666    }
667
668    async fn folder(&self, folder_id: &VaultId) -> Result<Folder> {
669        let account = self.account.lock().await;
670        Ok(account.folder(folder_id).await?)
671    }
672
673    async fn is_authenticated(&self) -> bool {
674        let account = self.account.lock().await;
675        account.is_authenticated().await
676    }
677
678    async fn import_account_events(
679        &mut self,
680        events: CreateSet,
681    ) -> Result<()> {
682        let mut inner = self.account.lock().await;
683        Ok(inner.import_account_events(events).await?)
684    }
685
686    async fn new_device_vault(
687        &mut self,
688    ) -> Result<(DeviceSigner, DeviceManager)> {
689        let mut account = self.account.lock().await;
690        Ok(account.new_device_vault().await?)
691    }
692
693    async fn device_signer(&self) -> Result<DeviceSigner> {
694        let account = self.account.lock().await;
695        Ok(account.device_signer().await?)
696    }
697
698    async fn device_public_key(&self) -> Result<DevicePublicKey> {
699        let account = self.account.lock().await;
700        Ok(account.device_public_key().await?)
701    }
702
703    async fn patch_devices_unchecked(
704        &mut self,
705        events: &[DeviceEvent],
706    ) -> Result<()> {
707        let mut account = self.account.lock().await;
708        Ok(account.patch_devices_unchecked(events).await?)
709    }
710
711    async fn revoke_device(
712        &mut self,
713        device_key: &DevicePublicKey,
714    ) -> Result<()> {
715        let current_device = self.current_device().await?;
716        if current_device.public_key() == device_key {
717            return Err(Error::RevokeDeviceSelf);
718        }
719
720        // Update the local device event log
721        {
722            let mut account = self.account.lock().await;
723            account.revoke_device(device_key).await?;
724        }
725
726        #[cfg(feature = "audit")]
727        {
728            let audit_event = AuditEvent::new(
729                Default::default(),
730                EventKind::RevokeDevice,
731                *self.account_id(),
732                Some(AuditData::Device(*device_key)),
733            );
734            append_audit_events(&[audit_event]).await?;
735        }
736
737        // Send the device event logs to the remote servers
738        if let Some(e) = self.sync().await.first_error() {
739            tracing::error!(error = ?e);
740            return Err(Error::RevokeDeviceSync(Box::new(e)));
741        }
742
743        Ok(())
744    }
745
746    async fn current_device(&self) -> Result<TrustedDevice> {
747        let account = self.account.lock().await;
748        Ok(account.current_device().await?)
749    }
750
751    async fn trusted_devices(&self) -> Result<IndexSet<TrustedDevice>> {
752        let account = self.account.lock().await;
753        Ok(account.trusted_devices().await?)
754    }
755
756    async fn public_identity(&self) -> Result<PublicIdentity> {
757        let account = self.account.lock().await;
758        Ok(account.public_identity().await?)
759    }
760
761    async fn account_name(&self) -> Result<String> {
762        let account = self.account.lock().await;
763        Ok(account.account_name().await?)
764    }
765
766    async fn folder_description(
767        &mut self,
768        folder_id: &VaultId,
769    ) -> Result<String> {
770        let mut account = self.account.lock().await;
771        Ok(account.folder_description(folder_id).await?)
772    }
773
774    async fn set_folder_description(
775        &mut self,
776        folder_id: &VaultId,
777        description: impl AsRef<str> + Send + Sync,
778    ) -> Result<FolderChange<Self::NetworkResult>> {
779        let _ = self.sync_lock.lock().await;
780        let result = {
781            let mut account = self.account.lock().await;
782            account
783                .set_folder_description(folder_id, description)
784                .await?
785        };
786
787        let result = FolderChange {
788            event: result.event,
789            commit_state: result.commit_state,
790            sync_result: self.sync().await,
791        };
792
793        Ok(result)
794    }
795
796    async fn login_folder_summary(&self) -> Result<Summary> {
797        let account = self.account.lock().await;
798        Ok(account.login_folder_summary().await?)
799    }
800
801    async fn reload_login_folder(&mut self) -> Result<()> {
802        let mut account = self.account.lock().await;
803        Ok(account.reload_login_folder().await?)
804    }
805
806    async fn change_cipher(
807        &mut self,
808        account_key: &AccessKey,
809        cipher: &Cipher,
810        kdf: Option<KeyDerivation>,
811    ) -> Result<CipherComparison> {
812        let conversion = {
813            let mut account = self.account.lock().await;
814            // Update the local account data.
815            account.change_cipher(account_key, cipher, kdf).await?
816        };
817
818        let identity = if conversion.identity.is_some() {
819            let log = self.identity_log().await?;
820            let reader = log.read().await;
821            let diff = reader.diff_unchecked().await?;
822            Some(diff)
823        } else {
824            None
825        };
826
827        // Prepare event logs for the folders that
828        // were converted
829        let mut folders = HashMap::new();
830
831        for folder in &conversion.folders {
832            if folder.flags().is_sync_disabled() {
833                continue;
834            }
835            let event_log = self.folder_log(folder.id()).await?;
836            let log_file = event_log.read().await;
837            let diff = log_file.diff_unchecked().await?;
838            folders.insert(*folder.id(), diff);
839        }
840
841        // Force update the folders on remote servers
842        let sync_options: SyncOptions = Default::default();
843        let updates = UpdateSet {
844            identity,
845            folders,
846            ..Default::default()
847        };
848
849        let sync_result = self.force_update(updates, &sync_options).await;
850        if let Some(sync_error) = sync_result.first_error() {
851            return Err(Error::ForceUpdate(Box::new(sync_error)));
852        }
853
854        // In case we have pending updates to the account, device
855        // or file event logs
856        if let Some(sync_error) =
857            self.sync_with_options(&sync_options).await.first_error()
858        {
859            return Err(Error::ForceUpdate(Box::new(sync_error)));
860        }
861
862        Ok(conversion)
863    }
864
865    async fn change_account_password(
866        &mut self,
867        password: SecretString,
868    ) -> Result<()> {
869        {
870            let mut account = self.account.lock().await;
871            account.change_account_password(password).await?
872        }
873
874        let log = self.identity_log().await?;
875        let reader = log.read().await;
876        let identity = reader.diff_unchecked().await?;
877
878        // Force update the folders on remote servers
879        let sync_options: SyncOptions = Default::default();
880        let updates = UpdateSet {
881            identity: Some(identity),
882            ..Default::default()
883        };
884
885        let sync_result = self.force_update(updates, &sync_options).await;
886        if let Some(sync_error) = sync_result.first_error() {
887            return Err(Error::ForceUpdate(Box::new(sync_error)));
888        }
889
890        // In case we have pending updates to the account, device
891        // or file event logs
892        if let Some(sync_error) =
893            self.sync_with_options(&sync_options).await.first_error()
894        {
895            return Err(Error::ForceUpdate(Box::new(sync_error)));
896        }
897
898        Ok(())
899    }
900
901    async fn sign_in(&mut self, key: &AccessKey) -> Result<Vec<Summary>> {
902        self.login(key).await
903    }
904
905    async fn verify(&self, key: &AccessKey) -> bool {
906        let account = self.account.lock().await;
907        account.verify(key).await
908    }
909
910    async fn open_folder(&self, folder_id: &VaultId) -> Result<()> {
911        let account = self.account.lock().await;
912        Ok(account.open_folder(folder_id).await?)
913    }
914
915    async fn current_folder(&self) -> Result<Option<Summary>> {
916        let account = self.account.lock().await;
917        Ok(account.current_folder().await?)
918    }
919
920    async fn history(
921        &self,
922        folder_id: &VaultId,
923    ) -> Result<Vec<(CommitHash, UtcDateTime, WriteEvent)>> {
924        let account = self.account.lock().await;
925        Ok(account.history(folder_id).await?)
926    }
927
928    async fn sign_out(&mut self) -> Result<()> {
929        self.deactivate().await;
930        self.remotes = Default::default();
931        self.server_origins = None;
932
933        #[cfg(feature = "files")]
934        {
935            self.file_transfers.take();
936        }
937
938        let mut account = self.account.lock().await;
939        Ok(account.sign_out().await?)
940    }
941
942    async fn rename_account(
943        &mut self,
944        account_name: String,
945    ) -> Result<AccountChange<Self::NetworkResult>> {
946        let _ = self.sync_lock.lock().await;
947        let result = {
948            let mut account = self.account.lock().await;
949            account.rename_account(account_name).await?
950        };
951
952        let result = AccountChange {
953            event: result.event,
954            sync_result: self.sync().await,
955        };
956
957        Ok(result)
958    }
959
960    async fn set_account_name(
961        &mut self,
962        account_name: String,
963    ) -> std::result::Result<(), Self::Error> {
964        let mut account = self.account.lock().await;
965        Ok(account.set_account_name(account_name).await?)
966    }
967
968    async fn delete_account(&mut self) -> Result<()> {
969        // Shutdown any change listeners
970        #[cfg(feature = "listen")]
971        self.shutdown_websockets().await;
972
973        // Stop any pending file transfers
974        #[cfg(feature = "files")]
975        self.stop_file_transfers().await;
976
977        {
978            let mut account = self.account.lock().await;
979            // Delete the account and sign out
980            account.delete_account().await?;
981        }
982
983        Ok(())
984    }
985
986    async fn find<P>(&self, predicate: P) -> Option<Summary>
987    where
988        P: FnMut(&&Summary) -> bool + Send,
989    {
990        let account = self.account.lock().await;
991        account.find(predicate).await
992    }
993
994    async fn find_folder(&self, vault: &FolderRef) -> Option<Summary> {
995        let account = self.account.lock().await;
996        account.find_folder(vault).await
997    }
998
999    async fn load_folders(&mut self) -> Result<Vec<Summary>> {
1000        let mut account = self.account.lock().await;
1001        Ok(account.load_folders().await?)
1002    }
1003
1004    async fn list_folders(&self) -> Result<Vec<Summary>> {
1005        let account = self.account.lock().await;
1006        Ok(account.list_folders().await?)
1007    }
1008
1009    async fn list_secret_ids(
1010        &self,
1011        folder_id: &VaultId,
1012    ) -> Result<Vec<SecretId>> {
1013        let account = self.account.lock().await;
1014        Ok(account.list_secret_ids(folder_id).await?)
1015    }
1016
1017    async fn account_data(&self) -> Result<AccountData> {
1018        let account = self.account.lock().await;
1019        Ok(account.account_data().await?)
1020    }
1021
1022    async fn root_hash(&self, folder_id: &VaultId) -> Result<CommitHash> {
1023        let account = self.account.lock().await;
1024        Ok(account.root_hash(folder_id).await?)
1025    }
1026
1027    async fn identity_state(&self) -> Result<CommitState> {
1028        let account = self.account.lock().await;
1029        Ok(account.identity_state().await?)
1030    }
1031
1032    async fn commit_state(&self, folder_id: &VaultId) -> Result<CommitState> {
1033        let account = self.account.lock().await;
1034        Ok(account.commit_state(folder_id).await?)
1035    }
1036
1037    async fn compact_account(
1038        &mut self,
1039    ) -> Result<HashMap<Summary, AccountEvent>> {
1040        let result = {
1041            let mut account = self.account.lock().await;
1042            account.compact_account().await?
1043        };
1044
1045        let identity = {
1046            let log = self.identity_log().await?;
1047            let reader = log.read().await;
1048            reader.diff_unchecked().await?
1049        };
1050
1051        // Prepare event logs for the folders that
1052        // were converted
1053        let mut folders = HashMap::new();
1054        let compact_folders = self.list_folders().await?;
1055
1056        for folder in &compact_folders {
1057            if folder.flags().is_sync_disabled() {
1058                continue;
1059            }
1060            let event_log = self.folder_log(folder.id()).await?;
1061            let log_file = event_log.read().await;
1062            let diff = log_file.diff_unchecked().await?;
1063            folders.insert(*folder.id(), diff);
1064        }
1065
1066        // Force update the folders on remote servers
1067        let sync_options: SyncOptions = Default::default();
1068        let updates = UpdateSet {
1069            identity: Some(identity),
1070            folders,
1071            ..Default::default()
1072        };
1073
1074        let sync_result = self.force_update(updates, &sync_options).await;
1075        if let Some(sync_error) = sync_result.first_error() {
1076            return Err(Error::ForceUpdate(Box::new(sync_error)));
1077        }
1078
1079        // In case we have pending updates to the account, device
1080        // or file event logs
1081        if let Some(sync_error) =
1082            self.sync_with_options(&sync_options).await.first_error()
1083        {
1084            return Err(Error::ForceUpdate(Box::new(sync_error)));
1085        }
1086
1087        Ok(result)
1088    }
1089
1090    async fn compact_folder(
1091        &mut self,
1092        folder_id: &VaultId,
1093    ) -> Result<AccountEvent> {
1094        let result = {
1095            let mut account = self.account.lock().await;
1096            account.compact_folder(folder_id).await?
1097        };
1098
1099        // Prepare event logs for the folders that
1100        // were converted
1101        let mut folders = HashMap::new();
1102        let folder = self
1103            .find(|f| f.id() == folder_id)
1104            .await
1105            .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
1106        if !folder.flags().is_sync_disabled() {
1107            let event_log = self.folder_log(folder_id).await?;
1108            let log_file = event_log.read().await;
1109            let diff = log_file.diff_unchecked().await?;
1110            folders.insert(*folder_id, diff);
1111        }
1112
1113        if !folders.is_empty() {
1114            // Force update the folders on remote servers
1115            let sync_options: SyncOptions = Default::default();
1116            let updates = UpdateSet {
1117                identity: None,
1118                folders,
1119                ..Default::default()
1120            };
1121
1122            let sync_result = self.force_update(updates, &sync_options).await;
1123            if let Some(sync_error) = sync_result.first_error() {
1124                return Err(Error::ForceUpdate(Box::new(sync_error)));
1125            }
1126
1127            // In case we have pending updates to the account, device
1128            // or file event logs
1129            if let Some(sync_error) =
1130                self.sync_with_options(&sync_options).await.first_error()
1131            {
1132                return Err(Error::ForceUpdate(Box::new(sync_error)));
1133            }
1134        }
1135
1136        Ok(result)
1137    }
1138
1139    async fn restore_folder(
1140        &mut self,
1141        folder_id: &VaultId,
1142        records: Vec<EventRecord>,
1143    ) -> Result<Summary> {
1144        let mut account = self.account.lock().await;
1145        Ok(account.restore_folder(folder_id, records).await?)
1146    }
1147
1148    async fn change_folder_password(
1149        &mut self,
1150        folder_id: &VaultId,
1151        new_key: AccessKey,
1152    ) -> Result<()> {
1153        {
1154            let mut account = self.account.lock().await;
1155            account.change_folder_password(folder_id, new_key).await?;
1156        }
1157
1158        let identity = {
1159            let log = self.identity_log().await?;
1160            let reader = log.read().await;
1161            reader.diff_unchecked().await?
1162        };
1163
1164        // Prepare event logs for the folders that
1165        // were converted
1166        let mut folders = HashMap::new();
1167        let folder = self
1168            .find(|f| f.id() == folder_id)
1169            .await
1170            .ok_or_else(|| StorageError::FolderNotFound(*folder_id))?;
1171        if !folder.flags().is_sync_disabled() {
1172            let event_log = self.folder_log(folder_id).await?;
1173            let log_file = event_log.read().await;
1174            let diff = log_file.diff_unchecked().await?;
1175            folders.insert(*folder_id, diff);
1176        }
1177
1178        if !folders.is_empty() {
1179            // Force update the folders on remote servers
1180            let sync_options: SyncOptions = Default::default();
1181            let updates = UpdateSet {
1182                identity: Some(identity),
1183                folders,
1184                ..Default::default()
1185            };
1186
1187            let sync_result = self.force_update(updates, &sync_options).await;
1188            if let Some(sync_error) = sync_result.first_error() {
1189                return Err(Error::ForceUpdate(Box::new(sync_error)));
1190            }
1191
1192            // In case we have pending updates to the account, device
1193            // or file event logs
1194            if let Some(sync_error) =
1195                self.sync_with_options(&sync_options).await.first_error()
1196            {
1197                return Err(Error::ForceUpdate(Box::new(sync_error)));
1198            }
1199        }
1200
1201        Ok(())
1202    }
1203
1204    #[cfg(feature = "search")]
1205    async fn detached_view(
1206        &self,
1207        folder_id: &VaultId,
1208        commit: CommitHash,
1209    ) -> Result<sos_account::DetachedView> {
1210        let account = self.account.lock().await;
1211        Ok(account.detached_view(folder_id, commit).await?)
1212    }
1213
1214    #[cfg(feature = "search")]
1215    async fn initialize_search_index(
1216        &mut self,
1217    ) -> Result<(DocumentCount, Vec<Summary>)> {
1218        let mut account = self.account.lock().await;
1219        Ok(account.initialize_search_index().await?)
1220    }
1221
1222    #[cfg(feature = "search")]
1223    async fn statistics(&self) -> AccountStatistics {
1224        let account = self.account.lock().await;
1225        account.statistics().await
1226    }
1227
1228    #[cfg(feature = "search")]
1229    async fn search_index(&self) -> Result<Arc<RwLock<SearchIndex>>> {
1230        let account = self.account.lock().await;
1231        Ok(account.search_index().await?)
1232    }
1233
1234    #[cfg(feature = "search")]
1235    async fn query_view(
1236        &self,
1237        views: &[DocumentView],
1238        archive: Option<&ArchiveFilter>,
1239    ) -> Result<Vec<Document>> {
1240        let account = self.account.lock().await;
1241        Ok(account.query_view(views, archive).await?)
1242    }
1243
1244    #[cfg(feature = "search")]
1245    async fn query_map(
1246        &self,
1247        query: &str,
1248        filter: QueryFilter,
1249    ) -> Result<Vec<Document>> {
1250        let account = self.account.lock().await;
1251        Ok(account.query_map(query, filter).await?)
1252    }
1253
1254    #[cfg(feature = "search")]
1255    async fn document_count(&self) -> Result<DocumentCount> {
1256        let account = self.account.lock().await;
1257        Ok(account.document_count().await?)
1258    }
1259
1260    #[cfg(feature = "search")]
1261    async fn document_exists(
1262        &self,
1263        vault_id: &VaultId,
1264        label: &str,
1265        id: Option<&SecretId>,
1266    ) -> Result<bool> {
1267        let account = self.account.lock().await;
1268        Ok(account.document_exists(vault_id, label, id).await?)
1269    }
1270
1271    #[cfg(feature = "files")]
1272    async fn download_file(
1273        &self,
1274        vault_id: &VaultId,
1275        secret_id: &SecretId,
1276        file_name: &sos_core::ExternalFileName,
1277    ) -> Result<Vec<u8>> {
1278        let account = self.account.lock().await;
1279        Ok(account
1280            .download_file(vault_id, secret_id, file_name)
1281            .await?)
1282    }
1283
1284    async fn create_secret(
1285        &mut self,
1286        meta: SecretMeta,
1287        secret: Secret,
1288        options: AccessOptions,
1289    ) -> Result<SecretChange<Self::NetworkResult>> {
1290        let _ = self.sync_lock.lock().await;
1291
1292        let result = {
1293            let mut account = self.account.lock().await;
1294            account.create_secret(meta, secret, options).await?
1295        };
1296
1297        let result = SecretChange {
1298            id: result.id,
1299            event: result.event,
1300            commit_state: result.commit_state,
1301            folder: result.folder,
1302            sync_result: self.sync().await,
1303            #[cfg(feature = "files")]
1304            file_events: result.file_events,
1305        };
1306
1307        #[cfg(feature = "files")]
1308        self.queue_file_mutation_events(&result.file_events).await?;
1309
1310        Ok(result)
1311    }
1312
1313    async fn insert_secrets(
1314        &mut self,
1315        secrets: Vec<(SecretMeta, Secret)>,
1316    ) -> Result<SecretInsert<Self::NetworkResult>> {
1317        let _ = self.sync_lock.lock().await;
1318
1319        let result = {
1320            let mut account = self.account.lock().await;
1321            account.insert_secrets(secrets).await?
1322        };
1323
1324        #[cfg(feature = "files")]
1325        let mut file_events = Vec::new();
1326
1327        let result = SecretInsert {
1328            results: result
1329                .results
1330                .into_iter()
1331                .map(|#[allow(unused_mut)] mut result| {
1332                    #[cfg(feature = "files")]
1333                    file_events.append(&mut result.file_events);
1334                    SecretChange {
1335                        id: result.id,
1336                        event: result.event,
1337                        commit_state: result.commit_state,
1338                        folder: result.folder,
1339                        sync_result: Default::default(),
1340                        #[cfg(feature = "files")]
1341                        file_events: result.file_events,
1342                    }
1343                })
1344                .collect(),
1345            sync_result: self.sync().await,
1346        };
1347
1348        #[cfg(feature = "files")]
1349        self.queue_file_mutation_events(&file_events).await?;
1350
1351        Ok(result)
1352    }
1353
1354    async fn update_secret(
1355        &mut self,
1356        secret_id: &SecretId,
1357        meta: SecretMeta,
1358        secret: Option<Secret>,
1359        options: AccessOptions,
1360    ) -> Result<SecretChange<Self::NetworkResult>> {
1361        let _ = self.sync_lock.lock().await;
1362
1363        let result = {
1364            let mut account = self.account.lock().await;
1365            account
1366                .update_secret(secret_id, meta, secret, options)
1367                .await?
1368        };
1369
1370        let result = SecretChange {
1371            id: result.id,
1372            event: result.event,
1373            commit_state: result.commit_state,
1374            folder: result.folder,
1375            sync_result: self.sync().await,
1376            #[cfg(feature = "files")]
1377            file_events: result.file_events,
1378        };
1379
1380        #[cfg(feature = "files")]
1381        self.queue_file_mutation_events(&result.file_events).await?;
1382
1383        Ok(result)
1384    }
1385
1386    async fn move_secret(
1387        &mut self,
1388        secret_id: &SecretId,
1389        from: &VaultId,
1390        to: &VaultId,
1391        options: AccessOptions,
1392    ) -> Result<SecretMove<Self::NetworkResult>> {
1393        let _ = self.sync_lock.lock().await;
1394
1395        let result = {
1396            let mut account = self.account.lock().await;
1397            account.move_secret(secret_id, from, to, options).await?
1398        };
1399
1400        let result = SecretMove {
1401            id: result.id,
1402            event: result.event,
1403            sync_result: self.sync().await,
1404            #[cfg(feature = "files")]
1405            file_events: result.file_events,
1406        };
1407
1408        #[cfg(feature = "files")]
1409        self.queue_file_mutation_events(&result.file_events).await?;
1410
1411        Ok(result)
1412    }
1413
1414    async fn read_secret(
1415        &self,
1416        secret_id: &SecretId,
1417        folder: Option<&VaultId>,
1418    ) -> Result<(SecretRow, ReadEvent)> {
1419        let account = self.account.lock().await;
1420        Ok(account.read_secret(secret_id, folder).await?)
1421    }
1422
1423    async fn raw_secret(
1424        &self,
1425        folder_id: &VaultId,
1426        secret_id: &SecretId,
1427    ) -> std::result::Result<Option<(VaultCommit, ReadEvent)>, Self::Error>
1428    {
1429        let account = self.account.lock().await;
1430        Ok(account.raw_secret(folder_id, secret_id).await?)
1431    }
1432
1433    async fn delete_secret(
1434        &mut self,
1435        secret_id: &SecretId,
1436        options: AccessOptions,
1437    ) -> Result<SecretDelete<Self::NetworkResult>> {
1438        let _ = self.sync_lock.lock().await;
1439
1440        let result = {
1441            let mut account = self.account.lock().await;
1442            account.delete_secret(secret_id, options).await?
1443        };
1444
1445        let result = SecretDelete {
1446            event: result.event,
1447            commit_state: result.commit_state,
1448            folder: result.folder,
1449            sync_result: self.sync().await,
1450            #[cfg(feature = "files")]
1451            file_events: result.file_events,
1452        };
1453
1454        #[cfg(feature = "files")]
1455        self.queue_file_mutation_events(&result.file_events).await?;
1456
1457        Ok(result)
1458    }
1459
1460    async fn archive(
1461        &mut self,
1462        folder_id: &VaultId,
1463        secret_id: &SecretId,
1464        options: AccessOptions,
1465    ) -> Result<SecretMove<Self::NetworkResult>> {
1466        let _ = self.sync_lock.lock().await;
1467        let result = {
1468            let mut account = self.account.lock().await;
1469            account.archive(folder_id, secret_id, options).await?
1470        };
1471
1472        let result = SecretMove {
1473            id: result.id,
1474            event: result.event,
1475            sync_result: self.sync().await,
1476            #[cfg(feature = "files")]
1477            file_events: result.file_events,
1478        };
1479
1480        #[cfg(feature = "files")]
1481        self.queue_file_mutation_events(&result.file_events).await?;
1482
1483        Ok(result)
1484    }
1485
1486    async fn unarchive(
1487        &mut self,
1488        secret_id: &SecretId,
1489        secret_kind: &SecretType,
1490        options: AccessOptions,
1491    ) -> Result<(SecretMove<Self::NetworkResult>, Summary)> {
1492        let _ = self.sync_lock.lock().await;
1493
1494        let (result, to) = {
1495            let mut account = self.account.lock().await;
1496            account.unarchive(secret_id, secret_kind, options).await?
1497        };
1498
1499        let result = SecretMove {
1500            id: result.id,
1501            event: result.event,
1502            sync_result: self.sync().await,
1503            #[cfg(feature = "files")]
1504            file_events: result.file_events,
1505        };
1506
1507        #[cfg(feature = "files")]
1508        self.queue_file_mutation_events(&result.file_events).await?;
1509
1510        Ok((result, to))
1511    }
1512
1513    #[cfg(feature = "files")]
1514    async fn update_file(
1515        &mut self,
1516        secret_id: &SecretId,
1517        meta: SecretMeta,
1518        path: impl AsRef<Path> + Send + Sync,
1519        options: AccessOptions,
1520    ) -> Result<SecretChange<Self::NetworkResult>> {
1521        let _ = self.sync_lock.lock().await;
1522
1523        let result = {
1524            let mut account = self.account.lock().await;
1525            let result =
1526                account.update_file(secret_id, meta, path, options).await?;
1527            result
1528        };
1529
1530        let result = SecretChange {
1531            id: result.id,
1532            event: result.event,
1533            commit_state: result.commit_state,
1534            folder: result.folder,
1535            sync_result: self.sync().await,
1536            #[cfg(feature = "files")]
1537            file_events: result.file_events,
1538        };
1539
1540        #[cfg(feature = "files")]
1541        self.queue_file_mutation_events(&result.file_events).await?;
1542
1543        Ok(result)
1544    }
1545
1546    async fn create_folder(
1547        &mut self,
1548        options: NewFolderOptions,
1549    ) -> Result<FolderCreate<Self::NetworkResult>> {
1550        let _ = self.sync_lock.lock().await;
1551        let result = {
1552            let mut account = self.account.lock().await;
1553            account.create_folder(options).await?
1554        };
1555
1556        let result = FolderCreate {
1557            folder: result.folder,
1558            event: result.event,
1559            commit_state: result.commit_state,
1560            sync_result: self.sync().await,
1561        };
1562
1563        Ok(result)
1564    }
1565
1566    async fn rename_folder(
1567        &mut self,
1568        folder_id: &VaultId,
1569        name: String,
1570    ) -> Result<FolderChange<Self::NetworkResult>> {
1571        let _ = self.sync_lock.lock().await;
1572        let result = {
1573            let mut account = self.account.lock().await;
1574            account.rename_folder(folder_id, name).await?
1575        };
1576
1577        let result = FolderChange {
1578            event: result.event,
1579            commit_state: result.commit_state,
1580            sync_result: self.sync().await,
1581        };
1582
1583        Ok(result)
1584    }
1585
1586    async fn update_folder_flags(
1587        &mut self,
1588        folder_id: &VaultId,
1589        flags: VaultFlags,
1590    ) -> Result<FolderChange<Self::NetworkResult>> {
1591        let _ = self.sync_lock.lock().await;
1592        let result = {
1593            let mut account = self.account.lock().await;
1594            account.update_folder_flags(folder_id, flags).await?
1595        };
1596
1597        let result = FolderChange {
1598            event: result.event,
1599            commit_state: result.commit_state,
1600            sync_result: self.sync().await,
1601        };
1602
1603        Ok(result)
1604    }
1605
1606    async fn import_folder(
1607        &mut self,
1608        path: impl AsRef<Path> + Send + Sync,
1609        key: AccessKey,
1610        overwrite: bool,
1611    ) -> Result<FolderCreate<Self::NetworkResult>> {
1612        let _ = self.sync_lock.lock().await;
1613
1614        let result = {
1615            let mut account = self.account.lock().await;
1616            account.import_folder(path.as_ref(), key, overwrite).await?
1617        };
1618
1619        let result = FolderCreate {
1620            folder: result.folder,
1621            event: result.event,
1622            commit_state: result.commit_state,
1623            sync_result: self.sync().await,
1624        };
1625
1626        Ok(result)
1627    }
1628
1629    async fn import_login_folder(
1630        &mut self,
1631        vault: Vault,
1632    ) -> Result<AccountEvent> {
1633        let mut account = self.account.lock().await;
1634        Ok(account.import_login_folder(vault).await?)
1635    }
1636
1637    async fn import_folder_buffer(
1638        &mut self,
1639        buffer: impl AsRef<[u8]> + Send + Sync,
1640        key: AccessKey,
1641        overwrite: bool,
1642    ) -> Result<FolderCreate<Self::NetworkResult>> {
1643        let _ = self.sync_lock.lock().await;
1644
1645        let result = {
1646            let mut account = self.account.lock().await;
1647            account.import_folder_buffer(buffer, key, overwrite).await?
1648        };
1649
1650        let result = FolderCreate {
1651            folder: result.folder,
1652            event: result.event,
1653            commit_state: result.commit_state,
1654            sync_result: self.sync().await,
1655        };
1656
1657        Ok(result)
1658    }
1659
1660    async fn export_folder(
1661        &mut self,
1662        path: impl AsRef<Path> + Send + Sync,
1663        folder_id: &VaultId,
1664        new_key: AccessKey,
1665        save_key: bool,
1666    ) -> Result<()> {
1667        let mut account = self.account.lock().await;
1668        Ok(account
1669            .export_folder(path, folder_id, new_key, save_key)
1670            .await?)
1671    }
1672
1673    async fn export_folder_buffer(
1674        &mut self,
1675        folder_id: &VaultId,
1676        new_key: AccessKey,
1677        save_key: bool,
1678    ) -> Result<Vec<u8>> {
1679        let mut account = self.account.lock().await;
1680        Ok(account
1681            .export_folder_buffer(folder_id, new_key, save_key)
1682            .await?)
1683    }
1684
1685    async fn delete_folder(
1686        &mut self,
1687        folder_id: &VaultId,
1688    ) -> Result<FolderDelete<Self::NetworkResult>> {
1689        let _ = self.sync_lock.lock().await;
1690        let result = {
1691            let mut account = self.account.lock().await;
1692            account.delete_folder(folder_id).await?
1693        };
1694
1695        let result = FolderDelete {
1696            events: result.events,
1697            commit_state: result.commit_state,
1698            sync_result: self.sync().await,
1699        };
1700
1701        Ok(result)
1702    }
1703
1704    async fn forget_folder(&mut self, folder_id: &VaultId) -> Result<bool> {
1705        let mut account = self.account.lock().await;
1706        Ok(account.forget_folder(folder_id).await?)
1707    }
1708
1709    #[cfg(feature = "contacts")]
1710    async fn load_avatar(
1711        &self,
1712        secret_id: &SecretId,
1713        folder: Option<&VaultId>,
1714    ) -> Result<Option<Vec<u8>>> {
1715        let account = self.account.lock().await;
1716        Ok(account.load_avatar(secret_id, folder).await?)
1717    }
1718
1719    #[cfg(feature = "contacts")]
1720    async fn export_contact(
1721        &self,
1722        path: impl AsRef<Path> + Send + Sync,
1723        secret_id: &SecretId,
1724        folder: Option<&VaultId>,
1725    ) -> Result<()> {
1726        let account = self.account.lock().await;
1727        Ok(account.export_contact(path, secret_id, folder).await?)
1728    }
1729
1730    #[cfg(feature = "contacts")]
1731    async fn export_all_contacts(
1732        &self,
1733        path: impl AsRef<Path> + Send + Sync,
1734    ) -> Result<()> {
1735        let account = self.account.lock().await;
1736        Ok(account.export_all_contacts(path).await?)
1737    }
1738
1739    #[cfg(feature = "contacts")]
1740    async fn import_contacts(
1741        &mut self,
1742        content: &str,
1743        progress: impl Fn(ContactImportProgress) + Send + Sync,
1744    ) -> Result<Vec<SecretId>> {
1745        let mut account = self.account.lock().await;
1746        Ok(account.import_contacts(content, progress).await?)
1747    }
1748
1749    /*
1750    #[cfg(feature = "security-report")]
1751    async fn generate_security_report<T, D, R>(
1752        &mut self,
1753        options: SecurityReportOptions<T, D, R>,
1754    ) -> Result<SecurityReport<T>>
1755    where
1756        D: Fn(Vec<String>) -> R + Send + Sync,
1757        R: std::future::Future<Output = Vec<T>> + Send + Sync,
1758    {
1759        let mut account = self.account.lock().await;
1760        Ok(account.generate_security_report(options).await?)
1761    }
1762    */
1763
1764    #[cfg(feature = "migrate")]
1765    async fn export_unsafe_archive(
1766        &self,
1767        path: impl AsRef<Path> + Send + Sync,
1768    ) -> Result<()> {
1769        let account = self.account.lock().await;
1770        Ok(account.export_unsafe_archive(path).await?)
1771    }
1772
1773    #[cfg(feature = "migrate")]
1774    async fn import_file(
1775        &mut self,
1776        target: ImportTarget,
1777    ) -> Result<FolderCreate<Self::NetworkResult>> {
1778        let _ = self.sync_lock.lock().await;
1779
1780        let result = {
1781            let mut account = self.account.lock().await;
1782            account.import_file(target).await?
1783        };
1784
1785        let result = FolderCreate {
1786            folder: result.folder,
1787            event: result.event,
1788            commit_state: result.commit_state,
1789            sync_result: self.sync().await,
1790        };
1791
1792        Ok(result)
1793    }
1794
1795    #[cfg(feature = "archive")]
1796    async fn export_backup_archive(
1797        &self,
1798        path: impl AsRef<Path> + Send + Sync,
1799    ) -> Result<()> {
1800        let account = self.account.lock().await;
1801        Ok(account.export_backup_archive(path).await?)
1802    }
1803
1804    #[cfg(feature = "archive")]
1805    async fn import_backup_archive(
1806        path: impl AsRef<Path> + Send + Sync,
1807        target: &BackendTarget,
1808    ) -> Result<Vec<PublicIdentity>> {
1809        Ok(LocalAccount::import_backup_archive(path, target).await?)
1810    }
1811
1812    #[cfg(feature = "clipboard")]
1813    async fn copy_clipboard(
1814        &self,
1815        clipboard: &Clipboard,
1816        target: &SecretPath,
1817        request: &ClipboardCopyRequest,
1818    ) -> Result<bool> {
1819        let account = self.account.lock().await;
1820        Ok(account.copy_clipboard(clipboard, target, request).await?)
1821    }
1822}
1823
1824#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
1825#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
1826impl DelegatedAccess for NetworkAccount {
1827    type Error = Error;
1828
1829    async fn find_folder_password(
1830        &self,
1831        folder_id: &VaultId,
1832    ) -> Result<Option<AccessKey>> {
1833        let account = self.account.lock().await;
1834        Ok(account.find_folder_password(folder_id).await?)
1835    }
1836
1837    async fn remove_folder_password(
1838        &mut self,
1839        folder_id: &VaultId,
1840    ) -> Result<()> {
1841        let mut account = self.account.lock().await;
1842        Ok(account.remove_folder_password(folder_id).await?)
1843    }
1844
1845    async fn save_folder_password(
1846        &mut self,
1847        folder_id: &VaultId,
1848        key: AccessKey,
1849    ) -> Result<()> {
1850        let mut account = self.account.lock().await;
1851        Ok(account.save_folder_password(folder_id, key).await?)
1852    }
1853}