Skip to content
This repository has been archived by the owner on Sep 21, 2024. It is now read-only.

Commit

Permalink
fix: Ensure write access when syncing a sphere. Fixes #389
Browse files Browse the repository at this point in the history
  • Loading branch information
jsantell committed Aug 7, 2023
1 parent 255b476 commit 7a86068
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
16 changes: 16 additions & 0 deletions rust/noosphere-sphere/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ mod tests {
use crate::{
helpers::{make_valid_link_record, simulated_sphere_context, SimulationAccess},
HasMutableSphereContext, HasSphereContext, SphereContentWrite, SpherePetnameWrite,
SphereSync, SyncError,
};

#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -382,4 +383,19 @@ mod tests {

Ok(())
}

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
async fn it_requires_write_access_to_sync() -> Result<()> {
initialize_tracing(None);

let (mut sphere_context, _) =
simulated_sphere_context(SimulationAccess::Readonly, None).await?;

assert!(matches!(
sphere_context.sync(crate::SyncRecovery::None).await,
Err(SyncError::InsufficientPermission)
));
Ok(())
}
}
3 changes: 3 additions & 0 deletions rust/noosphere-sphere/src/sync/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use thiserror::Error;
/// gateway
#[derive(Error, Debug)]
pub enum SyncError {
/// The error was due to not having write access to the sphere
#[error("Insufficient permission to sync")]
InsufficientPermission,
/// The error was a conflict; this is possibly recoverable
#[error("There was a conflict during sync")]
Conflict,
Expand Down
45 changes: 44 additions & 1 deletion rust/noosphere-sphere/src/sync/write.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use anyhow::Result;
use async_trait::async_trait;
use noosphere_core::data::{Link, MemoIpld};
use noosphere_core::{
authority::Authorization,
data::{Link, MemoIpld},
};
use noosphere_storage::Storage;

use crate::{internal::SphereContextInternal, HasSphereContext};
use crate::{HasMutableSphereContext, SyncError, SyncRecovery};

use crate::GatewaySyncStrategy;
Expand Down Expand Up @@ -36,6 +40,17 @@ where
async fn sync(&mut self, recovery: SyncRecovery) -> Result<Link<MemoIpld>, SyncError> {
debug!("Attempting to sync...");

// Check that the author has write access to sync.
// If a sphere was joined from another sphere, do not check,
// but allow sync to proceed, as the local sphere does not have
// local proof until after initial sync. If truly no write access is
// available, the gateway will reject this sync.
if !is_sphere_joined(self).await {
self.assert_write_access()
.await
.map_err(|_| SyncError::InsufficientPermission)?;
}

let sync_strategy = GatewaySyncStrategy::default();

let version = match recovery {
Expand Down Expand Up @@ -78,3 +93,31 @@ where
Ok(version)
}
}

/// Given a `HasSphereContext<S>`, return a boolean indicating
/// whether or not this sphere has been joined from another sphere
/// (e.g. possibly lacking local authorization until syncing with a gateway).
async fn is_sphere_joined<C, S>(context: &C) -> bool
where
C: HasSphereContext<S>,
S: Storage + 'static,
{
let context = {
let context = context.sphere_context().await;
if context.is_err() {
return false;
}
context.unwrap()
};

let author = context.author();

let auth = {
let auth = author.require_authorization();
if auth.is_err() {
return false;
}
auth.unwrap()
};
matches!(auth, Authorization::Cid(_))
}

0 comments on commit 7a86068

Please sign in to comment.