aboutsummaryrefslogtreecommitdiffstats
path: root/src/document
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-07 22:35:21 +0100
committertv <tv@krebsco.de>2026-11-07 22:35:21 +0100
commitf44fbf5b93269bb3573e8a2701e70ab0d7613153 (patch)
tree32915998f6e797afcc13f485ccde66bac0e94150 /src/document
parent389b11b597b6bf60f120b190002bbb76fff28dbf (diff)
access: the policy enforced
_continuum/access/policy ({"version": 1}) has every node screen every change it receives, on every path changes come in. A policy a node doesn't know stops its writes through the API. GET /admin/refused. Auth plan M6.
Diffstat (limited to 'src/document')
-rw-r--r--src/document/store.rs6
-rw-r--r--src/document/sync.rs10
2 files changed, 16 insertions, 0 deletions
diff --git a/src/document/store.rs b/src/document/store.rs
index 31c4824..778307f 100644
--- a/src/document/store.rs
+++ b/src/document/store.rs
@@ -175,6 +175,12 @@ pub(crate) enum StoreError {
/// (`Replica::writable`).
#[error("the node is rejoining a newer epoch; writes are refused until it is done")]
Rejoining,
+ /// The swarm's write protection policy is one this node doesn't know
+ /// (`access::policy`): no writes through the API until it is upgraded.
+ #[error(
+ "the swarm's policy (_continuum/access/policy) is one this node doesn't know ({0}); upgrade it to write"
+ )]
+ UnknownPolicy(String),
#[error(transparent)]
Doc(#[from] automerge::AutomergeError),
#[error(transparent)]
diff --git a/src/document/sync.rs b/src/document/sync.rs
index 8cb740b..f124ee8 100644
--- a/src/document/sync.rs
+++ b/src/document/sync.rs
@@ -22,6 +22,16 @@ use crate::transport::SyncPayload;
/// A sync message from a peer, decoded (`decode`), to apply (`SyncSession::receive`).
pub(crate) struct Received(sync::Message);
+impl Received {
+ /// The changes it carries, as their chunks, taken out of it: applied otherwise
+ /// (`access::screen`), what is left of it says what the peer has and needs.
+ pub(crate) fn take_changes(&mut self) -> Vec<u8> {
+ let bytes = self.0.changes.iter().flatten().copied().collect();
+ self.0.changes = sync::ChunkList::empty();
+ bytes
+ }
+}
+
/// The changes none of the others depend on, sorted as heads are (`get_heads`).
fn tips<'a>(
changes: impl Iterator<