diff options
| author | tv <tv@krebsco.de> | 2026-11-08 09:33:41 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-08 10:36:24 +0100 |
| commit | f713fe668c29ecd60df547d989b0ace40cfe4da0 (patch) | |
| tree | 329d4a0b67be2a214427d7bfe878649b3a4fc916 /src | |
| parent | b758c93a1887ea36b0f52ccd4a6f9824de77d819 (diff) | |
access: a forgotten node cancels its own record
A node forgotten swarm-wide while alive cancels its forget record with
a change naming no user; the rules judged _continuum/forgotten by the
registry alone, so every node refused the cancellation and everything
the node wrote after it. A node may now write its own
_continuum/forgotten/<id>, as it may its member entry.
Review finding 4.
Diffstat (limited to 'src')
| -rw-r--r-- | src/access/rules.rs | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/src/access/rules.rs b/src/access/rules.rs index 2aed4b8..96ee9d4 100644 --- a/src/access/rules.rs +++ b/src/access/rules.rs @@ -15,7 +15,8 @@ //! 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 //! proposal names, the rest of a record by any member; a user's tokens revoked by that -//! user too (logging out); the rest by a user who may write there. +//! user too (logging out); a member's forget record by that member too (cancelling it, +//! alive); the rest by a user who may write there. //! * User data: by a user who may write there. //! * Under a strict policy (`access::policy`), the values their users sign //! (`access::envelope`) only as they signed them (`signed_values`). @@ -134,6 +135,8 @@ pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result (Some(meta::EPOCHS | meta::SWARM), _) => false, // Logging out: a user revokes its own tokens (`POST /auth/logout`). (Some(meta::LOGOUTS), Some(owner)) => change.user == Some(owner) || user_may(path), + // A node forgotten while alive cancels its own record (`swarm::peer::forget`). + (Some(meta::FORGOTTEN), Some(owner)) => owner == node || user_may(path), (Some(meta::REMAKES), Some(id)) => match path.get(3).map(String::as_str) { // Its coordinator's; or a record carried into a new epoch whole, by the // node that coordinated it (`remake::switch`): its proposal written with it. @@ -431,6 +434,10 @@ mod tests { let tokens = "_continuum/logouts/bob"; assert!(judged(&doc, "a", Some("bob"), &[tokens]).is_ok()); assert!(refused(judged(&doc, "a", Some("alice"), &[tokens]))); + // A forget record: cancelled by the node it names, not by another. + let forgotten = "_continuum/forgotten/a"; + assert!(judged(&doc, "a", None, &[forgotten]).is_ok()); + assert!(refused(judged(&doc, "b", None, &[forgotten]))); } /// A banned node's changes: refused, as the ban stood when they were made. |
