diff options
| author | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
| commit | f2487f5a1f897bb5499ffd782562f53967f20606 (patch) | |
| tree | 3e6b64f4ef1ebe1c19e346c2080a5a7afb31ec26 /src/access | |
| parent | c82a62186a8e0a46fd41e08345a2fa3e54ddffe2 (diff) | |
access: keeping the swarm manageable
A write that would leave its own writer unable to manage users
(deleting, disabling or narrowing its entry, removing the registry) is
refused; --protocol-writers can set a registry right that nobody may
manage any more.
Auth plan M1.
Diffstat (limited to 'src/access')
| -rw-r--r-- | src/access/registry.rs | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/access/registry.rs b/src/access/registry.rs index 4b4304a..948e0de 100644 --- a/src/access/registry.rs +++ b/src/access/registry.rs @@ -108,6 +108,14 @@ pub(crate) fn user(doc: &impl ReadDoc, name: &str) -> Option<User> { value.is_object().then(|| User::from_json(&value)) } +/// The users who may manage users: enabled, with `write` on `_continuum/users`. +pub(crate) fn managers(doc: &impl ReadDoc) -> Vec<String> { + names(doc) + .into_iter() + .filter(|name| caps_of(doc, name).allows(Right::Write, &users_dir())) + .collect() +} + /// What user `name` may do: none if it isn't registered (or is disabled). pub(crate) fn caps_of(doc: &impl ReadDoc, name: &str) -> Caps { user(doc, name).map(|user| user.caps()).unwrap_or_default() @@ -301,6 +309,24 @@ mod tests { } #[test] + fn who_may_manage_users() { + let mut doc = Document::new(); + for (name, admin) in [("alice", true), ("bob", false)] { + let entry = entry("x", 0, &first_caps(admin)); + change(&mut doc, |tx| { + store::write_path(tx, &user_path(name), &entry).unwrap() + }); + } + assert_eq!(managers(&doc), vec!["alice"]); + let mut disabled = user_path("alice"); + disabled.push("disabled".to_owned()); + change(&mut doc, |tx| { + store::write_path(tx, &disabled, &json!(true)).unwrap() + }); + assert!(managers(&doc).is_empty()); + } + + #[test] fn concurrent_grants_both_hold() { let mut ours = Document::new(); let entry = entry("x", 0, &[]); |
