Skip to content

Commit

Permalink
Ensure prevent sync pattern is applied on startup
Browse files Browse the repository at this point in the history
Closes #7779, Closes #7780
  • Loading branch information
FirelightFlagboy committed Jul 31, 2024
1 parent e8dae36 commit 9965976
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions libparsec/crates/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ libparsec_protocol = { workspace = true }
paste = { workspace = true }
log = { workspace = true }
sharks = { workspace = true }
thiserror = { workspace = true }
anyhow = { workspace = true }

[dev-dependencies]
libparsec_tests_lite = { workspace = true }
Expand Down
10 changes: 9 additions & 1 deletion libparsec/crates/client/src/workspace/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod file_updater;
mod folder_updater;
mod manifest_access;
mod per_manifest_update_lock;
mod prevent_sync_pattern;
mod reparent_updater;
mod resolve_path;
mod sync_updater;
Expand Down Expand Up @@ -172,7 +173,14 @@ impl WorkspaceStore {
}
};

// 3) All set !
// 3) Ensure the prevent sync pattern is applied to the workspace
prevent_sync_pattern::ensure_prevent_sync_pattern_applied_to_wksp(
&mut storage,
device.clone(),
)
.await?;

// 4) All set !

Ok(Self {
realm_id,
Expand Down
116 changes: 116 additions & 0 deletions libparsec/crates/client/src/workspace/store/prevent_sync_pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::sync::Arc;

use libparsec_platform_storage::workspace::{ManifestData, WorkspaceStorage};
use libparsec_types::{
DataError, LocalDevice, LocalFolderManifest, LocalWorkspaceManifest, SecretKey,
};

#[derive(Debug, thiserror::Error)]
pub enum ApplyPreventSyncPatternError {
#[error("Decryption error")]
DecryptionError,
#[error(transparent)]
Internal(anyhow::Error),
}

pub(super) async fn ensure_prevent_sync_pattern_applied_to_wksp(
storage: &mut WorkspaceStorage,
device: Arc<LocalDevice>,
) -> Result<(), ApplyPreventSyncPatternError> {
const PAGE_SIZE: u32 = 1000;

let (pattern, fully_applied) = storage
.get_prevent_sync_pattern()
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

if fully_applied {
return Ok(());
}

let mut page = 0;
loop {
let manifests = storage
.list_manifests(page, PAGE_SIZE)
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

let mut updated_manifest = Vec::with_capacity(manifests.len());
for manifest in &manifests {
if let Some(folder) = decode_folder(&manifest.encrypted, &device.local_symkey)? {
let new_folder =
folder.apply_prevent_sync_pattern(Some(&pattern), device.time_provider.now());
// TODO: Is it ok to just check the updated field (DateTime) to see if the manifest has changed,
// or better to do a full eq ?
if new_folder.updated != folder.updated {
updated_manifest.push(ManifestData {
entry_id: new_folder.base.id,
encrypted: new_folder.dump_and_encrypt(&device.local_symkey),
need_sync: new_folder.need_sync,
base_version: new_folder.base.version,
})
}
} else if let Some(workspace) =
decode_workspace(&manifest.encrypted, &device.local_symkey)?
{
let new_workspace = LocalWorkspaceManifest(
workspace
.apply_prevent_sync_pattern(Some(&pattern), device.time_provider.now()),
);
// TODO: Is it ok to just check the updated field (DateTime) to see if the manifest has changed,
// or better to do a full eq ?
if new_workspace.updated != workspace.updated {
updated_manifest.push(ManifestData {
entry_id: new_workspace.base.id,
encrypted: new_workspace.dump_and_encrypt(&device.local_symkey),
need_sync: new_workspace.need_sync,
base_version: new_workspace.base.version,
})
}
}
}

storage
.update_manifests(updated_manifest.into_iter())
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

// The manifests list is not filled to the page size,
// We consider that another call will result in an empty list, so we can stop here.
if manifests.len() < PAGE_SIZE as usize {
break;
}
page += 1;
}
storage
.mark_prevent_sync_pattern_fully_applied(&pattern)
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;
Ok(())
}

fn decode_folder(
encoded: &[u8],
symkey: &SecretKey,
) -> Result<Option<LocalFolderManifest>, ApplyPreventSyncPatternError> {
match LocalFolderManifest::decrypt_and_load(encoded, symkey) {
Ok(manifest) => Ok(Some(manifest)),
Err(DataError::Decryption) => Err(ApplyPreventSyncPatternError::DecryptionError),
// We consider that BadSerialization indicate that the manifest is not of folder type.
Err(DataError::BadSerialization { .. }) => Ok(None),
Err(e) => Err(ApplyPreventSyncPatternError::Internal(e.into())),
}
}

fn decode_workspace(
encoded: &[u8],
symkey: &SecretKey,
) -> Result<Option<LocalWorkspaceManifest>, ApplyPreventSyncPatternError> {
match LocalWorkspaceManifest::decrypt_and_load(encoded, symkey) {
Ok(manifest) => Ok(Some(manifest)),
Err(DataError::Decryption) => return Err(ApplyPreventSyncPatternError::DecryptionError),
// We consider that BadSerialization indicate that the manifest is not of workspace type.
Err(DataError::BadSerialization { .. }) => Ok(None),
Err(e) => Err(ApplyPreventSyncPatternError::Internal(e.into())),
}
}

0 comments on commit 9965976

Please sign in to comment.