124 lines
4.5 KiB
Rust
124 lines
4.5 KiB
Rust
//! # peach-web
|
|
//!
|
|
//! `peach-web` provides a web interface for monitoring and interacting with the
|
|
//! PeachCloud device. This allows administration of the single-board computer
|
|
//! (ie. Raspberry Pi) running PeachCloud, as well as the ssb-server and related
|
|
//! plugins.
|
|
//!
|
|
//! ## Design
|
|
//!
|
|
//! `peach-web` is written primarily in Rust and presents a web interface for
|
|
//! interacting with the device. The stack currently consists of Rouille (Rust
|
|
//! micro-web-framework), Maud (an HTML template engine for Rust), HTML and
|
|
//! CSS.
|
|
|
|
mod config;
|
|
pub mod error;
|
|
mod private_router;
|
|
mod public_router;
|
|
mod routes;
|
|
mod templates;
|
|
pub mod utils;
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
sync::{Mutex, RwLock},
|
|
};
|
|
|
|
use lazy_static::lazy_static;
|
|
use log::info;
|
|
|
|
// crate-local dependencies
|
|
use config::ServerConfig;
|
|
use utils::theme::Theme;
|
|
|
|
// load the application configuration and create the theme switcher
|
|
lazy_static! {
|
|
static ref SERVER_CONFIG: ServerConfig =
|
|
ServerConfig::new().expect("Failed to load rouille configuration values on server startup");
|
|
static ref THEME: RwLock<Theme> = RwLock::new(Theme::Light);
|
|
}
|
|
|
|
/// Wireless interface identifier.
|
|
pub const WLAN_IFACE: &str = "wlan0";
|
|
|
|
/// Access point interface identifier.
|
|
pub const AP_IFACE: &str = "ap0";
|
|
|
|
/// Session data for each authenticated client.
|
|
#[derive(Debug, Clone)]
|
|
pub struct SessionData {
|
|
_login: String,
|
|
}
|
|
|
|
/// Launch the peach-web server.
|
|
fn main() {
|
|
// initialize logger
|
|
env_logger::init();
|
|
|
|
// set ip address / hostname and port for the webserver
|
|
// defaults to "127.0.0.1:8000"
|
|
let addr_and_port = format!("{}:{}", SERVER_CONFIG.addr, SERVER_CONFIG.port);
|
|
|
|
// store the session data for each session and a hashmap that associates
|
|
// each session id with the data
|
|
// note: we are storing this data in memory. all sessions are erased when
|
|
// the program is restarted.
|
|
let sessions_storage: Mutex<HashMap<String, SessionData>> = Mutex::new(HashMap::new());
|
|
|
|
info!("Launching web server on {}", addr_and_port);
|
|
|
|
// the `start_server` starts listening forever on the given address
|
|
rouille::start_server(addr_and_port, move |request| {
|
|
// assign a unique id to each client (appends a cookie to the response
|
|
// with a name of "SID" and a duration of one hour (3600 seconds)
|
|
rouille::session::session(request, "SID", 3600, |session| {
|
|
// if the "DISABLE_AUTH" env var is true, authenticate the session
|
|
let mut session_data = if SERVER_CONFIG.disable_auth {
|
|
Some(SessionData {
|
|
_login: "success".to_string(),
|
|
})
|
|
// if the client already has an identifier from a previous request,
|
|
// try to load the existing session data. if successful, make a
|
|
// copy of the data in order to avoid locking the session for too
|
|
// long
|
|
} else if session.client_has_sid() {
|
|
sessions_storage.lock().unwrap().get(session.id()).cloned()
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// pass the request to the public router
|
|
//
|
|
// the public router includes authentication-related routes which
|
|
// do not require the user to be authenticated (ie. login and reset
|
|
// password)
|
|
//
|
|
// if the user is already authenticated, their request will be
|
|
// passed to the private router by public_router::handle_route()
|
|
//
|
|
// we pass a mutable reference to the `Option<SessionData>` so that
|
|
// the function is free to modify it
|
|
let response = public_router::handle_route(request, &mut session_data);
|
|
|
|
// since the function call to `handle_route` can modify the session
|
|
// data, we have to store it back in the `sessions_storage` after
|
|
// the request has been handled
|
|
if let Some(data) = session_data {
|
|
sessions_storage
|
|
.lock()
|
|
.unwrap()
|
|
.insert(session.id().to_owned(), data);
|
|
} else if session.client_has_sid() {
|
|
// if the content of the `Option` was erased (ie. due to
|
|
// deauthentication on logout), remove the session from the
|
|
// storage. this is only done if the client already has an
|
|
// identifier, otherwise calling `session.id()` will assign one
|
|
sessions_storage.lock().unwrap().remove(session.id());
|
|
}
|
|
|
|
response
|
|
})
|
|
});
|
|
}
|