1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
//! The swarm's write protection policy (`_continuum/access/policy`): whether every node
//! judges received changes by rules by path before applying them (`access::screen`,
//! `access::rules`). Absent, nobody does: what exists keeps working as it did. Written
//! by a user who may write protocol data, as any of it.
//!
//! `{"version": 1, "signatures": "optional"}`: rules enforced; a change is its claimed
//! committer's whether or not a signature proves it (`document::signatures`). A policy
//! this node doesn't know (another version, or a setting it lacks) stops it from taking
//! writes through the API, and it receives without judging: it can't judge as the
//! others do, so it writes nothing they might refuse, until it is upgraded.
use serde_json::Value as JsonValue;
use crate::document::{ReadDoc, meta, store};
/// The policy versions this node knows.
pub(crate) const VERSION: u64 = 1;
/// Where the policy is.
pub(crate) fn path() -> Vec<String> {
meta::path(&[meta::ACCESS, "policy"])
}
/// What the policy says.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum Policy {
/// None: changes aren't judged.
Open,
/// Rules by path enforced.
Enforced,
/// One this node doesn't know, and why.
Unknown(String),
}
impl Policy {
pub(crate) fn enforced(&self) -> bool {
matches!(self, Policy::Enforced)
}
}
/// The policy `doc` holds.
pub(crate) fn of(doc: &impl ReadDoc) -> Policy {
let value = match store::read_path(doc, &path()) {
Ok(Some(value)) => value,
Ok(None) => return Policy::Open,
Err(error) => return Policy::Unknown(format!("it doesn't read: {error}")),
};
let version = value.get("version").and_then(JsonValue::as_u64);
if version != Some(VERSION) {
return Policy::Unknown(format!(
"version {}, this node knows {VERSION}",
value
.get("version")
.map_or("none".to_owned(), JsonValue::to_string)
));
}
match value.get("signatures").and_then(JsonValue::as_str) {
None | Some("optional") => Policy::Enforced,
Some(other) => Policy::Unknown(format!("signatures {other:?}")),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::document::Document;
use crate::document::testing::change;
use serde_json::json;
fn with(policy: JsonValue) -> Policy {
let mut doc = Document::new();
change(&mut doc, |doc| {
store::write_path(doc, &path(), &policy).unwrap();
});
of(&doc)
}
#[test]
fn what_the_policy_says() {
assert_eq!(of(&Document::new()), Policy::Open);
assert_eq!(with(json!({"version": 1})), Policy::Enforced);
assert_eq!(
with(json!({"version": 1, "signatures": "optional"})),
Policy::Enforced
);
assert!(matches!(with(json!({"version": 2})), Policy::Unknown(_)));
assert!(matches!(
with(json!({"version": 1, "signatures": "sometimes"})),
Policy::Unknown(_)
));
assert!(matches!(with(json!("on")), Policy::Unknown(_)));
}
}
|