From 471239c5670214fe875706da28e0691f75527970 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sat, 15 Oct 2016 18:58:57 -0700 Subject: [PATCH] Protect the session_key from external libs. Clean-up config docs. --- lib/src/config/config.rs | 38 ++++++++++++++++++++++++++------------ lib/src/config/mod.rs | 30 +++++++++++++++++------------- lib/src/rocket.rs | 2 +- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/lib/src/config/config.rs b/lib/src/config/config.rs index fc493e01..f550a009 100644 --- a/lib/src/config/config.rs +++ b/lib/src/config/config.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; use std::net::ToSocketAddrs; use std::path::Path; +use std::cell::RefCell; +use std::fmt; use config::Environment::*; use config::{self, Environment, ConfigError}; @@ -8,13 +10,13 @@ use config::{self, Environment, ConfigError}; use logger::LoggingLevel; use toml::Value; -#[derive(Debug, PartialEq, Clone)] +#[derive(PartialEq)] pub struct Config { pub address: String, pub port: usize, pub log_level: LoggingLevel, - pub session_key: Option, pub env: Environment, + session_key: RefCell>, extra: HashMap, filename: String, } @@ -41,7 +43,7 @@ impl Config { address: "localhost".to_string(), port: 8000, log_level: LoggingLevel::Normal, - session_key: None, + session_key: RefCell::new(None), extra: HashMap::new(), env: env, filename: filename.to_string(), @@ -52,7 +54,7 @@ impl Config { address: "0.0.0.0".to_string(), port: 80, log_level: LoggingLevel::Normal, - session_key: None, + session_key: RefCell::new(None), extra: HashMap::new(), env: env, filename: filename.to_string(), @@ -63,7 +65,7 @@ impl Config { address: "0.0.0.0".to_string(), port: 80, log_level: LoggingLevel::Critical, - session_key: None, + session_key: RefCell::new(None), extra: HashMap::new(), env: env, filename: filename.to_string(), @@ -101,7 +103,7 @@ impl Config { return Err(self.bad_type(name, val, "a 192-bit base64 string")); } - self.session_key = Some(key.to_string()); + self.session_key = RefCell::new(Some(key.to_string())); } else if name == "log" { let level_str = parse!(self, name, val, as_str, "a string")?; self.log_level = match level_str.parse() { @@ -116,6 +118,16 @@ impl Config { Ok(()) } + #[inline(always)] + pub fn take_session_key(&self) -> Option { + self.session_key.borrow_mut().take() + } + + #[inline(always)] + pub fn extras<'a>(&'a self) -> impl Iterator { + self.extra.iter() + } + pub fn get_str<'a>(&'a self, name: &str) -> config::Result<&'a str> { let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?; parse!(self, name, value, as_str, "a string") @@ -143,11 +155,6 @@ impl Config { } } - #[inline(always)] - pub fn extras<'a>(&'a self) -> impl Iterator { - self.extra.iter() - } - // Builder pattern below, mostly for testing. #[inline(always)] @@ -170,7 +177,7 @@ impl Config { #[inline(always)] pub fn session_key(mut self, var: String) -> Self { - self.session_key = Some(var); + self.session_key = RefCell::new(Some(var)); self } @@ -180,3 +187,10 @@ impl Config { self } } + +impl fmt::Debug for Config { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Config[{}] {{ address: {}, port: {}, log_level: {:?} }}", + self.env, self.address, self.port, self.log_level) + } +} diff --git a/lib/src/config/mod.rs b/lib/src/config/mod.rs index 027a9784..65f390be 100644 --- a/lib/src/config/mod.rs +++ b/lib/src/config/mod.rs @@ -11,8 +11,8 @@ use std::env; pub use self::error::{ConfigError, ParsingError}; pub use self::environment::Environment; +pub use self::config::Config; use self::Environment::*; -use self::config::Config; use toml::{self, Table}; use logger::{self, LoggingLevel}; @@ -23,7 +23,7 @@ const CONFIG_FILENAME: &'static str = "Rocket.toml"; pub type Result = ::std::result::Result; -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq)] pub struct RocketConfig { pub active_env: Environment, config: HashMap, @@ -152,14 +152,16 @@ impl RocketConfig { /// /// # Panics /// -/// If there is a problem, prints a nice error message and bails. +/// If there is a problem, prints a nice error message and bails. This function +/// also panics if it is called more than once. /// /// # Thread-Safety /// /// This function is _not_ thread-safe. It should be called by a single thread. +#[doc(hidden)] pub fn init() -> &'static Config { - if let Some(config) = active() { - return config; + if active().is_some() { + panic!("Configuration has already been initialized!") } let bail = |e: ConfigError| -> ! { @@ -192,6 +194,7 @@ pub fn init() -> &'static Config { } } +/// Retrieve the active configuration, if there is one. pub fn active() -> Option<&'static Config> { unsafe { CONFIG.as_ref().map(|c| c.active()) } } @@ -225,9 +228,9 @@ mod test { ); ($env:expr, $rconfig:expr, $econfig:expr) => ( - match $rconfig.clone() { - Ok(config) => assert_eq!(config.get($env), &$econfig), - Err(e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e) + match $rconfig { + Ok(ref config) => assert_eq!(config.get($env), &$econfig), + Err(ref e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e) } ); } @@ -306,11 +309,12 @@ mod test { pi = 3.14 "#; - let mut expected = default_config(Development); - expected.address = "1.2.3.4".to_string(); - expected.port = 7810; - expected.log_level = LoggingLevel::Critical; - expected.session_key = Some("01234567890123456789012345678901".to_string()); + let mut expected = default_config(Development) + .address("1.2.3.4".to_string()) + .port(7810) + .log_level(LoggingLevel::Critical) + .session_key("01234567890123456789012345678901".into()); + expected.set("template_dir", &Value::String("mine".into())).unwrap(); expected.set("json", &Value::Boolean(true)).unwrap(); expected.set("pi", &Value::Float(3.14)).unwrap(); diff --git a/lib/src/rocket.rs b/lib/src/rocket.rs index 6ed2f422..175756fc 100644 --- a/lib/src/rocket.rs +++ b/lib/src/rocket.rs @@ -235,7 +235,7 @@ impl Rocket { White.paint(&config.address), White.paint(&config.port)); info_!("logging: {:?}", White.paint(config.log_level)); - info_!("session key: {}", White.paint(config.session_key.is_some())); + info_!("session key: {}", White.paint(config.take_session_key().is_some())); for (name, value) in config.extras() { info_!("{} {}: {}", Yellow.paint("[extra]"), name, White.paint(value)); }