From 9b7c5c8138580da2b8b1a772e586f2c0e66f5fa7 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 23 Feb 2024 18:22:58 +0000 Subject: [PATCH] feat: [#488] panic starting the app when tracker config is invalid For the time being, it only checks that private tracker don't use UDP. --- src/app.rs | 2 ++ src/config.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/app.rs b/src/app.rs index bb71d5dc..9cdd0523 100644 --- a/src/app.rs +++ b/src/app.rs @@ -39,6 +39,8 @@ pub async fn run(configuration: Configuration, api_version: &Version) -> Running logging::setup(&log_level); + configuration.validate().await.expect("invalid configuration"); + let configuration = Arc::new(configuration); // Get configuration settings needed to build the app dependencies and diff --git a/src/config.rs b/src/config.rs index d655eaf1..7335c1eb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use tokio::sync::RwLock; use torrust_index_located_error::{Located, LocatedError}; +use url::{ParseError, Url}; /// Information required for loading config #[derive(Debug, Default, Clone)] @@ -99,6 +100,17 @@ pub enum Error { Infallible, } +/// Errors that can occur validating the configuration. +#[derive(Error, Debug)] +pub enum ValidationError { + /// Unable to load the configuration from the configuration file. + #[error("Invalid tracker URL: {source}")] + InvalidTrackerUrl { source: LocatedError<'static, ParseError> }, + + #[error("UDP private trackers are not supported. URL schemes for private tracker URLs must be HTTP ot HTTPS")] + UdpTrackersInPrivateModeNotSupported, +} + impl From for Error { #[track_caller] fn from(err: ConfigError) -> Self { @@ -149,6 +161,11 @@ impl TrackerMode { pub fn is_open(&self) -> bool { matches!(self, TrackerMode::Public | TrackerMode::Whitelisted) } + + #[must_use] + pub fn is_close(&self) -> bool { + !self.is_open() + } } /// Configuration for the associated tracker. @@ -550,6 +567,42 @@ impl Configuration { settings_lock.net.base_url.clone() } + + /// # Errors + /// + /// Will return an error if the configuration is invalid. + pub async fn validate(&self) -> Result<(), ValidationError> { + self.validate_tracker_config().await + } + + /// # Errors + /// + /// Will return an error if the `tracker` configuration section is invalid. + pub async fn validate_tracker_config(&self) -> Result<(), ValidationError> { + let settings_lock = self.settings.read().await; + + let tracker_mode = settings_lock.tracker.mode.clone(); + let tracker_url = settings_lock.tracker.url.clone(); + + let tracker_url = match parse_url(&tracker_url) { + Ok(url) => url, + Err(err) => { + return Err(ValidationError::InvalidTrackerUrl { + source: Located(err).into(), + }) + } + }; + + if tracker_mode.is_close() && (tracker_url.scheme() != "http" && tracker_url.scheme() != "https") { + return Err(ValidationError::UdpTrackersInPrivateModeNotSupported); + } + + Ok(()) + } +} + +fn parse_url(url_str: &str) -> Result { + Url::parse(url_str) } /// The public index configuration.