From 22d3e8148d30887041a030b93b3e6de3f749a6cd Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 7 Nov 2026 22:35:21 +0100 Subject: access: bans _continuum/banned/: every node refuses the banned node's changes from then on (judged as the ban stood) and leaves its handshakes unanswered. Auth plan M6. --- src/access/rules.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src/access/rules.rs') diff --git a/src/access/rules.rs b/src/access/rules.rs index e151cbb..c061893 100644 --- a/src/access/rules.rs +++ b/src/access/rules.rs @@ -9,7 +9,8 @@ //! * A change without dependencies is an epoch's root: the genesis change, the first a //! document holds, or a remake's snapshot, whose hash is the epoch's ID. Nothing else //! is judged of it: it writes the protocol data it starts with. -//! * Any other is its committer's, a member at its dependencies, or registering itself. +//! * Any other is its committer's, a member at its dependencies, or registering itself, +//! and not banned there (`access::bans`). //! * Protocol data (`_continuum`, `document::meta`): a member's entry and its votes by //! that member only (removing an entry also by a user who may write there); epochs //! and the swarm ID in a root only; a remake's decision by the coordinator its @@ -86,6 +87,9 @@ pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result let Some(node) = change.committer else { return refuse("it names no node".to_owned()); }; + if super::bans::banned(&at, node) { + return refuse(format!("{node} is banned")); + } let own_entry = meta::path(&[meta::MEMBERS, node]); let member = store::read_path(&at, &own_entry).ok().flatten().is_some(); let registering = change @@ -313,6 +317,34 @@ mod tests { assert!(refused(judged(&doc, "a", Some("alice"), &[tokens]))); } + /// A banned node's changes: refused, as the ban stood when they were made. + #[test] + fn banned_nodes() { + let mut doc = swarm(true); + let before = doc.get_heads(); + write(&mut doc, "_continuum/banned/b", json!({"by": "alice"})); + assert!(refused(judged( + &doc, + "b", + None, + &["_continuum/members/b/alive"] + ))); + let touched = paths(&["_continuum/members/b/alive"]); + let earlier = judge( + &doc, + Epoch::GENESIS, + &Change { + hash: ChangeHash([9; 32]), + deps: &before, + seen: &before, + committer: Some("b"), + user: None, + paths: &touched, + }, + ); + assert!(earlier.is_ok()); + } + /// A node that isn't a member may only register itself. #[test] fn strangers_register_themselves_only() { -- cgit v1.3.1