From e8e935caf0b8b474d07e30dacf4627200aa0150f Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Thu, 1 Aug 2024 13:09:56 +0100 Subject: [PATCH] feat: [#978] add a config option to disable cheking keys' expiration When the tracker is running in private mode you can disable checking keys' expiration in the configuration with: ```toml [core] private = false [core.private_mode] check_keys_expiration = true ``` All keys will be valid as long as they exist in the database. --- packages/configuration/src/v2/core.rs | 39 +++++++++++++++++++++++++++ src/core/auth.rs | 10 +++---- src/core/mod.rs | 32 ++++++++++++++++++++-- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/packages/configuration/src/v2/core.rs b/packages/configuration/src/v2/core.rs index 09280917..5d6afdee 100644 --- a/packages/configuration/src/v2/core.rs +++ b/packages/configuration/src/v2/core.rs @@ -1,3 +1,4 @@ +use derive_more::{Constructor, Display}; use serde::{Deserialize, Serialize}; use super::network::Network; @@ -32,6 +33,10 @@ pub struct Core { #[serde(default = "Core::default_private")] pub private: bool, + // Configuration specific when the tracker is running in private mode. + #[serde(default = "Core::default_private_mode")] + pub private_mode: Option, + // Tracker policy configuration. #[serde(default = "Core::default_tracker_policy")] pub tracker_policy: TrackerPolicy, @@ -54,6 +59,7 @@ impl Default for Core { listed: Self::default_listed(), net: Self::default_network(), private: Self::default_private(), + private_mode: Self::default_private_mode(), tracker_policy: Self::default_tracker_policy(), tracker_usage_statistics: Self::default_tracker_usage_statistics(), } @@ -85,6 +91,14 @@ impl Core { false } + fn default_private_mode() -> Option { + if Self::default_private() { + Some(PrivateMode::default()) + } else { + None + } + } + fn default_tracker_policy() -> TrackerPolicy { TrackerPolicy::default() } @@ -92,3 +106,28 @@ impl Core { true } } + +/// Configuration specific when the tracker is running in private mode. +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, Constructor, Display)] +pub struct PrivateMode { + /// A flag to disable expiration date for peer keys. + /// + /// When true, if the keys is not permanent the expiration date will be + /// ignored. The key will be accepted even if it has expired. + #[serde(default = "PrivateMode::default_check_keys_expiration")] + pub check_keys_expiration: bool, +} + +impl Default for PrivateMode { + fn default() -> Self { + Self { + check_keys_expiration: Self::default_check_keys_expiration(), + } + } +} + +impl PrivateMode { + fn default_check_keys_expiration() -> bool { + true + } +} diff --git a/src/core/auth.rs b/src/core/auth.rs index 999b4361..fef5b309 100644 --- a/src/core/auth.rs +++ b/src/core/auth.rs @@ -33,7 +33,7 @@ //! //! // And you can later verify it with: //! -//! assert!(auth::verify_key(&expiring_key).is_ok()); +//! assert!(auth::verify_key_expiration(&expiring_key).is_ok()); //! ``` use std::panic::Location; @@ -106,7 +106,7 @@ pub fn generate_key(lifetime: Option) -> PeerKey { /// /// - `Error::KeyExpired` if `auth_key.valid_until` is past the `current_time`. /// - `Error::KeyInvalid` if `auth_key.valid_until` is past the `None`. -pub fn verify_key(auth_key: &PeerKey) -> Result<(), Error> { +pub fn verify_key_expiration(auth_key: &PeerKey) -> Result<(), Error> { let current_time: DurationSinceUnixEpoch = CurrentClock::now(); match auth_key.valid_until { @@ -322,7 +322,7 @@ mod tests { fn should_be_generated_with_a_expiration_time() { let expiring_key = auth::generate_key(Some(Duration::new(9999, 0))); - assert!(auth::verify_key(&expiring_key).is_ok()); + assert!(auth::verify_key_expiration(&expiring_key).is_ok()); } #[test] @@ -336,12 +336,12 @@ mod tests { // Mock the time has passed 10 sec. clock::Stopped::local_add(&Duration::from_secs(10)).unwrap(); - assert!(auth::verify_key(&expiring_key).is_ok()); + assert!(auth::verify_key_expiration(&expiring_key).is_ok()); // Mock the time has passed another 10 sec. clock::Stopped::local_add(&Duration::from_secs(10)).unwrap(); - assert!(auth::verify_key(&expiring_key).is_err()); + assert!(auth::verify_key_expiration(&expiring_key).is_err()); } } } diff --git a/src/core/mod.rs b/src/core/mod.rs index f4cff8da..a8c26540 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -996,7 +996,16 @@ impl Tracker { location: Location::caller(), key: Box::new(key.clone()), }), - Some(key) => auth::verify_key(key), + Some(key) => match self.config.private_mode { + Some(private_mode) => { + if private_mode.check_keys_expiration { + return auth::verify_key_expiration(key); + } + + Ok(()) + } + None => auth::verify_key_expiration(key), + }, } } @@ -1779,8 +1788,9 @@ mod tests { use std::time::Duration; use torrust_tracker_clock::clock::Time; + use torrust_tracker_configuration::v2::core::PrivateMode; - use crate::core::auth; + use crate::core::auth::{self, Key}; use crate::core::tests::the_tracker::private_tracker; use crate::CurrentClock; @@ -1829,6 +1839,24 @@ mod tests { assert!(tracker.verify_auth_key(&expiring_key.key()).await.is_ok()); } + #[tokio::test] + async fn it_should_accept_an_expired_key_when_checking_expiration_is_disabled_in_configuration() { + let mut tracker = private_tracker(); + + tracker.config.private_mode = Some(PrivateMode { + check_keys_expiration: false, + }); + + let past_time = Some(Duration::ZERO); + + let expiring_key = tracker + .add_auth_key(Key::new("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(), past_time) + .await + .unwrap(); + + assert!(tracker.authenticate(&expiring_key.key()).await.is_ok()); + } + #[tokio::test] async fn it_should_fail_verifying_an_unregistered_authentication_key() { let tracker = private_tracker();