From 80792cd30416e6a52a80cb52578884ada118f0f8 Mon Sep 17 00:00:00 2001 From: tom27052006 <83423411+tom27052006@users.noreply.github.com> Date: Tue, 14 Jul 2026 15:20:53 +0200 Subject: [PATCH 1/2] Make 2FA remember duration configurable --- .env.template | 3 +++ src/auth.rs | 23 ++++++++++++++++++++++- src/config.rs | 6 ++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 0d922774..c79407a7 100644 --- a/.env.template +++ b/.env.template @@ -587,6 +587,9 @@ ## Note that the checkbox would still be present, but ignored. # DISABLE_2FA_REMEMBER=false ## +## Number of days before a remembered 2FA login expires (min: 1, max: 3650). +# TWO_FACTOR_REMEMBER_DAYS=30 +## ## Authenticator Settings ## Disable authenticator time drifted codes to be valid. ## TOTP codes of the previous and next 30 seconds will be invalid diff --git a/src/auth.rs b/src/auth.rs index 88a59b4b..994e53dd 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -473,13 +473,34 @@ pub fn generate_2fa_remember_claims(device_uuid: DeviceId, user_uuid: UserId) -> let time_now = Utc::now(); TwoFactorRememberClaims { nbf: time_now.timestamp(), - exp: (time_now + TimeDelta::try_days(30).unwrap()).timestamp(), + exp: two_factor_remember_expiration(time_now, CONFIG.two_factor_remember_days()), iss: JWT_2FA_REMEMBER_ISSUER.to_string(), sub: device_uuid, user_uuid, } } +fn two_factor_remember_expiration(time_now: DateTime, remember_days: i64) -> i64 { + (time_now + TimeDelta::try_days(remember_days).expect("TWO_FACTOR_REMEMBER_DAYS is validated")).timestamp() +} + +#[cfg(test)] +mod two_factor_remember_tests { + use chrono::TimeZone; + + use super::*; + + #[test] + fn expiration_uses_configured_number_of_days() { + let time_now = Utc.with_ymd_and_hms(2026, 7, 14, 12, 0, 0).unwrap(); + + assert_eq!( + two_factor_remember_expiration(time_now, 45), + Utc.with_ymd_and_hms(2026, 8, 28, 12, 0, 0).unwrap().timestamp() + ); + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct BasicJwtClaims { // Not before diff --git a/src/config.rs b/src/config.rs index 49281b6c..b148fc69 100644 --- a/src/config.rs +++ b/src/config.rs @@ -705,6 +705,8 @@ make_config! { /// Disable Two-Factor remember |> Enabling this would force the users to use a second factor to login every time. /// Note that the checkbox would still be present, but ignored. disable_2fa_remember: bool, true, def, false; + /// Two-Factor remember duration |> Number of days before a remembered Two-Factor login expires (min: 1, max: 3650). + two_factor_remember_days: i64, true, def, 30; /// Disable authenticator time drifted codes to be valid |> Enabling this only allows the current TOTP code to be valid /// TOTP codes of the previous and next 30 seconds will be invalid. @@ -1209,6 +1211,10 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> { err!("`INVITATION_EXPIRATION_HOURS` has a minimum duration of 1 hour") } + if !(1..=3650).contains(&cfg.two_factor_remember_days) { + err!("`TWO_FACTOR_REMEMBER_DAYS` must be between 1 and 3650 days") + } + // Validate schedule crontab format if !cfg.send_purge_schedule.is_empty() && cfg.send_purge_schedule.parse::().is_err() { err!("`SEND_PURGE_SCHEDULE` is not a valid cron expression") From f60c30fd412522477542895739dbc4cf4cb39d9c Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 14 Jul 2026 17:45:49 +0200 Subject: [PATCH 2/2] Lower maximum 2FA remember duration to 365 days --- .env.template | 2 +- src/config.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.template b/.env.template index c79407a7..bf025d8d 100644 --- a/.env.template +++ b/.env.template @@ -587,7 +587,7 @@ ## Note that the checkbox would still be present, but ignored. # DISABLE_2FA_REMEMBER=false ## -## Number of days before a remembered 2FA login expires (min: 1, max: 3650). +## Number of days before a remembered 2FA login expires (min: 1, max: 365). # TWO_FACTOR_REMEMBER_DAYS=30 ## ## Authenticator Settings diff --git a/src/config.rs b/src/config.rs index b148fc69..9ef31b61 100644 --- a/src/config.rs +++ b/src/config.rs @@ -705,7 +705,7 @@ make_config! { /// Disable Two-Factor remember |> Enabling this would force the users to use a second factor to login every time. /// Note that the checkbox would still be present, but ignored. disable_2fa_remember: bool, true, def, false; - /// Two-Factor remember duration |> Number of days before a remembered Two-Factor login expires (min: 1, max: 3650). + /// Two-Factor remember duration |> Number of days before a remembered Two-Factor login expires (min: 1, max: 365). two_factor_remember_days: i64, true, def, 30; /// Disable authenticator time drifted codes to be valid |> Enabling this only allows the current TOTP code to be valid @@ -1211,8 +1211,8 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> { err!("`INVITATION_EXPIRATION_HOURS` has a minimum duration of 1 hour") } - if !(1..=3650).contains(&cfg.two_factor_remember_days) { - err!("`TWO_FACTOR_REMEMBER_DAYS` must be between 1 and 3650 days") + if !(1..=365).contains(&cfg.two_factor_remember_days) { + err!("`TWO_FACTOR_REMEMBER_DAYS` must be between 1 and 365 days") } // Validate schedule crontab format