diff --git a/Cargo.lock b/Cargo.lock index f327027..1d97c6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2346,6 +2346,7 @@ dependencies = [ "log 0.4.17", "maud", "peach-lib", + "peach-network", "rouille", "temporary", "xdg", diff --git a/peach-web/Cargo.toml b/peach-web/Cargo.toml index 9379556..93605a4 100644 --- a/peach-web/Cargo.toml +++ b/peach-web/Cargo.toml @@ -45,7 +45,7 @@ log = "0.4" maud = "0.23" peach-lib = { path = "../peach-lib" } # these will be reintroduced when the full peachcloud mode is added -#peach-network = { path = "../peach-network" } +peach-network = { path = "../peach-network" } #peach-stats = { path = "../peach-stats" } rouille = { version = "3.5", default-features = false } temporary = "0.6" diff --git a/peach-web/src/private_router.rs b/peach-web/src/private_router.rs index 5bc7665..426a690 100644 --- a/peach-web/src/private_router.rs +++ b/peach-web/src/private_router.rs @@ -200,6 +200,10 @@ pub fn mount_peachpub_routes( routes::settings::scuttlebutt::default::write_config() }, + (GET) (/settings/network) => { + Response::html(routes::settings::network::menu::build_template(request)).reset_flash() + }, + (GET) (/settings/theme/{theme: String}) => { routes::settings::theme::set_theme(theme) }, diff --git a/peach-web/src/routes/settings/mod.rs b/peach-web/src/routes/settings/mod.rs index d910549..b864d03 100644 --- a/peach-web/src/routes/settings/mod.rs +++ b/peach-web/src/routes/settings/mod.rs @@ -1,6 +1,6 @@ pub mod admin; //pub mod dns; pub mod menu; -//pub mod network; +pub mod network; pub mod scuttlebutt; pub mod theme; diff --git a/peach-web/src/routes/settings/network.rs b/peach-web/src/routes/settings/network.rs deleted file mode 100644 index 0e67c15..0000000 --- a/peach-web/src/routes/settings/network.rs +++ /dev/null @@ -1,322 +0,0 @@ -use log::{debug, warn}; -use rocket::{ - form::{Form, FromForm}, - get, post, - request::FlashMessage, - response::{Flash, Redirect}, - uri, UriDisplayQuery, -}; -use rocket_dyn_templates::{tera::Context, Template}; - -use peach_network::network; - -use crate::{ - context, - context::network::{NetworkAlertContext, NetworkDetailContext, NetworkListContext}, - routes::authentication::Authenticated, - utils::{monitor, monitor::Threshold}, - AP_IFACE, WLAN_IFACE, -}; - -// STRUCTS USED BY NETWORK ROUTES - -#[derive(Debug, FromForm, UriDisplayQuery)] -pub struct Ssid { - pub ssid: String, -} - -#[derive(Debug, FromForm)] -pub struct WiFi { - pub ssid: String, - pub pass: String, -} - -// HELPERS AND ROUTES FOR /settings/network/wifi/usage/reset - -#[get("/wifi/usage/reset")] -pub fn wifi_usage_reset(_auth: Authenticated) -> Flash { - let url = uri!(wifi_usage); - match monitor::reset_data() { - Ok(_) => Flash::success(Redirect::to(url), "Reset stored network traffic total"), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to reset stored network traffic total", - ), - } -} - -#[post("/wifi/connect", data = "")] -pub fn connect_wifi(network: Form, _auth: Authenticated) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_detail(ssid = ssid)); - match network::id(&*WLAN_IFACE, ssid) { - Ok(Some(id)) => match network::connect(&id, &*WLAN_IFACE) { - Ok(_) => Flash::success(Redirect::to(url), "Connected to chosen network"), - Err(_) => Flash::error(Redirect::to(url), "Failed to connect to chosen network"), - }, - _ => Flash::error(Redirect::to(url), "Failed to retrieve the network ID"), - } -} - -#[post("/wifi/disconnect", data = "")] -pub fn disconnect_wifi(network: Form, _auth: Authenticated) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_home); - match network::disable(&*WLAN_IFACE, ssid) { - Ok(_) => Flash::success(Redirect::to(url), "Disconnected from WiFi network"), - Err(_) => Flash::error(Redirect::to(url), "Failed to disconnect from WiFi network"), - } -} - -#[post("/wifi/forget", data = "")] -pub fn forget_wifi(network: Form, _auth: Authenticated) -> Flash { - let ssid = &network.ssid; - let url = uri!(network_home); - match network::forget(&*WLAN_IFACE, ssid) { - Ok(_) => Flash::success(Redirect::to(url), "WiFi credentials removed"), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to remove WiFi credentials".to_string(), - ), - } -} - -#[get("/wifi/modify?")] -pub fn wifi_password(ssid: &str, flash: Option, _auth: Authenticated) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/settings/network/wifi".to_string())); - context.insert("title", &Some("Update WiFi Password".to_string())); - context.insert("selected", &Some(ssid.to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("settings/network/modify_ap", &context.into_json()) -} - -#[post("/wifi/modify", data = "")] -pub fn wifi_set_password(wifi: Form, _auth: Authenticated) -> Flash { - let ssid = &wifi.ssid; - let pass = &wifi.pass; - let url = uri!(network_detail(ssid = ssid)); - match network::update(&*WLAN_IFACE, ssid, pass) { - Ok(_) => Flash::success(Redirect::to(url), "WiFi password updated".to_string()), - Err(_) => Flash::error( - Redirect::to(url), - "Failed to update WiFi password".to_string(), - ), - } -} - -// HELPERS AND ROUTES FOR /settings/network - -#[get("/")] -pub fn network_home(flash: Option, _auth: Authenticated) -> Template { - // assign context - let mut context = Context::new(); - context.insert("back", &Some("/settings")); - context.insert("title", &Some("Network Configuration")); - context.insert("ap_state", &context::network::ap_state()); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - // template_dir is set in Rocket.toml - Template::render("settings/network/menu", &context.into_json()) -} - -// HELPERS AND ROUTES FOR /settings/network/ap/activate - -#[get("/ap/activate")] -pub fn deploy_ap(_auth: Authenticated) -> Flash { - // activate the wireless access point - debug!("Activating WiFi access point."); - match network::start_iface_service(&*AP_IFACE) { - Ok(_) => Flash::success( - Redirect::to("/settings/network"), - "Activated WiFi access point", - ), - Err(_) => Flash::error( - Redirect::to("/settings/network"), - "Failed to activate WiFi access point", - ), - } -} - -// HELPERS AND ROUTES FOR /settings/network/wifi - -#[get("/wifi")] -pub fn wifi_list(flash: Option, _auth: Authenticated) -> Template { - // assign context through context_builder call - let mut context = NetworkListContext::build(); - context.back = Some("/settings/network".to_string()); - context.title = Some("WiFi Networks".to_string()); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.kind().to_string()); - context.flash_msg = Some(flash.message().to_string()); - }; - - Template::render("settings/network/list_aps", &context) -} - -// HELPERS AND ROUTES FOR /settings/network/wifi - -#[get("/wifi?")] -pub fn network_detail(ssid: &str, flash: Option, _auth: Authenticated) -> Template { - let mut context = NetworkDetailContext::build(); - context.back = Some("/settings/network/wifi".to_string()); - context.title = Some("WiFi Network".to_string()); - context.selected = Some(ssid.to_string()); - - if let Some(flash) = flash { - context.flash_name = Some(flash.kind().to_string()); - context.flash_msg = Some(flash.message().to_string()); - }; - - Template::render("settings/network/ap_details", &context) -} - -// HELPERS AND ROUTES FOR /settings/network/wifi/activate - -#[get("/wifi/activate")] -pub fn deploy_client(_auth: Authenticated) -> Flash { - // activate the wireless client - debug!("Activating WiFi client mode."); - match network::start_iface_service(&*WLAN_IFACE) { - Ok(_) => Flash::success(Redirect::to("/settings/network"), "Activated WiFi client"), - Err(_) => Flash::error( - Redirect::to("/settings/network"), - "Failed to activate WiFi client", - ), - } -} - -// HELPERS AND ROUTES FOR /settings/network/wifi/add - -#[get("/wifi/add")] -pub fn add_wifi(flash: Option, _auth: Authenticated) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/settings/network".to_string())); - context.insert("title", &Some("Add WiFi Network".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("settings/network/add_ap", &context.into_json()) -} - -#[get("/wifi/add?")] -pub fn add_ssid(ssid: &str, flash: Option, _auth: Authenticated) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/settings/network".to_string())); - context.insert("title", &Some("Add WiFi Network".to_string())); - context.insert("selected", &Some(ssid.to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("settings/network/add_ap", &context.into_json()) -} - -#[post("/wifi/add", data = "")] -pub fn add_credentials(wifi: Form, _auth: Authenticated) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/settings/network".to_string())); - context.insert("title", &Some("Add WiFi Network".to_string())); - - // check if the credentials already exist for this access point - // note: this is nicer but it's an unstable feature: - // if check_saved_aps(&wifi.ssid).contains(true) - // use unwrap_or instead, set value to false if err is returned - //let creds_exist = network::saved_networks(&wifi.ssid).unwrap_or(false); - let creds_exist = match network::saved_networks() { - Ok(Some(networks)) => networks.contains(&wifi.ssid), - _ => false, - }; - - // if credentials not found, generate and write wifi config to wpa_supplicant - let (flash_name, flash_msg) = if creds_exist { - ( - "error".to_string(), - "Network credentials already exist for this access point".to_string(), - ) - } else { - match network::add(&*WLAN_IFACE, &wifi.ssid, &wifi.pass) { - Ok(_) => { - debug!("Added WiFi credentials."); - // force reread of wpa_supplicant.conf file with new credentials - match network::reconfigure() { - Ok(_) => debug!("Successfully reconfigured wpa_supplicant"), - Err(_) => warn!("Failed to reconfigure wpa_supplicant"), - } - ("success".to_string(), "Added WiFi credentials".to_string()) - } - Err(e) => { - debug!("Failed to add WiFi credentials."); - ("error".to_string(), format!("{}", e)) - } - } - }; - - context.insert("flash_name", &Some(flash_name)); - context.insert("flash_msg", &Some(flash_msg)); - - Template::render("settings/network/add_ap", &context.into_json()) -} - -// HELPERS AND ROUTES FOR WIFI USAGE - -#[get("/wifi/usage")] -pub fn wifi_usage(flash: Option, _auth: Authenticated) -> Template { - let mut context = NetworkAlertContext::build(); - // set back icon link to network route - context.back = Some("/settings/network".to_string()); - context.title = Some("Network Data Usage".to_string()); - // check to see if there is a flash message to display - if let Some(flash) = flash { - // add flash message contents to the context object - context.flash_name = Some(flash.kind().to_string()); - context.flash_msg = Some(flash.message().to_string()); - }; - // template_dir is set in Rocket.toml - Template::render("settings/network/data_usage_limits", &context) -} - -#[post("/wifi/usage", data = "")] -pub fn wifi_usage_alerts(thresholds: Form, _auth: Authenticated) -> Flash { - match monitor::update_store(thresholds.into_inner()) { - Ok(_) => { - debug!("WiFi data usage thresholds updated."); - Flash::success( - Redirect::to("/settings/network/wifi/usage"), - "Updated alert thresholds and flags", - ) - } - Err(_) => { - warn!("Failed to update WiFi data usage thresholds."); - Flash::error( - Redirect::to("/settings/network/wifi/usage"), - "Failed to update alert thresholds and flags", - ) - } - } -} diff --git a/peach-web/src/routes/settings/network/add_ap.rs b/peach-web/src/routes/settings/network/add_ap.rs new file mode 100644 index 0000000..e69de29 diff --git a/peach-web/src/routes/settings/network/ap_details.rs b/peach-web/src/routes/settings/network/ap_details.rs new file mode 100644 index 0000000..e69de29 diff --git a/peach-web/src/routes/settings/network/configure_dns.rs b/peach-web/src/routes/settings/network/configure_dns.rs new file mode 100644 index 0000000..e69de29 diff --git a/peach-web/src/routes/settings/network/data_usage_limits.rs b/peach-web/src/routes/settings/network/data_usage_limits.rs new file mode 100644 index 0000000..e69de29 diff --git a/peach-web/src/routes/settings/network/list_aps.rs b/peach-web/src/routes/settings/network/list_aps.rs new file mode 100644 index 0000000..e69de29 diff --git a/peach-web/src/routes/settings/network/menu.rs b/peach-web/src/routes/settings/network/menu.rs new file mode 100644 index 0000000..dd9f58a --- /dev/null +++ b/peach-web/src/routes/settings/network/menu.rs @@ -0,0 +1,57 @@ +use maud::{html, Markup, PreEscaped}; +use peach_network::network; +use rouille::Request; + +use crate::{ + templates, + utils::{flash::FlashRequest, theme}, +}; + +// ROUTE: /settings/network + +/// Read the wireless interface mode (WiFi AP or client) and selectively render +/// the activation button for the deactivated mode. +fn render_mode_toggle_button() -> Markup { + match network::state("ap0") { + Ok(Some(state)) if state == "up" => { + html! { + a id="connectWifi" class="button button-primary center" href="/settings/network/wifi/activate" title="Enable WiFi" { "Enable WiFi" } + } + } + _ => html! { + a id="deployAccessPoint" class="button button-primary center" href="/settings/network/ap/activate" title="Deploy Access Point" { "Deploy Access Point" } + }, + } +} + +/// Network settings menu template builder. +pub fn build_template(request: &Request) -> PreEscaped { + let (flash_name, flash_msg) = request.retrieve_flash(); + + let menu_template = html! { + (PreEscaped("")) + div class="card center" { + (PreEscaped("")) + div id="buttons" { + a class="button button-primary center" href="/settings/network/wifi/add" title="Add WiFi Network" { "Add WiFi Network" } + a id="configureDNS" class="button button-primary center" href="/settings/network/dns" title="Configure DNS" { "Configure DNS" } + (PreEscaped("")) + (render_mode_toggle_button()) + a id="listWifi" class="button button-primary center" href="/settings/network/wifi" title="List WiFi Networks" { "List WiFi Networks" } + a id="viewUsage" class="button button-primary center" href="/settings/network/wifi/usage" title="View Data Usage" { "View Data Usage" } + a id="viewStatus" class="button button-primary center" href="/status/network" title="View Network Status" { "View Network Status" } + } + // render flash message if cookies were found in the request + @if let (Some(name), Some(msg)) = (flash_name, flash_msg) { + (PreEscaped("")) + (templates::flash::build_template(name, msg)) + } + } + }; + + let body = templates::nav::build_template(menu_template, "Network Settings", Some("/settings")); + + let theme = theme::get_theme(); + + templates::base::build_template(body, theme) +} diff --git a/peach-web/src/routes/settings/network/mod.rs b/peach-web/src/routes/settings/network/mod.rs new file mode 100644 index 0000000..b9a0e3e --- /dev/null +++ b/peach-web/src/routes/settings/network/mod.rs @@ -0,0 +1 @@ +pub mod menu; diff --git a/peach-web/src/routes/settings/network/modify_ap.rs b/peach-web/src/routes/settings/network/modify_ap.rs new file mode 100644 index 0000000..e69de29