diff --git a/workspace/net/Cargo.toml b/workspace/net/Cargo.toml index f1f8283588..da6b0baccb 100644 --- a/workspace/net/Cargo.toml +++ b/workspace/net/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/saveoursecrets/sdk" [features] default = [] full = [ + "archive", "client", "server", "hashcheck", @@ -32,6 +33,7 @@ server = [ "tokio-stream", ] hashcheck = [] +archive = ["sos-sdk/archive"] contacts = ["sos-sdk/contacts"] migrate = ["sos-migrate"] device = [ diff --git a/workspace/net/src/client/account/user_storage.rs b/workspace/net/src/client/account/user_storage.rs index d726f7ae5f..f2efe9b964 100644 --- a/workspace/net/src/client/account/user_storage.rs +++ b/workspace/net/src/client/account/user_storage.rs @@ -450,40 +450,6 @@ impl UserStorage { ) -> Result<(Summary, Option)> { let _ = self.sync_lock.lock().await; - /* - let passphrase = DelegatedPassword::generate_folder_password()?; - let key = AccessKey::Password(passphrase); - let (buffer, _, summary) = { - let mut writer = self.storage.write().await; - writer.create_vault(name, Some(key.clone())).await? - }; - - let secret_key = self.user.identity().signer().to_bytes(); - let secure_key = - SecureAccessKey::encrypt(&key, secret_key, None).await?; - - DelegatedPassword::save_folder_password( - self.user.identity().keeper(), - summary.id(), - key, - ) - .await?; - - let event = Event::Account(AccountEvent::CreateFolder(*summary.id())); - let audit_event: AuditEvent = (self.address(), &event).into(); - self.append_audit_logs(vec![audit_event]).await?; - - let options = AccessOptions { - folder: Some(summary), - ..Default::default() - }; - let (summary, before_last_commit, before_commit_proof) = - self.before_apply_events(&options, false).await?; - - //let (_, event) = event.try_into()?; - let event = WriteEvent::CreateVault(buffer); - */ - let (summary, event, commit_state, secure_key) = self.account.create_folder(name).await?; @@ -589,69 +555,6 @@ impl UserStorage { Ok(self.account.open_folder(summary).await?) } - /* - /// Helper to get all the state information needed - /// before calling sync methods. - /// - /// Computes the target folder that will be used, the last commit - /// hash and the proof for the current head of the events log. - async fn before_apply_events( - &self, - options: &AccessOptions, - apply_changes: bool, - ) -> Result<(Summary, Option, CommitProof)> { - let (folder, mut last_commit, mut commit_proof) = { - let reader = self.storage.read().await; - let folder = options - .folder - .clone() - .or_else(|| reader.current().map(|g| g.summary().clone())) - .ok_or(Error::NoOpenFolder)?; - - let event_log = reader - .cache() - .get(folder.id()) - .ok_or(Error::CacheNotAvailable(*folder.id()))?; - let last_commit = event_log.last_commit().await?; - let commit_proof = event_log.tree().head()?; - (folder, last_commit, commit_proof) - }; - - // Most sync events should try to apply remote changes - // beforehand but some (such as creating new folders) should - // not as it would just result in a 404 - if apply_changes { - match self - .sync_before_apply_change( - &folder, - last_commit.as_ref(), - &commit_proof, - ) - .await - { - Ok(changed) => { - // If changes were made we need to re-compute the - // proof and last commit - if changed { - let reader = self.storage.read().await; - let event_log = reader - .cache() - .get(folder.id()) - .ok_or(Error::CacheNotAvailable(*folder.id()))?; - last_commit = event_log.last_commit().await?; - commit_proof = event_log.tree().head()?; - } - } - Err(e) => { - tracing::error!(error = ?e, "failed to sync before change"); - } - } - } - - Ok((folder, last_commit, commit_proof)) - } - */ - /// Create a secret in the current open folder or a specific folder. pub async fn create_secret( &mut self, @@ -1014,40 +917,6 @@ impl UserStorage { Ok((event, summary)) } - /// Create a backup archive containing the - /// encrypted data for the account. - pub async fn export_backup_archive>( - &self, - path: P, - ) -> Result<()> { - Ok(self.account.export_backup_archive(path).await?) - } - - /// Read the inventory from an archive. - pub async fn restore_archive_inventory< - R: AsyncRead + AsyncSeek + Unpin, - >( - buffer: R, - ) -> Result { - Ok(LocalAccount::restore_archive_inventory(buffer).await?) - } - - /// Import from an archive file. - pub async fn restore_backup_archive>( - owner: Option<&mut UserStorage>, - path: P, - options: RestoreOptions, - data_dir: Option, - ) -> Result { - Ok(LocalAccount::restore_backup_archive( - owner.map(|o| &mut o.account), - path, - options, - data_dir, - ) - .await?) - } - /// Create a detached view of an event log until a /// particular commit. /// @@ -1107,6 +976,44 @@ impl UserStorage { } } +#[cfg(feature = "archive")] +impl UserStorage { + /// Create a backup archive containing the + /// encrypted data for the account. + pub async fn export_backup_archive>( + &self, + path: P, + ) -> Result<()> { + Ok(self.account.export_backup_archive(path).await?) + } + + /// Read the inventory from an archive. + pub async fn restore_archive_inventory< + R: AsyncRead + AsyncSeek + Unpin, + >( + buffer: R, + ) -> Result { + Ok(LocalAccount::restore_archive_inventory(buffer).await?) + } + + /// Import from an archive file. + pub async fn restore_backup_archive>( + owner: Option<&mut UserStorage>, + path: P, + options: RestoreOptions, + data_dir: Option, + ) -> Result { + Ok(LocalAccount::restore_backup_archive( + owner.map(|o| &mut o.account), + path, + options, + data_dir, + ) + .await?) + } + +} + #[cfg(feature = "contacts")] impl UserStorage { /// Get an avatar JPEG image for a contact in the current @@ -1150,14 +1057,6 @@ impl UserStorage { } } -/* -impl From for Arc> { - fn from(value: UserStorage) -> Self { - value.account.into() - } -} -*/ - #[async_trait] impl RemoteSync for UserStorage { async fn sync(&self) -> Option { @@ -1241,41 +1140,6 @@ impl RemoteSync for UserStorage { } } - /* - async fn sync_before_apply_change( - &self, - folder: &Summary, - last_commit: &CommitHash, - client_proof: &CommitProof, - ) -> Result { - let mut changed = false; - let mut last_commit = last_commit.clone(); - let mut client_proof = client_proof.clone(); - - let _ = self.sync_lock.lock().await; - for remote in self.remotes.values() { - let local_changed = remote - .sync_before_apply_change(folder, &last_commit, &client_proof) - .await?; - - // If a remote changes were applied to local - // we need to recompute the last commit and client proof - if local_changed { - let reader = self.storage.read().await; - let event_log = reader - .cache() - .get(folder.id()) - .ok_or(Error::CacheNotAvailable(*folder.id()))?; - last_commit = event_log.last_commit().await?; - client_proof = event_log.tree().head()?; - } - - changed = changed || local_changed; - } - Ok(changed) - } - */ - async fn sync_send_events( &self, folder: &Summary, diff --git a/workspace/sdk/src/account/account.rs b/workspace/sdk/src/account/account.rs index 200ac8fd1a..0523155ce4 100644 --- a/workspace/sdk/src/account/account.rs +++ b/workspace/sdk/src/account/account.rs @@ -671,7 +671,7 @@ impl Account { new_key: AccessKey, save_key: bool, ) -> Result<()> { - let buffer = AccountBackup::export_vault( + let buffer = export_vault( self.address(), &self.paths, self.user()?.identity().keeper(), @@ -1755,3 +1755,40 @@ impl Account { DelegatedPassword::find_folder_password(identity, vault_id).await } } + + +/// Export a vault by changing the vault passphrase and +/// converting it to a buffer. +/// +/// The identity vault must be unlocked so we can retrieve +/// the passphrase for the target vault. +async fn export_vault( + _address: &Address, + paths: &UserPaths, + identity: Arc>, + vault_id: &VaultId, + new_passphrase: AccessKey, +) -> Result> { + use crate::passwd::ChangePassword; + // Get the current vault passphrase from the identity vault + let current_passphrase = + DelegatedPassword::find_folder_password(identity, vault_id) + .await?; + + // Find the local vault for the account + let local_accounts = AccountsList::new(paths); + let (vault, _) = + local_accounts.find_local_vault(vault_id, false).await?; + + // Change the password before exporting + let (_, vault, _) = ChangePassword::new( + &vault, + current_passphrase, + new_passphrase, + None, + ) + .build() + .await?; + + encode(&vault).await +} diff --git a/workspace/sdk/src/account/archive/backup.rs b/workspace/sdk/src/account/archive/backup.rs index 9c6ec40209..8f5a0efe02 100644 --- a/workspace/sdk/src/account/archive/backup.rs +++ b/workspace/sdk/src/account/archive/backup.rs @@ -314,41 +314,6 @@ impl AccountBackup { Ok((size, checksum.as_slice().try_into()?)) } - /// Export a vault by changing the vault passphrase and - /// converting it to a buffer. - /// - /// The identity vault must be unlocked so we can retrieve - /// the passphrase for the target vault. - pub async fn export_vault( - _address: &Address, - paths: &UserPaths, - identity: Arc>, - vault_id: &VaultId, - new_passphrase: AccessKey, - ) -> Result> { - // Get the current vault passphrase from the identity vault - let current_passphrase = - DelegatedPassword::find_folder_password(identity, vault_id) - .await?; - - // Find the local vault for the account - let local_accounts = AccountsList::new(paths); - let (vault, _) = - local_accounts.find_local_vault(vault_id, false).await?; - - // Change the password before exporting - let (_, vault, _) = ChangePassword::new( - &vault, - current_passphrase, - new_passphrase, - None, - ) - .build() - .await?; - - encode(&vault).await - } - /// Create a buffer for a zip archive including the /// identity vault and all user vaults. pub async fn export_archive_buffer( diff --git a/workspace/sdk/src/account/provider.rs b/workspace/sdk/src/account/provider.rs index 3f360b1156..72dfca561e 100644 --- a/workspace/sdk/src/account/provider.rs +++ b/workspace/sdk/src/account/provider.rs @@ -1,7 +1,7 @@ //! Storage provider backed by the local filesystem. use crate::{ account::{ - archive::RestoreTargets, search::SearchIndex, AccountStatus, + search::SearchIndex, AccountStatus, NewAccount, UserPaths, }, commit::{CommitHash, CommitTree}, @@ -25,6 +25,9 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc}; use tokio::sync::RwLock; +#[cfg(feature = "archive")] +use crate::account::archive::RestoreTargets; + /// Manages multiple folders loaded into memory and mirrored to disc. pub struct FolderStorage { /// State of this storage. @@ -173,6 +176,7 @@ impl FolderStorage { /// Restore vaults from an archive. /// /// Buffer is the compressed archive contents. + #[cfg(feature = "archive")] pub async fn restore_archive( &mut self, targets: &RestoreTargets,