aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/access.md4
-rw-r--r--src/api/access.rs42
2 files changed, 39 insertions, 7 deletions
diff --git a/docs/access.md b/docs/access.md
index 1385950..3877dff 100644
--- a/docs/access.md
+++ b/docs/access.md
@@ -70,7 +70,9 @@ change to it counts on a node as soon as it has reached it.
sees the keys on the way to what it may read, as a directory one may pass through
but not list (a capability on `servers/eu` shows `servers` with `eu` alone in it),
and nothing else; a list on the way is left out whole, as its items have no paths of
- their own. Native forms (`text/plain` of a map, a counter as its own type) only of
+ their own. A shallow read (`?shallow=true`) shows such a map as a map and no more (no
+ size), and nothing beside the way: a scalar at a `*` no capability covers stays
+ hidden. Native forms (`text/plain` of a map, a counter as its own type) only of
what it may read whole. What a write answers with is what was written. A stream
shows what the user could read when it opened.
* **Protocol data** is in the store too, under `_continuum`: `read` and `write` on it
diff --git a/src/api/access.rs b/src/api/access.rs
index 11daf83..6d26139 100644
--- a/src/api/access.rs
+++ b/src/api/access.rs
@@ -146,18 +146,34 @@ pub(crate) fn prune(
}
/// A shallow read of `path` (`store::read_shallow`), its `entries` only those `access`
-/// lets its user read at least partly.
+/// lets its user read at least partly. One it may read only partly is only a way
+/// through to what it may: a map, shown as no more than that (no size); anything else
+/// there (a scalar no capability covers, a list, as a deep read leaves it out) isn't
+/// shown at all.
pub(crate) fn prune_shallow(mut value: JsonValue, path: &[String], access: &Access) -> JsonValue {
if access.visible(path) == Visible::All {
return value;
}
if let Some(entries) = value.get_mut("entries").and_then(JsonValue::as_object_mut) {
let mut child = path.to_vec();
- entries.retain(|key, _| {
+ entries.retain(|key, entry| {
child.push(key.clone());
- let visible = access.visible(&child) != Visible::Nothing;
+ let visible = access.visible(&child);
child.pop();
- visible
+ match visible {
+ Visible::All => true,
+ Visible::Nothing => false,
+ Visible::Partly => {
+ let way = entry
+ .get("type")
+ .and_then(JsonValue::as_str)
+ .is_some_and(|kind| kind == "map");
+ if way {
+ *entry = serde_json::json!({ "type": "map" });
+ }
+ way
+ }
+ }
});
let size = entries.len();
value["size"] = size.into();
@@ -558,12 +574,26 @@ mod tests {
#[test]
fn a_shallow_read_lists_the_way() {
let read = json!({ "type": "map", "size": 3,
- "entries": { "a": {}, "b": {}, "_continuum": {} } });
+ "entries": { "a": { "type": "map", "size": 4 }, "b": {},
+ "_continuum": { "type": "map", "size": 9 } } });
let reader = caps(&[("a/x", &["read"])]);
assert_eq!(
prune_shallow(read.clone(), &[], &reader),
- json!({ "type": "map", "size": 1, "entries": { "a": {} } })
+ json!({ "type": "map", "size": 1, "entries": { "a": { "type": "map" } } })
);
assert_eq!(prune_shallow(read.clone(), &[], &Access::Everything), read);
+ // At a `*`: a scalar beside the way, which no capability covers, isn't shown;
+ // what the user may read is, whole.
+ let data = json!({ "type": "map", "size": 3, "entries": {
+ "count": { "type": "number", "size": 8, "value": 42 },
+ "x": { "type": "map", "size": 2 },
+ "public": { "type": "string", "size": 2, "value": "hi" } } });
+ let wildcard = caps(&[("data/*/public", &["read"]), ("data/public", &["read"])]);
+ assert_eq!(
+ prune_shallow(data, &path("data"), &wildcard),
+ json!({ "type": "map", "size": 2, "entries": {
+ "x": { "type": "map" },
+ "public": { "type": "string", "size": 2, "value": "hi" } } })
+ );
}
}