Load values from Rocket.toml into managed state #74

Merged
glyph merged 6 commits from rocket_config into main 2022-01-25 09:35:40 +00:00
8 changed files with 66 additions and 44 deletions

View File

@ -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" }

View File

@ -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`

View File

@ -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

View File

@ -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<dyn std::error::Error>;
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<Build> {
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::<RocketConfig>())
}
/// Launch the peach-web rocket server.

View File

@ -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<Build> {
rocket::build()
pub fn mount_peachpub_routes(rocket: Rocket<Build>) -> Rocket<Build> {
rocket
.mount(
"/",
routes![
@ -66,8 +66,8 @@ pub fn mount_peachpub_routes() -> Rocket<Build> {
/// 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<Build> {
mount_peachpub_routes()
pub fn mount_peachcloud_routes(rocket: Rocket<Build>) -> Rocket<Build> {
mount_peachpub_routes(rocket)
.mount(
"/settings/network",
routes![

View File

@ -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,14 +43,14 @@ impl<'r> FromRequest<'r> for Authenticated {
type Error = LoginError;
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
// 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,
};
// retrieve auth state from managed state (returns `Option<bool>`).
// this value is read from the Rocket.toml config file on start-up
let authentication_is_disabled: bool = *req
.rocket()
.state::<RocketConfig>()
.map(|config| (&config.disable_auth))
.unwrap_or(&false);
if authentication_is_disabled {
let auth = Authenticated {};
request::Outcome::Success(auth)

View File

@ -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<RocketConfig>) -> 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())
}

View File

@ -1,4 +1,4 @@
use rocket::{get, request::FlashMessage};
use rocket::get;
use rocket_dyn_templates::{tera::Context, Template};
use crate::routes::authentication::Authenticated;