From cfc685ec4777388c309d0ef69fcd7e89dd617b32 Mon Sep 17 00:00:00 2001 From: tom27052006 <83423411+tom27052006@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:30:54 +0200 Subject: [PATCH] Report admin TOTP source honestly (environment vs config) `admin_totp_status()` now checks the environment first and reports "config" instead of "enrolled", since a secret written to `config.json` by hand is indistinguishable from one enrolled via the admin page. This also fixes the case where the secret is set in both env and config: it is now correctly reported as not removable from the admin page, because the environment value stays effective. --- src/config.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index a1a508ad..9cb5ad57 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1619,15 +1619,22 @@ impl Config { self.update_config(builder, false).await } - /// Returns whether admin page TOTP is enabled, and whether the secret was enrolled - /// via the admin page ("enrolled") or comes from the environment ("environment"). + /// Returns whether admin page TOTP is active, and where the secret comes from: + /// - `"environment"`: set via the `ADMIN_TOTP_SECRET` env var; it can only be changed + /// there and therefore cannot be disabled from the admin page. + /// - `"config"`: present in the saved config file; it can be managed from the admin page. + /// A secret written to the config file by hand is indistinguishable from one enrolled + /// via the admin page, so both are reported as `"config"`. + /// + /// The environment is checked first: if the secret is set there it stays effective even + /// after removing a (stale) copy from the config file, so it must not be reported as removable. pub fn admin_totp_status(&self) -> (bool, &'static str) { let inner = self.inner.read().unwrap(); let is_set = |v: &Option| v.as_deref().is_some_and(|s| !s.trim().is_empty()); - if is_set(&inner._usr.admin_totp_secret) { - (true, "enrolled") - } else if is_set(&inner._env.admin_totp_secret) { + if is_set(&inner._env.admin_totp_secret) { (true, "environment") + } else if is_set(&inner._usr.admin_totp_secret) { + (true, "config") } else { (false, "none") }