aboutsummaryrefslogtreecommitdiffstats
path: root/src/access/envelope.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-08 16:15:39 +0000
committertv <tv@krebsco.de>2026-11-08 17:36:11 +0100
commit63c2272a4feb890277ed1362b48a3524d0b07165 (patch)
treed69b836320a72f70ba15b10aec6c32b578f1f9f8 /src/access/envelope.rs
parenta7c70346b448f493991df1e035beaa4bde113b4f (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.rs17
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]