From a3e936154e07ba3b95157d26ffeae9364f3d5cef Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 7 Nov 2026 22:35:21 +0100 Subject: access: logouts apart from users' entries _continuum/logouts/ holds when a user's tokens were last revoked, written by the user itself or by one who may manage users, so users' entries can be signed by their managers alone. Auth plan M7. --- src/access/registry.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src/access/registry.rs') diff --git a/src/access/registry.rs b/src/access/registry.rs index eb7919c..caa263d 100644 --- a/src/access/registry.rs +++ b/src/access/registry.rs @@ -67,7 +67,8 @@ pub(crate) struct User { pub(crate) caps: BTreeMap, pub(crate) disabled: bool, /// Tokens issued before (Unix ms) are no longer taken (`token::verify`): how all - /// of a user's tokens are revoked at once. + /// of a user's tokens are revoked at once, kept apart from its entry + /// (`logouts_path`), as the user writes it itself. pub(crate) tokens_not_before: u64, /// Its keys (`keys/`, `authorized_keys` lines, `access::sshsig`): what it signs /// values with (`access::envelope`) and logs in with. One that doesn't read is left @@ -100,11 +101,7 @@ impl User { disabled: value .get("disabled") .is_some_and(|disabled| disabled != &JsonValue::Bool(false)), - // A damaged one revokes every token. - tokens_not_before: match value.get("tokensNotBefore") { - None => 0, - Some(at) => at.as_u64().unwrap_or(u64::MAX), - }, + tokens_not_before: 0, keys: value .get("keys") .and_then(JsonValue::as_object) @@ -132,7 +129,21 @@ impl User { /// The entry of user `name`, if it has one. pub(crate) fn user(doc: &impl ReadDoc, name: &str) -> Option { let value = store::read_path(doc, &user_path(name)).ok()??; - value.is_object().then(|| User::from_json(&value)) + let mut user = value.is_object().then(|| User::from_json(&value))?; + // A damaged one revokes every token. + user.tokens_not_before = match store::read_path(doc, &logouts_path(name)) { + Ok(None) => 0, + Ok(Some(at)) => at.as_u64().unwrap_or(u64::MAX), + Err(_) => u64::MAX, + }; + Some(user) +} + +/// Where user `name`'s tokens were last revoked (Unix ms: those issued before aren't +/// taken any more), written by the user itself (`POST /auth/logout`) or by one who may +/// manage users. +pub(crate) fn logouts_path(name: &str) -> Vec { + meta::path(&[meta::LOGOUTS, name]) } /// The users who may manage users: enabled, with `write` on `_continuum/users`. -- cgit v1.3.1