diff options
Diffstat (limited to 'src/state')
| -rw-r--r-- | src/state/host.rs | 21 | ||||
| -rw-r--r-- | src/state/mod.rs | 11 |
2 files changed, 29 insertions, 3 deletions
diff --git a/src/state/host.rs b/src/state/host.rs index a48a6fb..e401509 100644 --- a/src/state/host.rs +++ b/src/state/host.rs @@ -403,9 +403,24 @@ impl Host for AppState { tokio::task::spawn_blocking(move || { let result = { let mut replica = state.doc.blocking_write(); - let result = replica - .apply_changes([change]) - .map_err(|error| error.to_string()); + let result = if crate::access::policy::of(&replica.doc).enforced() { + // Judged first (`access::screen`). + let (epoch, epoch_seq) = (replica.epoch, replica.epoch_seq); + crate::access::screen::apply_bytes( + &mut replica.doc, + epoch, + epoch_seq, + change.raw_bytes(), + &state.screening, + &mut crate::document::PatchLog::inactive(), + ) + .map(|_| ()) + .map_err(|error| format!("{error:#}")) + } else { + replica + .apply_changes([change]) + .map_err(|error| error.to_string()) + }; replica.refresh_heads(); result }; // lock released before notifying diff --git a/src/state/mod.rs b/src/state/mod.rs index ff19124..049c9e6 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -150,6 +150,9 @@ pub(crate) struct AppState { /// Which of its changes this node signs besides those a write's `Sign` says /// (`--sign-every`). pub(crate) sign_every: SignEvery, + /// Received changes waiting for their dependencies, and those refused, while the + /// policy has them judged (`access::screen`). Locked after the document. + pub(crate) screening: Arc<std::sync::Mutex<crate::access::screen::Screening>>, pub(crate) token_lifetime: Duration, pub(crate) session_lifetime: Duration, /// Origins whose pages may call this node's open endpoints (`api::cors`). @@ -490,6 +493,14 @@ impl AppState { tokio::task::spawn_blocking(move || { let result = { let mut replica = state.doc.blocking_write(); + // A write through the API under a policy this node doesn't know: what + // the others would refuse it can't tell (`access::policy`). + if user.is_some() + && let crate::access::policy::Policy::Unknown(why) = + crate::access::policy::of(&replica.doc) + { + return Err(E::from(StoreError::UnknownPolicy(why))); + } // Checked here, under the lock: the caller's readiness check (if any) // was before a rejoin could swap in a fresh document. if !replica.writable { |
