From 680044cba8fcc2c3144ce3b48169c49fa49749fb Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 16:58:13 +0200 Subject: [PATCH 1/6] read config params from figment and attach managed state --- peach-web/src/main.rs | 48 +++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/peach-web/src/main.rs b/peach-web/src/main.rs index ded1686..238e561 100644 --- a/peach-web/src/main.rs +++ b/peach-web/src/main.rs @@ -32,21 +32,23 @@ pub mod routes; mod tests; pub mod utils; -use std::{env, process}; +use std::process; -use lazy_static::lazy_static; -use log::{error, info}; -use rocket::{Build, Rocket}; +use log::{debug, error, info}; +use rocket::{fairing::AdHoc, serde::Deserialize, Build, Rocket}; pub type BoxError = Box; -lazy_static! { - // determine run-mode from env var; default to standalone mode (aka peachpub) - static ref STANDALONE_MODE: bool = match env::var("PEACH_STANDALONE_MODE") { - // parse the value to a boolean; default to true for any error - Ok(val) => val.parse().unwrap_or(true), - Err(_) => true - }; +/// Application configuration parameters. +/// These values are extracted from Rocket's default configuration provider: +/// `Config::figment()`. As such, the values are drawn from `Rocket.toml` or +/// the TOML file path in the `ROCKET_CONFIG` environment variable. The TOML +/// file parameters are automatically overruled by any `ROCKET_` variables +/// which might be set. +#[derive(Debug, Deserialize)] +pub struct RocketConfig { + disable_auth: bool, + standalone_mode: bool, } static WLAN_IFACE: &str = "wlan0"; @@ -54,11 +56,27 @@ static AP_IFACE: &str = "ap0"; pub fn init_rocket() -> Rocket { info!("Initializing Rocket"); - if *STANDALONE_MODE { - router::mount_peachpub_routes() + // build a basic rocket instance + let rocket = rocket::build(); + + // return the default provider figment used by `rocket::build()` + let figment = rocket.figment(); + + // deserialize configuration parameters into our `RocketConfig` struct (defined above) + // since we're in the intialisation phase, panic if the extraction fails + let config: RocketConfig = figment.extract().expect("configuration extraction failed"); + + debug!("{:?}", config); + + info!("Mounting Rocket routes"); + let mounted_rocket = if config.standalone_mode { + router::mount_peachpub_routes(rocket) } else { - router::mount_peachcloud_routes() - } + router::mount_peachcloud_routes(rocket) + }; + + info!("Attaching application configuration to managed state"); + mounted_rocket.attach(AdHoc::config::()) } /// Launch the peach-web rocket server. -- 2.40.1 From f3ddbcf07cbd0938c9f9fb44686db649a790e012 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 16:59:03 +0200 Subject: [PATCH 2/6] set auth request guard from managed state --- peach-web/src/routes/authentication.rs | 47 ++++++++++++++------------ 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/peach-web/src/routes/authentication.rs b/peach-web/src/routes/authentication.rs index 97ea167..b16469e 100644 --- a/peach-web/src/routes/authentication.rs +++ b/peach-web/src/routes/authentication.rs @@ -7,7 +7,6 @@ use rocket::{ request::{self, FlashMessage, FromRequest, Request}, response::{Flash, Redirect}, serde::Deserialize, - Config, }; use rocket_dyn_templates::{tera::Context, Template}; @@ -15,6 +14,8 @@ use peach_lib::{error::PeachError, password_utils}; use crate::error::PeachWebError; use crate::utils::TemplateOrRedirect; +//use crate::DisableAuth; +use crate::RocketConfig; // HELPERS AND STRUCTS FOR AUTHENTICATION WITH COOKIES @@ -42,26 +43,30 @@ impl<'r> FromRequest<'r> for Authenticated { type Error = LoginError; async fn from_request(req: &'r Request<'_>) -> request::Outcome { - // check for `disable_auth` config value; set to `false` if unset - // can be set via the `ROCKET_DISABLE_AUTH` environment variable - // - env var, if set, takes precedence over value defined in `Rocket.toml` - let authentication_is_disabled: bool = match Config::figment().find_value("disable_auth") { - // deserialize the boolean value; set to `false` if an error is encountered - Ok(value) => value.deserialize().unwrap_or(false), - Err(_) => false, - }; - if authentication_is_disabled { - let auth = Authenticated {}; - request::Outcome::Success(auth) - } else { - let authenticated = req - .cookies() - .get_private(AUTH_COOKIE_KEY) - .and_then(|cookie| cookie.value().parse().ok()) - .map(|_value: String| Authenticated {}); - match authenticated { - Some(auth) => request::Outcome::Success(auth), - None => request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn)), + // retrieve auth state from managed state (returns `Option`). + // this value is read from the Rocket.toml config file on start-up + let authentication_is_disabled = req + .rocket() + .state::() + .map(|config| (&config.disable_auth)); + + match authentication_is_disabled { + Some(true) => { + let auth = Authenticated {}; + request::Outcome::Success(auth) + } + _ => { + let authenticated = req + .cookies() + .get_private(AUTH_COOKIE_KEY) + .and_then(|cookie| cookie.value().parse().ok()) + .map(|_value: String| Authenticated {}); + match authenticated { + Some(auth) => request::Outcome::Success(auth), + None => { + request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn)) + } + } } } } -- 2.40.1 From d0321d17d00b40093eae44a268449ff625f87c20 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 16:59:44 +0200 Subject: [PATCH 3/6] remove lazy_static dependency --- peach-web/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/peach-web/Cargo.toml b/peach-web/Cargo.toml index ddd4b0d..90e0295 100644 --- a/peach-web/Cargo.toml +++ b/peach-web/Cargo.toml @@ -36,7 +36,6 @@ maintenance = { status = "actively-developed" } [dependencies] env_logger = "0.8" -lazy_static = "1.4.0" log = "0.4" nest = "1.0.0" peach-lib = { path = "../peach-lib" } -- 2.40.1 From bfb53747db82705da5493c224e6dd40e7f4ef808 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 16:59:54 +0200 Subject: [PATCH 4/6] update rocket config file and related docs --- peach-web/README.md | 14 ++++++++------ peach-web/Rocket.toml | 7 ++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/peach-web/README.md b/peach-web/README.md index ec03092..b686101 100644 --- a/peach-web/README.md +++ b/peach-web/README.md @@ -25,7 +25,7 @@ Move into the repo and compile: Run the tests: -`ROCKET_DISABLE_AUTH=true PEACH_STANDALONE_MODE=false cargo test` +`ROCKET_DISABLE_AUTH=true ROCKET_STANDALONE_MODE=false cargo test` Move back to the `peach-workspace` directory: @@ -37,21 +37,23 @@ Run the binary: ### Environment -**Deployment Mode** +**Deployment Profile** -The web application deployment mode is configured with the `ROCKET_ENV` environment variable: +The web application deployment profile can be configured with the `ROCKET_ENV` environment variable: `export ROCKET_ENV=stage` -Other deployment modes are `dev` and `prod`. Read the [Rocket Environment Configurations docs](https://rocket.rs/v0.5-rc/guide/configuration/#environment-variables) for further information. +Default configuration parameters are defined in `Rocket.toml`. This file defines a set of default parameters, some of which are overwritten when running in `debug` mode (ie. `cargo run` or `cargo build`) or `release` mode (ie. `cargo run --release` or `cargo build --release`). + +Read the [Rocket Environment Configurations docs](https://rocket.rs/v0.5-rc/guide/configuration/#environment-variables) for further information. **Configuration Mode** -The web application can be run with a minimal set of routes and functionality (PeachPub - a simple sbot manager) or with the full-suite of capabilities, including network management and access to device statistics (PeachCloud). The mode is configured with the `PEACH_STANDALONE_MODE` environment variable: `true` or `false`. If the variable is unset or the value is incorrectly set, the application defaults to standalone mode. +The web application can be run with a minimal set of routes and functionality (PeachPub - a simple sbot manager) or with the full-suite of capabilities, including network management and access to device statistics (PeachCloud). The mode is enabled by default (as defined in `Rocket.toml`) but can be overwritten using the `ROCKET_STANDALONE_MODE` environment variable: `true` or `false`. If the variable is unset or the value is incorrectly set, the application defaults to standalone mode. **Authentication** -Authentication is disabled in `development` mode and enabled by default when running the application in `production` mode. It can be disabled by setting the `ROCKET_DISABLE_AUTH` environment variable to `true`: +Authentication is disabled in `debug` mode and enabled by default when running the application in `release` mode. It can be disabled by setting the `ROCKET_DISABLE_AUTH` environment variable to `true`: `export ROCKET_DISABLE_AUTH=true` diff --git a/peach-web/Rocket.toml b/peach-web/Rocket.toml index 1af1b71..c1f285e 100644 --- a/peach-web/Rocket.toml +++ b/peach-web/Rocket.toml @@ -1,10 +1,11 @@ [default] secret_key = "VYVUDivXvu8g6llxeJd9F92pMfocml5xl/Jjv5Sk4yw=" +disable_auth = false +standalone_mode = true -[development] +[debug] template_dir = "templates/" disable_auth = true -[production] +[release] template_dir = "templates/" -disable_auth = false -- 2.40.1 From 43344566def42c6d932988c08f8397d809f2c2a3 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 17:00:53 +0200 Subject: [PATCH 5/6] read values from managed state --- peach-web/src/router.rs | 8 ++++---- peach-web/src/routes/index.rs | 11 ++++++----- peach-web/src/routes/status/scuttlebutt.rs | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/peach-web/src/router.rs b/peach-web/src/router.rs index 341d9aa..99bcb7b 100644 --- a/peach-web/src/router.rs +++ b/peach-web/src/router.rs @@ -14,8 +14,8 @@ use crate::routes::{ /// catchers. This gives us everything we need to run PeachPub and excludes /// settings and status routes related to networking and the device (memory, /// hard disk, CPU etc.). -pub fn mount_peachpub_routes() -> Rocket { - rocket::build() +pub fn mount_peachpub_routes(rocket: Rocket) -> Rocket { + rocket .mount( "/", routes![ @@ -66,8 +66,8 @@ pub fn mount_peachpub_routes() -> Rocket { /// Create a Rocket instance with PeachPub routes, fileserver and catchers by /// calling `mount_peachpub_routes()` and then mount all additional routes /// required to run a complete PeachCloud build. -pub fn mount_peachcloud_routes() -> Rocket { - mount_peachpub_routes() +pub fn mount_peachcloud_routes(rocket: Rocket) -> Rocket { + mount_peachpub_routes(rocket) .mount( "/settings/network", routes![ diff --git a/peach-web/src/routes/index.rs b/peach-web/src/routes/index.rs index 54867b7..a703ed1 100644 --- a/peach-web/src/routes/index.rs +++ b/peach-web/src/routes/index.rs @@ -1,19 +1,20 @@ -use rocket::{get, request::FlashMessage}; +use rocket::{get, request::FlashMessage, State}; use rocket_dyn_templates::{tera::Context, Template}; use crate::routes::authentication::Authenticated; -use crate::STANDALONE_MODE; +use crate::RocketConfig; // HELPERS AND ROUTES FOR / (HOME PAGE) #[get("/")] -pub fn home(_auth: Authenticated) -> Template { +pub fn home(_auth: Authenticated, config: &State) -> Template { let mut context = Context::new(); context.insert("flash_name", &None::<()>); context.insert("flash_msg", &None::<()>); context.insert("title", &None::<()>); - // pass in mode so we can define appropriate urls in template - context.insert("standalone_mode", &*STANDALONE_MODE); + + // pass in mode from managed state so we can define appropriate urls in template + context.insert("standalone_mode", &config.standalone_mode); Template::render("home", &context.into_json()) } diff --git a/peach-web/src/routes/status/scuttlebutt.rs b/peach-web/src/routes/status/scuttlebutt.rs index c1f532a..5ed3df1 100644 --- a/peach-web/src/routes/status/scuttlebutt.rs +++ b/peach-web/src/routes/status/scuttlebutt.rs @@ -1,4 +1,4 @@ -use rocket::{get, request::FlashMessage}; +use rocket::get; use rocket_dyn_templates::{tera::Context, Template}; use crate::routes::authentication::Authenticated; -- 2.40.1 From 2bfba66dab398a8b3a1cb6832bcf30a293234420 Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Jan 2022 17:12:32 +0200 Subject: [PATCH 6/6] restructure auth mode check --- peach-web/src/routes/authentication.rs | 34 ++++++++++++-------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/peach-web/src/routes/authentication.rs b/peach-web/src/routes/authentication.rs index b16469e..e3e51a3 100644 --- a/peach-web/src/routes/authentication.rs +++ b/peach-web/src/routes/authentication.rs @@ -45,28 +45,24 @@ impl<'r> FromRequest<'r> for Authenticated { async fn from_request(req: &'r Request<'_>) -> request::Outcome { // retrieve auth state from managed state (returns `Option`). // this value is read from the Rocket.toml config file on start-up - let authentication_is_disabled = req + let authentication_is_disabled: bool = *req .rocket() .state::() - .map(|config| (&config.disable_auth)); + .map(|config| (&config.disable_auth)) + .unwrap_or(&false); - match authentication_is_disabled { - Some(true) => { - let auth = Authenticated {}; - request::Outcome::Success(auth) - } - _ => { - let authenticated = req - .cookies() - .get_private(AUTH_COOKIE_KEY) - .and_then(|cookie| cookie.value().parse().ok()) - .map(|_value: String| Authenticated {}); - match authenticated { - Some(auth) => request::Outcome::Success(auth), - None => { - request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn)) - } - } + if authentication_is_disabled { + let auth = Authenticated {}; + request::Outcome::Success(auth) + } else { + let authenticated = req + .cookies() + .get_private(AUTH_COOKIE_KEY) + .and_then(|cookie| cookie.value().parse().ok()) + .map(|_value: String| Authenticated {}); + match authenticated { + Some(auth) => request::Outcome::Success(auth), + None => request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn)), } } } -- 2.40.1