Skip to content

Commit

Permalink
refactor: [torrust#979] move logic from framework controller to domai…
Browse files Browse the repository at this point in the history
…n service

This is only the first step. The tracker has too much reponsabilities.
We should extract new domain/app services pat least per context.

This could be moved to a new "keys" service.
  • Loading branch information
josecelano committed Jul 31, 2024
1 parent cb565b4 commit d361190
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ use std::panic::Location;
use torrust_tracker_located_error::LocatedError;
use torrust_tracker_primitives::info_hash::InfoHash;

use super::auth::ParseKeyError;
use super::databases;

/// Authentication or authorization error returned by the core `Tracker`
#[derive(thiserror::Error, Debug, Clone)]
pub enum Error {
Expand All @@ -20,6 +23,7 @@ pub enum Error {
key: super::auth::Key,
source: LocatedError<'static, dyn std::error::Error + Send + Sync>,
},

#[error("The peer is not authenticated, {location}")]
PeerNotAuthenticated { location: &'static Location<'static> },

Expand All @@ -30,3 +34,22 @@ pub enum Error {
location: &'static Location<'static>,
},
}

/// Errors related to peers keys.
#[allow(clippy::module_name_repetitions)]
#[derive(thiserror::Error, Debug, Clone)]
pub enum PeerKeyError {
#[error("Invalid peer key duration: {seconds_valid:?}, is not valid")]
DurationOverflow { seconds_valid: u64 },

#[error("Invalid key: {key}")]
InvalidKey {
key: String,
source: LocatedError<'static, ParseKeyError>,
},

#[error("Can't persist key: {source}")]
DatabaseError {
source: LocatedError<'static, databases::error::Error>,
},
}
78 changes: 78 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,12 @@ use std::time::Duration;
use auth::PeerKey;
use databases::driver::Driver;
use derive_more::Constructor;
use error::PeerKeyError;
use tokio::sync::mpsc::error::SendError;
use torrust_tracker_clock::clock::Time;
use torrust_tracker_configuration::v2::database;
use torrust_tracker_configuration::{AnnouncePolicy, Core, TORRENT_PEERS_LIMIT};
use torrust_tracker_located_error::Located;
use torrust_tracker_primitives::info_hash::InfoHash;
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics;
Expand All @@ -472,6 +474,7 @@ use self::auth::Key;
use self::error::Error;
use self::torrent::Torrents;
use crate::core::databases::Database;
use crate::servers::apis::v1::context::auth_key::forms::AddKeyForm;
use crate::CurrentClock;

/// The domain layer tracker service.
Expand Down Expand Up @@ -793,6 +796,81 @@ impl Tracker {
}
}

/// Adds new peer keys to the tracker.
///
/// Keys can be pre-generated or randomly created. They can also be permanent or expire.
///
/// # Errors
///
/// Will return an error if:
///
/// - The key duration overflows the duration type maximum value.
/// - The provided pre-generated key is invalid.
/// - The key could not been persisted due to database issues.
pub async fn add_peer_key(&self, add_key_form: AddKeyForm) -> Result<auth::PeerKey, PeerKeyError> {
// code-review: all methods related to keys should be moved to a new independent "keys" service.

match add_key_form.opt_key {
// Upload pre-generated key
Some(pre_existing_key) => {
if let Some(seconds_valid) = add_key_form.opt_seconds_valid {
// Expiring key
let Some(valid_until) = CurrentClock::now_add(&Duration::from_secs(seconds_valid)) else {
return Err(PeerKeyError::DurationOverflow { seconds_valid });
};

let key = pre_existing_key.parse::<Key>();

match key {
Ok(key) => match self.add_auth_key(key, Some(valid_until)).await {
Ok(auth_key) => Ok(auth_key),
Err(err) => Err(PeerKeyError::DatabaseError {
source: Located(err).into(),
}),
},
Err(err) => Err(PeerKeyError::InvalidKey {
key: pre_existing_key,
source: Located(err).into(),
}),
}
} else {
// Permanent key
let key = pre_existing_key.parse::<Key>();

match key {
Ok(key) => match self.add_permanent_auth_key(key).await {
Ok(auth_key) => Ok(auth_key),
Err(err) => Err(PeerKeyError::DatabaseError {
source: Located(err).into(),
}),
},
Err(err) => Err(PeerKeyError::InvalidKey {
key: pre_existing_key,
source: Located(err).into(),
}),
}
}
}
// Generate a new random key
None => match add_key_form.opt_seconds_valid {
// Expiring key
Some(seconds_valid) => match self.generate_auth_key(Some(Duration::from_secs(seconds_valid))).await {
Ok(auth_key) => Ok(auth_key),
Err(err) => Err(PeerKeyError::DatabaseError {
source: Located(err).into(),
}),
},
// Permanent key
None => match self.generate_permanent_auth_key().await {
Ok(auth_key) => Ok(auth_key),
Err(err) => Err(PeerKeyError::DatabaseError {
source: Located(err).into(),
}),
},
},
}
}

/// It generates a new permanent authentication key.
///
/// Authentication keys are used by HTTP trackers.
Expand Down

0 comments on commit d361190

Please sign in to comment.