diff options
| author | tv <tv@krebsco.de> | 2026-11-08 16:15:39 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-08 17:36:11 +0100 |
| commit | 63c2272a4feb890277ed1362b48a3524d0b07165 (patch) | |
| tree | d69b836320a72f70ba15b10aec6c32b578f1f9f8 /src/access/envelope.rs | |
| parent | a7c70346b448f493991df1e035beaa4bde113b4f (diff) | |
users: a user can't remove its own last key
A user managing its own keys (1168) could remove the last, and then
neither sign nor log in by key. It can't now: DELETE /auth/keys/{id}
of the last answers 409, the rules take a user's change of its own keys
only with one left after it, and under a strict policy its own entry
signed only with one key at least. One who may manage users still may.
Diffstat (limited to 'src/access/envelope.rs')
| -rw-r--r-- | src/access/envelope.rs | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/access/envelope.rs b/src/access/envelope.rs index 7cd0083..e99a06e 100644 --- a/src/access/envelope.rs +++ b/src/access/envelope.rs @@ -218,8 +218,8 @@ pub(crate) fn check( } /// Whether `payload`, signed by its user (`user`, enabled), is that user's own entry -/// with only its keys changed from the one at `path` in `doc`: a user manages its own -/// keys, whatever else it may do. +/// with only its keys changed from the one at `path` in `doc`, one left at least: a user +/// manages its own keys, whatever else it may do. fn own_keys_only( doc: &impl ReadDoc, payload: &Payload, @@ -232,6 +232,15 @@ fn own_keys_only( let Ok(Some(mut before)) = store::read_plain(doc, path) else { return false; }; + // One key left at least: a user can't sign, nor log in by key, without one. + if payload + .value + .get("keys") + .and_then(JsonValue::as_object) + .is_none_or(serde_json::Map::is_empty) + { + return false; + } let mut after = payload.value.clone(); for entry in [&mut before, &mut after] { match entry.as_object_mut() { @@ -355,6 +364,10 @@ mod tests { assert!(check(&doc, &signed_as("alice", more), &path(at), None).is_err()); // bob, holding the same key, for alice: not his entry. assert!(check(&doc, &signed_as("bob", rekeyed), &path(at), None).is_err()); + // Her keys all gone: no. + let mut keyless = entry.clone(); + keyless["keys"] = json!({}); + assert!(check(&doc, &signed_as("alice", keyless), &path(at), None).is_err()); } #[test] |
