From 09ba5e4521ee2649f113da281ad150c08e48f9dd Mon Sep 17 00:00:00 2001 From: Johanna Larsson Date: Sat, 5 Sep 2026 14:16:31 +0100 Subject: [PATCH] Allow disabling TOTP even if last session was legacy This removes the `require_legacy_session_mfa` call on the TOTP disable path. It looks at the last session, which isn't really relevant, and we're getting a fresh TOTP from the form anyway, which should be enough proof to allow disabling TOTP. The way I bumped into this was having a "bot account" log in with app password on some app on a schdule, triggering lots of warning emails. So I tried to disable TOTP to stop the flood and wasn't allowed. --- crates/tranquil-api/src/server/totp.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/tranquil-api/src/server/totp.rs b/crates/tranquil-api/src/server/totp.rs index 2ddbdfc..02b31d8 100644 --- a/crates/tranquil-api/src/server/totp.rs +++ b/crates/tranquil-api/src/server/totp.rs @@ -6,8 +6,8 @@ use tranquil_pds::api::error::{ApiError, DbResultExt}; use tranquil_pds::auth::{ Active, Auth, decrypt_totp_secret, encrypt_totp_secret, generate_backup_codes, generate_qr_png_base64, generate_totp_secret, generate_totp_uri, hash_backup_code, - is_backup_code_format, require_legacy_session_mfa, verify_backup_code, verify_password_mfa, - verify_totp_code, verify_totp_mfa, + is_backup_code_format, verify_backup_code, verify_password_mfa, verify_totp_code, + verify_totp_mfa, }; use tranquil_pds::rate_limit::{TotpVerifyLimit, check_user_rate_limit_with_message}; use tranquil_pds::state::AppState; @@ -163,11 +163,9 @@ pub async fn disable_totp( auth: Auth, Json(input): Json, ) -> Result, ApiError> { - let session_mfa = require_legacy_session_mfa(&state, &auth).await?; - let _rate_limit = check_user_rate_limit_with_message::( &state, - session_mfa.did(), + auth.did.as_str(), "Too many verification attempts. Please try again in a few minutes.", ) .await?; @@ -184,7 +182,7 @@ pub async fn disable_totp( tranquil_pds::auth::legacy_2fa::clear_challenge(state.cache.as_ref(), &auth.did).await; - info!(did = %session_mfa.did(), "TOTP disabled (verified via {} and {})", password_mfa.method(), totp_mfa.method()); + info!(did = %password_mfa.did(), "TOTP disabled (verified via {} and {})", password_mfa.method(), totp_mfa.method()); Ok(Json(EmptyResponse {})) }