diff options
Diffstat (limited to 'src/api/access.rs')
| -rw-r--r-- | src/api/access.rs | 42 |
1 files changed, 36 insertions, 6 deletions
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" } } }) + ); } } |
