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 | de12c862b3f4e69290c8e93b3b4520024ba458f6 (patch) | |
| tree | 0f56381fa62948a7cb11b03fed6075fd85e7e649 /src/access | |
| parent | 3a9d9da74f55395ead20f3915ed04639e37b2f03 (diff) | |
access: the users endpoints
/admin/users: list, add (one or several), remove, disable, grant and
revoke capabilities; each one change, refused if it would lock its
writer out. Capabilities as the store's paths name them.
Auth plan M1.
Diffstat (limited to 'src/access')
| -rw-r--r-- | src/access/registry.rs | 54 |
1 files changed, 20 insertions, 34 deletions
diff --git a/src/access/registry.rs b/src/access/registry.rs index 3006b31..9eafc82 100644 --- a/src/access/registry.rs +++ b/src/access/registry.rs @@ -33,7 +33,7 @@ pub(crate) fn user_path(name: &str) -> Vec<String> { } /// Whether the swarm has a registry: until it has, every user a node lets in may do -/// what all could before (`docs/access.md`, An existing swarm). +/// everything but write protocol data (`docs/access.md`, A swarm without a registry). pub(crate) fn exists(doc: &impl ReadDoc) -> bool { store::is_map(doc, &users_dir()) } @@ -141,28 +141,23 @@ pub(crate) fn capability(by: &str, since: u64, path: &[String], rights: &[Right] }) } -/// The first users of a new swarm, as its genesis node records them (`first_users`): -/// each name, and whether it may do everything (protocol data and managing users -/// included), not only read and write the swarm's data. -pub(crate) type FirstUsers = Vec<(String, bool)>; +/// The first users of a new swarm, as its genesis node records them (`first_users`), +/// each with everything (`all_caps`). +pub(crate) type FirstUsers = Vec<String>; -/// The first users of a new swarm, from the genesis node's `--bootstrap-users`: each may -/// do everything. None without: then the swarm has no registry, and its users are all -/// alike, as before there were registries (`access.md`). +/// The first users of a new swarm, from the genesis node's `--bootstrap-users`, sorted. +/// None without: then the swarm has no registry, and its users are all alike +/// (`access.md`, A swarm without a registry). pub(crate) fn first_users(bootstrap_users: &[String]) -> FirstUsers { let users: std::collections::BTreeSet<&String> = bootstrap_users.iter().collect(); - users.into_iter().map(|name| (name.clone(), true)).collect() + users.into_iter().cloned().collect() } -/// The capabilities of a first user (`first_users`): the swarm's data, and for one who -/// may do everything protocol data too. -pub(crate) fn first_caps(admin: bool) -> Vec<(Vec<String>, &'static [Right])> { +/// Everything, as a first user has it (`first_users`): the swarm's data and protocol +/// data (managing users included), to read and write. +pub(crate) fn all_caps() -> Vec<(Vec<String>, &'static [Right])> { const BOTH: &[Right] = &[Right::Read, Right::Write]; - let mut caps = vec![(Vec::new(), BOTH)]; - if admin { - caps.push((meta::path(&[]), BOTH)); - } - caps + vec![(Vec::new(), BOTH), (meta::path(&[]), BOTH)] } /// A random ID for a capability (8 bytes, hex): concurrent grants don't collide. @@ -250,37 +245,28 @@ mod tests { let names = |list: &[&str]| list.iter().map(|n| (*n).to_owned()).collect::<Vec<_>>(); assert_eq!( first_users(&names(&["bob", "alice", "bob"])), - vec![("alice".to_owned(), true), ("bob".to_owned(), true)] + names(&["alice", "bob"]) ); // Without bootstrap users, no registry. assert!(first_users(&[]).is_empty()); - let admin = Caps::new( - first_caps(true) - .into_iter() - .map(|(path, rights)| { - serde_json::from_value(capability("x", 0, &path, rights)).unwrap() - }) - .collect(), - ); - assert!(admin.allows(Right::Write, &path("_continuum/users/x"))); - assert!(admin.allows(Right::Write, &path("accounts"))); - let user = Caps::new( - first_caps(false) + let all = Caps::new( + all_caps() .into_iter() .map(|(path, rights)| { serde_json::from_value(capability("x", 0, &path, rights)).unwrap() }) .collect(), ); - assert!(user.allows(Right::Write, &path("accounts"))); - assert!(!user.allows(Right::Read, &path("_continuum"))); + assert!(all.allows(Right::Write, &path("_continuum/users/x"))); + assert!(all.allows(Right::Write, &path("accounts"))); } #[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)); + const DATA: &[Right] = &[Right::Read, Right::Write]; + for (name, caps) in [("alice", all_caps()), ("bob", vec![(Vec::new(), DATA)])] { + let entry = entry("x", 0, &caps); change(&mut doc, |tx| { store::write_path(tx, &user_path(name), &entry).unwrap() }); |
