aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/access')
-rw-r--r--src/access/rules.rs37
-rw-r--r--src/access/screen.rs5
2 files changed, 40 insertions, 2 deletions
diff --git a/src/access/rules.rs b/src/access/rules.rs
index 96ee9d4..185996a 100644
--- a/src/access/rules.rs
+++ b/src/access/rules.rs
@@ -24,7 +24,8 @@
//! declared (`sealed_values`).
//!
//! In a swarm without a user registry (`access::registry`), whatever a user would need,
-//! any member may.
+//! any member may. A change written while the document had no policy (at its
+//! dependencies) is judged by none: the rules hold from the policy on.
use std::collections::BTreeSet;
@@ -92,6 +93,12 @@ pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result
};
}
let at = At::new(doc, change.seen).ok_or(Refusal::Unready)?;
+ // Written while the document had no policy (or one this node doesn't know): judged
+ // as it was then, by none. History from before the policy stays as it is.
+ let policy = super::policy::of(&at);
+ if !policy.enforced() {
+ return Ok(());
+ }
let refuse = |why: String| Err(Refusal::Rule(why));
let Some(node) = change.committer else {
return refuse("it names no node".to_owned());
@@ -161,7 +168,7 @@ pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result
return refuse(format!("{} may not write {}", who(change), shown(path)));
}
}
- if super::policy::of(&at).strict() {
+ if policy.strict() {
signed_values(&at, change.ops).or_else(refuse)?;
}
let declared = super::sealed::declared(&at);
@@ -332,6 +339,7 @@ mod tests {
fn swarm(users: bool) -> Document {
let mut doc = Document::new();
write(&mut doc, "_continuum/swarm", json!("s"));
+ write(&mut doc, "_continuum/access/policy", json!({"version": 1}));
write(&mut doc, "_continuum/members/a", json!({"since": 1}));
write(&mut doc, "_continuum/members/b", json!({"since": 1}));
write(
@@ -708,6 +716,31 @@ mod tests {
assert!(judged(vec![op("notes/x", Action::PutString("plain".to_owned()))]).is_ok());
}
+ /// Written before the policy: judged by none, whatever it does; from the policy on,
+ /// by the rules.
+ #[test]
+ fn before_the_policy() {
+ let mut doc = Document::new();
+ write(&mut doc, "_continuum/swarm", json!("s"));
+ write(&mut doc, "_continuum/members/a", json!({"since": 1}));
+ write(
+ &mut doc,
+ "_continuum/users/alice",
+ registry::entry("a", 1, &[]),
+ );
+ assert!(judged(&doc, "stranger", Some("mallory"), &["notes/x"]).is_ok());
+ write(&mut doc, "_continuum/access/policy", json!({"version": 1}));
+ assert!(refused(judged(
+ &doc,
+ "stranger",
+ Some("mallory"),
+ &["notes/x"]
+ )));
+ // A policy this node doesn't know: judged by none either.
+ write(&mut doc, "_continuum/access/policy", json!({"version": 9}));
+ assert!(judged(&doc, "stranger", Some("mallory"), &["notes/x"]).is_ok());
+ }
+
/// Roots: the first change of a swarm's first epoch, a later epoch's snapshot.
#[test]
fn roots() {
diff --git a/src/access/screen.rs b/src/access/screen.rs
index 8d23b47..35a2af7 100644
--- a/src/access/screen.rs
+++ b/src/access/screen.rs
@@ -579,6 +579,11 @@ mod tests {
};
transact(&mut theirs, UnixMillis(1), &writer, |doc| {
store::write_path(doc, &path("_continuum/swarm"), &json!("s"))?;
+ store::write_path(
+ doc,
+ &path("_continuum/access/policy"),
+ &json!({"version": 1}),
+ )?;
store::write_path(doc, &path("_continuum/users/alice"), &alice)
})
.unwrap();