Protect the session_key from external libs. Clean-up config docs.

This commit is contained in:
Sergio Benitez 2016-10-15 18:58:57 -07:00
parent cf9f746ee2
commit 471239c567
3 changed files with 44 additions and 26 deletions

View File

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use std::path::Path; use std::path::Path;
use std::cell::RefCell;
use std::fmt;
use config::Environment::*; use config::Environment::*;
use config::{self, Environment, ConfigError}; use config::{self, Environment, ConfigError};
@ -8,13 +10,13 @@ use config::{self, Environment, ConfigError};
use logger::LoggingLevel; use logger::LoggingLevel;
use toml::Value; use toml::Value;
#[derive(Debug, PartialEq, Clone)] #[derive(PartialEq)]
pub struct Config { pub struct Config {
pub address: String, pub address: String,
pub port: usize, pub port: usize,
pub log_level: LoggingLevel, pub log_level: LoggingLevel,
pub session_key: Option<String>,
pub env: Environment, pub env: Environment,
session_key: RefCell<Option<String>>,
extra: HashMap<String, Value>, extra: HashMap<String, Value>,
filename: String, filename: String,
} }
@ -41,7 +43,7 @@ impl Config {
address: "localhost".to_string(), address: "localhost".to_string(),
port: 8000, port: 8000,
log_level: LoggingLevel::Normal, log_level: LoggingLevel::Normal,
session_key: None, session_key: RefCell::new(None),
extra: HashMap::new(), extra: HashMap::new(),
env: env, env: env,
filename: filename.to_string(), filename: filename.to_string(),
@ -52,7 +54,7 @@ impl Config {
address: "0.0.0.0".to_string(), address: "0.0.0.0".to_string(),
port: 80, port: 80,
log_level: LoggingLevel::Normal, log_level: LoggingLevel::Normal,
session_key: None, session_key: RefCell::new(None),
extra: HashMap::new(), extra: HashMap::new(),
env: env, env: env,
filename: filename.to_string(), filename: filename.to_string(),
@ -63,7 +65,7 @@ impl Config {
address: "0.0.0.0".to_string(), address: "0.0.0.0".to_string(),
port: 80, port: 80,
log_level: LoggingLevel::Critical, log_level: LoggingLevel::Critical,
session_key: None, session_key: RefCell::new(None),
extra: HashMap::new(), extra: HashMap::new(),
env: env, env: env,
filename: filename.to_string(), filename: filename.to_string(),
@ -101,7 +103,7 @@ impl Config {
return Err(self.bad_type(name, val, "a 192-bit base64 string")); 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" { } else if name == "log" {
let level_str = parse!(self, name, val, as_str, "a string")?; let level_str = parse!(self, name, val, as_str, "a string")?;
self.log_level = match level_str.parse() { self.log_level = match level_str.parse() {
@ -116,6 +118,16 @@ impl Config {
Ok(()) Ok(())
} }
#[inline(always)]
pub fn take_session_key(&self) -> Option<String> {
self.session_key.borrow_mut().take()
}
#[inline(always)]
pub fn extras<'a>(&'a self) -> impl Iterator<Item=(&'a String, &'a Value)> {
self.extra.iter()
}
pub fn get_str<'a>(&'a self, name: &str) -> config::Result<&'a str> { pub fn get_str<'a>(&'a self, name: &str) -> config::Result<&'a str> {
let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?; let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?;
parse!(self, name, value, as_str, "a string") parse!(self, name, value, as_str, "a string")
@ -143,11 +155,6 @@ impl Config {
} }
} }
#[inline(always)]
pub fn extras<'a>(&'a self) -> impl Iterator<Item=(&'a String, &'a Value)> {
self.extra.iter()
}
// Builder pattern below, mostly for testing. // Builder pattern below, mostly for testing.
#[inline(always)] #[inline(always)]
@ -170,7 +177,7 @@ impl Config {
#[inline(always)] #[inline(always)]
pub fn session_key(mut self, var: String) -> Self { pub fn session_key(mut self, var: String) -> Self {
self.session_key = Some(var); self.session_key = RefCell::new(Some(var));
self self
} }
@ -180,3 +187,10 @@ impl Config {
self 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)
}
}

View File

@ -11,8 +11,8 @@ use std::env;
pub use self::error::{ConfigError, ParsingError}; pub use self::error::{ConfigError, ParsingError};
pub use self::environment::Environment; pub use self::environment::Environment;
pub use self::config::Config;
use self::Environment::*; use self::Environment::*;
use self::config::Config;
use toml::{self, Table}; use toml::{self, Table};
use logger::{self, LoggingLevel}; use logger::{self, LoggingLevel};
@ -23,7 +23,7 @@ const CONFIG_FILENAME: &'static str = "Rocket.toml";
pub type Result<T> = ::std::result::Result<T, ConfigError>; pub type Result<T> = ::std::result::Result<T, ConfigError>;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq)]
pub struct RocketConfig { pub struct RocketConfig {
pub active_env: Environment, pub active_env: Environment,
config: HashMap<Environment, Config>, config: HashMap<Environment, Config>,
@ -152,14 +152,16 @@ impl RocketConfig {
/// ///
/// # Panics /// # 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 /// # Thread-Safety
/// ///
/// This function is _not_ thread-safe. It should be called by a single thread. /// This function is _not_ thread-safe. It should be called by a single thread.
#[doc(hidden)]
pub fn init() -> &'static Config { pub fn init() -> &'static Config {
if let Some(config) = active() { if active().is_some() {
return config; panic!("Configuration has already been initialized!")
} }
let bail = |e: ConfigError| -> ! { 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> { pub fn active() -> Option<&'static Config> {
unsafe { CONFIG.as_ref().map(|c| c.active()) } unsafe { CONFIG.as_ref().map(|c| c.active()) }
} }
@ -225,9 +228,9 @@ mod test {
); );
($env:expr, $rconfig:expr, $econfig:expr) => ( ($env:expr, $rconfig:expr, $econfig:expr) => (
match $rconfig.clone() { match $rconfig {
Ok(config) => assert_eq!(config.get($env), &$econfig), Ok(ref config) => assert_eq!(config.get($env), &$econfig),
Err(e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e) Err(ref e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e)
} }
); );
} }
@ -306,11 +309,12 @@ mod test {
pi = 3.14 pi = 3.14
"#; "#;
let mut expected = default_config(Development); let mut expected = default_config(Development)
expected.address = "1.2.3.4".to_string(); .address("1.2.3.4".to_string())
expected.port = 7810; .port(7810)
expected.log_level = LoggingLevel::Critical; .log_level(LoggingLevel::Critical)
expected.session_key = Some("01234567890123456789012345678901".to_string()); .session_key("01234567890123456789012345678901".into());
expected.set("template_dir", &Value::String("mine".into())).unwrap(); expected.set("template_dir", &Value::String("mine".into())).unwrap();
expected.set("json", &Value::Boolean(true)).unwrap(); expected.set("json", &Value::Boolean(true)).unwrap();
expected.set("pi", &Value::Float(3.14)).unwrap(); expected.set("pi", &Value::Float(3.14)).unwrap();

View File

@ -235,7 +235,7 @@ impl Rocket {
White.paint(&config.address), White.paint(&config.address),
White.paint(&config.port)); White.paint(&config.port));
info_!("logging: {:?}", White.paint(config.log_level)); 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() { for (name, value) in config.extras() {
info_!("{} {}: {}", Yellow.paint("[extra]"), name, White.paint(value)); info_!("{} {}: {}", Yellow.paint("[extra]"), name, White.paint(value));
} }