Browse Source

Merge 5dcbb1c7d4 into 0cefa4cca7

pull/7421/merge
Tom 6 days ago
committed by GitHub
parent
commit
8054a2ac90
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      .env.template
  2. 23
      src/auth.rs
  3. 28
      src/config.rs

3
.env.template

@ -610,6 +610,9 @@
## Note that the checkbox would still be present, but ignored. ## Note that the checkbox would still be present, but ignored.
# DISABLE_2FA_REMEMBER=false # DISABLE_2FA_REMEMBER=false
## ##
## Number of days before a remembered 2FA login expires (min: 1, max: 90).
# TWO_FACTOR_REMEMBER_DAYS=30
##
## Authenticator Settings ## Authenticator Settings
## Disable authenticator time drifted codes to be valid. ## Disable authenticator time drifted codes to be valid.
## TOTP codes of the previous and next 30 seconds will be invalid ## TOTP codes of the previous and next 30 seconds will be invalid

23
src/auth.rs

@ -474,13 +474,34 @@ pub fn generate_2fa_remember_claims(device_uuid: DeviceId, user_uuid: UserId) ->
let time_now = Utc::now(); let time_now = Utc::now();
TwoFactorRememberClaims { TwoFactorRememberClaims {
nbf: time_now.timestamp(), 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(), iss: JWT_2FA_REMEMBER_ISSUER.to_string(),
sub: device_uuid, sub: device_uuid,
user_uuid, user_uuid,
} }
} }
fn two_factor_remember_expiration(time_now: DateTime<Utc>, 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)] #[derive(Debug, Serialize, Deserialize)]
pub struct BasicJwtClaims { pub struct BasicJwtClaims {
// Not before // Not before

28
src/config.rs

@ -716,6 +716,8 @@ make_config! {
/// Disable Two-Factor remember |> Enabling this would force the users to use a second factor to login every time. /// 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. /// Note that the checkbox would still be present, but ignored.
disable_2fa_remember: bool, true, def, false; disable_2fa_remember: bool, true, def, false;
/// Two-Factor remember duration |> Number of days before a remembered Two-Factor login expires (min: 1, max: 90).
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 /// 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. /// TOTP codes of the previous and next 30 seconds will be invalid.
@ -1237,6 +1239,10 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> {
err!("`INVITATION_EXPIRATION_HOURS` has a minimum duration of 1 hour") err!("`INVITATION_EXPIRATION_HOURS` has a minimum duration of 1 hour")
} }
if !(1..=90).contains(&cfg.two_factor_remember_days) {
err!("`TWO_FACTOR_REMEMBER_DAYS` must be between 1 and 90 days")
}
// Validate schedule crontab format // Validate schedule crontab format
if !cfg.send_purge_schedule.is_empty() && cfg.send_purge_schedule.parse::<Schedule>().is_err() { if !cfg.send_purge_schedule.is_empty() && cfg.send_purge_schedule.parse::<Schedule>().is_err() {
err!("`SEND_PURGE_SCHEDULE` is not a valid cron expression") err!("`SEND_PURGE_SCHEDULE` is not a valid cron expression")
@ -1858,3 +1864,25 @@ handlebars::handlebars_helper!(webver: | web_vault_version: String |
handlebars::handlebars_helper!(vwver: | vw_version: String | handlebars::handlebars_helper!(vwver: | vw_version: String |
semver::VersionReq::parse(&vw_version).expect("Invalid Vaultwarden version compare string").matches(&VW_VERSION) semver::VersionReq::parse(&vw_version).expect("Invalid Vaultwarden version compare string").matches(&VW_VERSION)
); );
#[cfg(test)]
mod tests {
use super::*;
fn config_with_two_factor_remember_days(days: i64) -> ConfigItems {
ConfigBuilder {
database_url: Some("sqlite://:memory:".to_owned()),
two_factor_remember_days: Some(days),
..Default::default()
}
.build()
}
#[test]
fn two_factor_remember_days_are_limited_to_ninety() {
assert!(validate_config(&config_with_two_factor_remember_days(90), false).is_ok());
let error = validate_config(&config_with_two_factor_remember_days(91), false).unwrap_err();
assert_eq!(format!("{error:?}"), "`TWO_FACTOR_REMEMBER_DAYS` must be between 1 and 90 days");
}
}

Loading…
Cancel
Save