From 04011e4f1a9aa6ce809757e667a7f8684f7c2681 Mon Sep 17 00:00:00 2001 From: notplants Date: Mon, 8 Nov 2021 16:38:10 +0100 Subject: [PATCH] Add rocket authentication to all routes --- Cargo.lock | 22 +++++- peach-lib/Cargo.toml | 1 + peach-lib/src/config_manager.rs | 39 +++++++++- peach-lib/src/error.rs | 2 + peach-lib/src/password_utils.rs | 96 ++++++++++-------------- peach-web/src/main.rs | 1 + peach-web/src/routes/authentication.rs | 19 +++-- peach-web/src/routes/device.rs | 13 ++-- peach-web/src/routes/index.rs | 4 +- peach-web/src/routes/ping.rs | 6 +- peach-web/src/routes/scuttlebutt.rs | 8 +- peach-web/src/routes/settings/admin.rs | 9 ++- peach-web/src/routes/settings/dns.rs | 7 +- peach-web/src/routes/settings/network.rs | 63 ++++++++-------- peach-web/static/js/common.js | 9 --- peach-web/templates/login.html.tera | 4 +- peach-web/templates/nav.html.tera | 2 +- 17 files changed, 172 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9465229..be13e3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2582,6 +2582,7 @@ dependencies = [ "log 0.4.14", "rand 0.8.4", "regex", + "rust-crypto", "serde 1.0.130", "serde_derive", "serde_json", @@ -2870,7 +2871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f77e66f6d6d898cbbd4a09c48fd3507cfc210b7c83055de02a38b5f7a1e6d216" dependencies = [ "libc", - "time 0.1.44", + "time 0.2.27", ] [[package]] @@ -3380,12 +3381,31 @@ dependencies = [ "uncased", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time 0.1.44", +] + [[package]] name = "rustc-demangle" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.1.7" diff --git a/peach-lib/Cargo.toml b/peach-lib/Cargo.toml index 5d56455..e7e77b3 100644 --- a/peach-lib/Cargo.toml +++ b/peach-lib/Cargo.toml @@ -12,6 +12,7 @@ jsonrpc-client-core = "0.5" jsonrpc-client-http = "0.5" jsonrpc-core = "8.0.1" serde = { version = "1.0", features = ["derive"] } +rust-crypto = "0.2.36" serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.8" diff --git a/peach-lib/src/config_manager.rs b/peach-lib/src/config_manager.rs index 735866a..5940706 100644 --- a/peach-lib/src/config_manager.rs +++ b/peach-lib/src/config_manager.rs @@ -4,12 +4,13 @@ //! //! The configuration file is located at: "/var/lib/peachcloud/config.yml" -use fslock::LockFile; +use fslock::{LockFile, IntoOsString}; use serde::{Deserialize, Serialize}; use std::fs; use crate::error::PeachError; use crate::error::*; +use crate::password_utils::hash_password; // main configuration file pub const YAML_PATH: &str = "/var/lib/peachcloud/config.yml"; @@ -34,6 +35,10 @@ pub struct PeachConfig { pub dyn_enabled: bool, #[serde(default)] // default is empty vector pub ssb_admin_ids: Vec, + #[serde(default)] + pub admin_password_hash: String, + #[serde(default)] + pub temporary_password_hash: String, } // helper functions for serializing and deserializing PeachConfig from disc @@ -69,6 +74,8 @@ pub fn load_peach_config() -> Result { dyn_tsig_key_path: "".to_string(), dyn_enabled: false, ssb_admin_ids: Vec::new(), + admin_password_hash: "".to_string(), + temporary_password_hash: "".to_string(), }; } // otherwise we load peach config from disk @@ -141,3 +148,33 @@ pub fn delete_ssb_admin_id(ssb_id: &str) -> Result { }), } } + +pub fn set_admin_password_hash(password_hash: &str) -> Result { + let mut peach_config = load_peach_config()?; + peach_config.admin_password_hash = password_hash.to_string(); + save_peach_config(peach_config) +} + +pub fn get_admin_password_hash() -> Result { + let peach_config = load_peach_config()?; + if !peach_config.admin_password_hash.is_empty() { + Ok(peach_config.admin_password_hash) + } else { + Err(PeachError::PasswordNotSet) + } +} + +pub fn set_temporary_password_hash(password_hash: &str) -> Result { + let mut peach_config = load_peach_config()?; + peach_config.temporary_password_hash = password_hash.to_string(); + save_peach_config(peach_config) +} + +pub fn get_temporary_password_hash() -> Result { + let peach_config = load_peach_config()?; + if !peach_config.temporary_password_hash.is_empty() { + Ok(peach_config.temporary_password_hash) + } else { + Err(PeachError::PasswordNotSet) + } +} \ No newline at end of file diff --git a/peach-lib/src/error.rs b/peach-lib/src/error.rs index 0068263..96e7b4b 100644 --- a/peach-lib/src/error.rs +++ b/peach-lib/src/error.rs @@ -63,6 +63,8 @@ pub enum PeachError { SaveDynDnsResultError { source: std::io::Error }, #[snafu(display("New passwords do not match"))] PasswordsDoNotMatch, + #[snafu(display("No admin password is set"))] + PasswordNotSet, #[snafu(display("The supplied password was not correct"))] InvalidPassword, #[snafu(display("Error saving new password: {}", msg))] diff --git a/peach-lib/src/password_utils.rs b/peach-lib/src/password_utils.rs index c35edbd..f0e84b9 100644 --- a/peach-lib/src/password_utils.rs +++ b/peach-lib/src/password_utils.rs @@ -1,34 +1,24 @@ -use crate::config_manager::{get_peachcloud_domain, load_peach_config}; +use crate::config_manager::{get_peachcloud_domain, load_peach_config, + set_admin_password_hash, get_admin_password_hash, + get_temporary_password_hash, set_temporary_password_hash}; use crate::error::PeachError; use crate::error::StdIoError; use crate::sbot_client; +use log::info; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use snafu::ResultExt; use std::iter; use std::process::Command; - -/// filepath where nginx basic auth passwords are stored -pub const HTPASSWD_FILE: &str = "/var/lib/peachcloud/passwords/htpasswd"; -/// filepath where random temporary password is stored for password resets -pub const HTPASSWD_TEMPORARY_PASSWORD_FILE: &str = - "/var/lib/peachcloud/passwords/temporary_password"; -/// the username of the user for nginx basic auth -pub const PEACHCLOUD_AUTH_USER: &str = "admin"; +use crypto::digest::Digest; +use crypto::sha3::Sha3; /// Returns Ok(()) if the supplied password is correct, /// and returns Err if the supplied password is incorrect. pub fn verify_password(password: &str) -> Result<(), PeachError> { - let output = Command::new("/usr/bin/htpasswd") - .arg("-vb") - .arg(HTPASSWD_FILE) - .arg(PEACHCLOUD_AUTH_USER) - .arg(password) - .output() - .context(StdIoError { - msg: "htpasswd is not installed", - })?; - if output.status.success() { + let real_admin_password_hash = get_admin_password_hash()?; + let password_hash = hash_password(&password.to_string()); + if real_admin_password_hash == password_hash { Ok(()) } else { Err(PeachError::InvalidPassword) @@ -49,57 +39,46 @@ pub fn validate_new_passwords(new_password1: &str, new_password2: &str) -> Resul /// Uses htpasswd to set a new password for the admin user pub fn set_new_password(new_password: &str) -> Result<(), PeachError> { - let output = Command::new("/usr/bin/htpasswd") - .arg("-cb") - .arg(HTPASSWD_FILE) - .arg(PEACHCLOUD_AUTH_USER) - .arg(new_password) - .output() - .context(StdIoError { - msg: "htpasswd is not installed", - })?; - if output.status.success() { - Ok(()) - } else { - let err_output = String::from_utf8(output.stderr)?; - Err(PeachError::FailedToSetNewPassword { msg: err_output }) + let new_password_hash = hash_password(&new_password.to_string()); + let result = set_admin_password_hash(&new_password_hash); + match result { + Ok(_) => { + Ok(()) + }, + Err(err) => { + Err(PeachError::FailedToSetNewPassword { msg: "failed to save password hash".to_string() }) + } } } +/// Creates a hash from a password string +pub fn hash_password(password: &String) -> String { + let mut hasher = Sha3::sha3_256(); + hasher.input_str(password); + hasher.result_str() +} + /// Uses htpasswd to set a new temporary password for the admin user /// which can be used to reset the permanent password pub fn set_new_temporary_password(new_password: &str) -> Result<(), PeachError> { - let output = Command::new("/usr/bin/htpasswd") - .arg("-cb") - .arg(HTPASSWD_TEMPORARY_PASSWORD_FILE) - .arg(PEACHCLOUD_AUTH_USER) - .arg(new_password) - .output() - .context(StdIoError { - msg: "htpasswd is not installed", - })?; - if output.status.success() { - Ok(()) - } else { - let err_output = String::from_utf8(output.stderr)?; - Err(PeachError::FailedToSetNewPassword { msg: err_output }) + let new_password_hash = hash_password(&new_password.to_string()); + let result = set_temporary_password_hash(&new_password_hash); + match result { + Ok(_) => { + Ok(()) + }, + Err(err) => { + Err(PeachError::FailedToSetNewPassword { msg: "failed to save temporary password hash".to_string() }) + } } } /// Returns Ok(()) if the supplied temp_password is correct, /// and returns Err if the supplied temp_password is incorrect pub fn verify_temporary_password(password: &str) -> Result<(), PeachError> { - // TODO: confirm temporary password has not expired - let output = Command::new("/usr/bin/htpasswd") - .arg("-vb") - .arg(HTPASSWD_TEMPORARY_PASSWORD_FILE) - .arg(PEACHCLOUD_AUTH_USER) - .arg(password) - .output() - .context(StdIoError { - msg: "htpasswd is not installed", - })?; - if output.status.success() { + let temporary_admin_password_hash = get_temporary_password_hash()?; + let password_hash = hash_password(&password.to_string()); + if temporary_admin_password_hash == password_hash { Ok(()) } else { Err(PeachError::InvalidPassword) @@ -143,6 +122,7 @@ using this link: http://peach.local/reset_password", msg += &remote_link; // finally send the message to the admins let peach_config = load_peach_config()?; + info!("sending password reset: {}", msg); for ssb_admin_id in peach_config.ssb_admin_ids { sbot_client::private_message(&msg, &ssb_admin_id)?; } diff --git a/peach-web/src/main.rs b/peach-web/src/main.rs index edd17bd..1f12ab2 100644 --- a/peach-web/src/main.rs +++ b/peach-web/src/main.rs @@ -87,6 +87,7 @@ fn init_rocket() -> Rocket { configure_dns, // WEB ROUTE configure_dns_post, // WEB ROUTE change_password, // WEB ROUTE + change_password_post, // WEB ROUTE reset_password, // WEB ROUTE reset_password_post, // WEB ROUTE send_password_reset_page, // WEB ROUTE diff --git a/peach-web/src/routes/authentication.rs b/peach-web/src/routes/authentication.rs index ef780d5..1e324c6 100644 --- a/peach-web/src/routes/authentication.rs +++ b/peach-web/src/routes/authentication.rs @@ -49,14 +49,12 @@ impl<'r> FromRequest<'r> for Authenticated { .cookies() .get_private(AUTH_COOKIE_KEY) .and_then(|cookie| cookie.value().parse().ok()) - .map(|value: String| { info!("cookie value: {}", value); Authenticated { is_authenticated: true } }); + .map(|value: String| { Authenticated { is_authenticated: true } }); match authenticated { Some(auth) => { - info!("Authenticated!"); request::Outcome::Success(auth) }, None => { - info!("not authenticated!"); request::Outcome::Failure((Status::Forbidden, LoginError::UsernameDoesNotExist)) } } @@ -125,16 +123,17 @@ pub fn login_post(login_form: Form, cookies: &CookieJar<'_>) -> Templ // NOTE: since we currently have just one user, the value of the cookie // is just admin (this is arbitrary). // If we had multiple users, we could put the user_id here. - info!("successfull password form"); cookies.add_private(Cookie::new(AUTH_COOKIE_KEY, ADMIN_USERNAME)); TemplateOrRedirect::Redirect(Redirect::to("/")) } Err(_) => { - info!("invalid password form"); // if unsuccessful login, render /login page again let mut context = LoginContext::build(); context.back = Some("/".to_string()); context.title = Some("Login".to_string()); + context.flash_name = Some("error".to_string()); + let flash_msg = "Invalid password".to_string(); + context.flash_msg = Some(flash_msg); TemplateOrRedirect::Template(Template::render("login", &context)) } } @@ -146,9 +145,9 @@ pub fn login_post(login_form: Form, cookies: &CookieJar<'_>) -> Templ #[get("/logout")] pub fn logout(cookies: &CookieJar<'_>) -> Flash { // logout authenticated user - debug!("Attempting deauthentication of user."); + info!("Attempting deauthentication of user."); cookies.remove_private(Cookie::named(AUTH_COOKIE_KEY)); - Flash::success(Redirect::to("/"), "Logged out") + Flash::success(Redirect::to("/login"), "Logged out") } @@ -376,7 +375,7 @@ pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebErr /// Change password request handler. This is used by a user who is already logged in. #[get("/settings/change_password")] -pub fn change_password(flash: Option) -> Template { +pub fn change_password(flash: Option, auth: Authenticated) -> Template { let mut context = ChangePasswordContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); @@ -392,7 +391,7 @@ pub fn change_password(flash: Option) -> Template { /// Change password form request handler. This route is used by a user who is already logged in. #[post("/settings/change_password", data = "")] -pub fn change_password_post(password_form: Form) -> Template { +pub fn change_password_post(password_form: Form, auth: Authenticated) -> Template { let result = save_password_form(password_form.into_inner()); match result { Ok(_) => { @@ -419,7 +418,7 @@ pub fn change_password_post(password_form: Form) -> Template { /// JSON change password form request handler. #[post("/api/v1/settings/change_password", data = "")] -pub fn save_password_form_endpoint(password_form: Json) -> Value { +pub fn save_password_form_endpoint(password_form: Json, auth: Authenticated) -> Value { let result = save_password_form(password_form.into_inner()); match result { Ok(_) => { diff --git a/peach-web/src/routes/device.rs b/peach-web/src/routes/device.rs index 73b2aaf..ef5af99 100644 --- a/peach-web/src/routes/device.rs +++ b/peach-web/src/routes/device.rs @@ -17,6 +17,7 @@ use peach_lib::stats_client::{CpuStatPercentages, DiskUsage, LoadAverage, MemSta use peach_lib::{dyndns_client, network_client, oled_client, sbot_client, stats_client}; use crate::utils::build_json_response; +use crate::routes::authentication::Authenticated; use rocket::serde::json::Value; // HELPERS AND ROUTES FOR /device @@ -150,7 +151,7 @@ impl DeviceContext { } #[get("/device")] -pub fn device_stats(flash: Option) -> Template { +pub fn device_stats(flash: Option, auth: Authenticated) -> Template { // assign context through context_builder call let mut context = DeviceContext::build(); context.back = Some("/".to_string()); @@ -181,7 +182,7 @@ pub fn reboot() -> io::Result { } #[get("/device/reboot")] -pub fn reboot_cmd() -> Flash { +pub fn reboot_cmd(auth: Authenticated) -> Flash { match reboot() { Ok(_) => Flash::success(Redirect::to("/shutdown"), "Rebooting the device"), Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to reboot the device"), @@ -190,7 +191,7 @@ pub fn reboot_cmd() -> Flash { /// JSON request handler for device reboot. #[post("/api/v1/device/reboot")] -pub fn reboot_device() -> Value { +pub fn reboot_device(auth: Authenticated) -> Value { match reboot() { Ok(_) => { debug!("Going down for reboot..."); @@ -219,7 +220,7 @@ pub fn shutdown() -> io::Result { } #[get("/device/shutdown")] -pub fn shutdown_cmd() -> Flash { +pub fn shutdown_cmd(auth: Authenticated) -> Flash { match shutdown() { Ok(_) => Flash::success(Redirect::to("/shutdown"), "Shutting down the device"), Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to shutdown the device"), @@ -228,7 +229,7 @@ pub fn shutdown_cmd() -> Flash { // shutdown the device #[post("/api/v1/device/shutdown")] -pub fn shutdown_device() -> Value { +pub fn shutdown_device(auth: Authenticated) -> Value { match shutdown() { Ok(_) => { debug!("Going down for shutdown..."); @@ -267,7 +268,7 @@ impl ShutdownContext { } #[get("/shutdown")] -pub fn shutdown_menu(flash: Option) -> Template { +pub fn shutdown_menu(flash: Option, auth: Authenticated) -> Template { let mut context = ShutdownContext::build(); context.back = Some("/".to_string()); context.title = Some("Shutdown Device".to_string()); diff --git a/peach-web/src/routes/index.rs b/peach-web/src/routes/index.rs index 4a89487..2d976f5 100644 --- a/peach-web/src/routes/index.rs +++ b/peach-web/src/routes/index.rs @@ -2,6 +2,8 @@ use rocket::{get, request::FlashMessage}; use rocket_dyn_templates::Template; use serde::Serialize; +use crate::routes::authentication::Authenticated; + // HELPERS AND ROUTES FOR / (HOME PAGE) #[derive(Debug, Serialize)] @@ -22,7 +24,7 @@ impl HomeContext { } #[get("/")] -pub fn index() -> Template { +pub fn index(auth: Authenticated) -> Template { let context = HomeContext { flash_name: None, flash_msg: None, diff --git a/peach-web/src/routes/ping.rs b/peach-web/src/routes/ping.rs index e9fc7c1..0c94141 100644 --- a/peach-web/src/routes/ping.rs +++ b/peach-web/src/routes/ping.rs @@ -22,7 +22,7 @@ pub fn ping_pong(auth: Authenticated) -> Value { /// Status route: check availability of `peach-network` microservice. #[get("/api/v1/ping/network")] -pub fn ping_network() -> Value { +pub fn ping_network(auth: Authenticated) -> Value { match network_client::ping() { Ok(_) => { debug!("peach-network responded successfully"); @@ -41,7 +41,7 @@ pub fn ping_network() -> Value { /// Status route: check availability of `peach-oled` microservice. #[get("/api/v1/ping/oled")] -pub fn ping_oled() -> Value { +pub fn ping_oled(auth: Authenticated) -> Value { match oled_client::ping() { Ok(_) => { debug!("peach-oled responded successfully"); @@ -60,7 +60,7 @@ pub fn ping_oled() -> Value { /// Status route: check availability of `peach-stats` microservice. #[get("/api/v1/ping/stats")] -pub fn ping_stats() -> Value { +pub fn ping_stats(auth: Authenticated) -> Value { match stats_client::ping() { Ok(_) => { debug!("peach-stats responded successfully"); diff --git a/peach-web/src/routes/scuttlebutt.rs b/peach-web/src/routes/scuttlebutt.rs index 9a705a8..1934ce7 100644 --- a/peach-web/src/routes/scuttlebutt.rs +++ b/peach-web/src/routes/scuttlebutt.rs @@ -4,6 +4,8 @@ use rocket::{get, request::FlashMessage}; use rocket_dyn_templates::Template; use serde::Serialize; +use crate::routes::authentication::Authenticated; + // HELPERS AND ROUTES FOR /messages #[derive(Debug, Serialize)] @@ -26,7 +28,7 @@ impl MessageContext { } #[get("/messages")] -pub fn messages(flash: Option) -> Template { +pub fn messages(flash: Option, auth: Authenticated) -> Template { let mut context = MessageContext::build(); context.back = Some("/".to_string()); context.title = Some("Private Messages".to_string()); @@ -61,7 +63,7 @@ impl PeerContext { } #[get("/peers")] -pub fn peers(flash: Option) -> Template { +pub fn peers(flash: Option, auth: Authenticated) -> Template { let mut context = PeerContext::build(); context.back = Some("/".to_string()); context.title = Some("Scuttlebutt Peers".to_string()); @@ -96,7 +98,7 @@ impl ProfileContext { } #[get("/profile")] -pub fn profile(flash: Option) -> Template { +pub fn profile(flash: Option, auth: Authenticated) -> Template { let mut context = ProfileContext::build(); context.back = Some("/".to_string()); context.title = Some("Profile".to_string()); diff --git a/peach-web/src/routes/settings/admin.rs b/peach-web/src/routes/settings/admin.rs index a688744..899c2f8 100644 --- a/peach-web/src/routes/settings/admin.rs +++ b/peach-web/src/routes/settings/admin.rs @@ -12,6 +12,7 @@ use peach_lib::config_manager; use peach_lib::config_manager::load_peach_config; use crate::error::PeachWebError; +use crate::routes::authentication::Authenticated; // HELPERS AND ROUTES FOR /settings/configure_admin @@ -40,7 +41,7 @@ impl ConfigureAdminContext { /// View and delete currently configured admin. #[get("/settings/configure_admin")] -pub fn configure_admin(flash: Option) -> Template { +pub fn configure_admin(flash: Option, auth: Authenticated) -> Template { let mut context = ConfigureAdminContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); @@ -87,7 +88,7 @@ pub fn save_add_admin_form(admin_form: AddAdminForm) -> Result<(), PeachWebError } #[get("/settings/admin/add")] -pub fn add_admin(flash: Option) -> Template { +pub fn add_admin(flash: Option, auth: Authenticated) -> Template { let mut context = AddAdminContext::build(); context.back = Some("/settings/configure_admin".to_string()); context.title = Some("Add Admin".to_string()); @@ -102,7 +103,7 @@ pub fn add_admin(flash: Option) -> Template { } #[post("/settings/admin/add", data = "")] -pub fn add_admin_post(add_admin_form: Form) -> Flash { +pub fn add_admin_post(add_admin_form: Form, auth: Authenticated) -> Flash { let result = save_add_admin_form(add_admin_form.into_inner()); let url = uri!(configure_admin); match result { @@ -119,7 +120,7 @@ pub struct DeleteAdminForm { } #[post("/settings/admin/delete", data = "")] -pub fn delete_admin_post(delete_admin_form: Form) -> Flash { +pub fn delete_admin_post(delete_admin_form: Form, auth: Authenticated) -> Flash { let result = config_manager::delete_ssb_admin_id(&delete_admin_form.ssb_id); let url = uri!(configure_admin); match result { diff --git a/peach-web/src/routes/settings/dns.rs b/peach-web/src/routes/settings/dns.rs index 6b021a3..5b3df65 100644 --- a/peach-web/src/routes/settings/dns.rs +++ b/peach-web/src/routes/settings/dns.rs @@ -20,6 +20,7 @@ use peach_lib::jsonrpc_client_core::{Error, ErrorKind}; use peach_lib::jsonrpc_core::types::error::ErrorCode; use crate::error::PeachWebError; +use crate::routes::authentication::Authenticated; use crate::utils::build_json_response; use rocket::serde::json::Value; @@ -113,7 +114,7 @@ impl ConfigureDNSContext { } #[get("/network/dns")] -pub fn configure_dns(flash: Option) -> Template { +pub fn configure_dns(flash: Option, auth: Authenticated) -> Template { let mut context = ConfigureDNSContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); @@ -128,7 +129,7 @@ pub fn configure_dns(flash: Option) -> Template { } #[post("/network/dns", data = "")] -pub fn configure_dns_post(dns: Form) -> Template { +pub fn configure_dns_post(dns: Form, auth: Authenticated) -> Template { let result = save_dns_configuration(dns.into_inner()); match result { Ok(_) => { @@ -153,7 +154,7 @@ pub fn configure_dns_post(dns: Form) -> Template { } #[post("/api/v1/dns/configure", data = "")] -pub fn save_dns_configuration_endpoint(dns_form: Json) -> Value { +pub fn save_dns_configuration_endpoint(dns_form: Json, auth: Authenticated) -> Value { let result = save_dns_configuration(dns_form.into_inner()); match result { Ok(_) => { diff --git a/peach-web/src/routes/settings/network.rs b/peach-web/src/routes/settings/network.rs index 28fddd8..0c07092 100644 --- a/peach-web/src/routes/settings/network.rs +++ b/peach-web/src/routes/settings/network.rs @@ -20,6 +20,7 @@ use peach_lib::stats_client::Traffic; use crate::utils::monitor; use crate::utils::monitor::{Alert, Data, Threshold}; use crate::utils::build_json_response; +use crate::routes::authentication::Authenticated; use rocket::serde::json::Value; // STRUCTS USED BY NETWORK ROUTES @@ -38,7 +39,7 @@ pub struct WiFi { // HELPERS AND ROUTES FOR /network/wifi/usage/reset #[get("/network/wifi/usage/reset")] -pub fn wifi_usage_reset() -> Flash { +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"), @@ -50,7 +51,7 @@ pub fn wifi_usage_reset() -> Flash { } #[post("/network/wifi/connect", data = "")] -pub fn connect_wifi(network: Form) -> Flash { +pub fn connect_wifi(network: Form, auth: Authenticated) -> Flash { let ssid = &network.ssid; let url = uri!(network_detail(ssid = ssid)); match network_client::id("wlan0", ssid) { @@ -63,7 +64,7 @@ pub fn connect_wifi(network: Form) -> Flash { } #[post("/network/wifi/disconnect", data = "")] -pub fn disconnect_wifi(network: Form) -> Flash { +pub fn disconnect_wifi(network: Form, auth: Authenticated) -> Flash { let ssid = &network.ssid; let url = uri!(network_home); match network_client::disable("wlan0", ssid) { @@ -73,7 +74,7 @@ pub fn disconnect_wifi(network: Form) -> Flash { } #[post("/network/wifi/forget", data = "")] -pub fn forget_wifi(network: Form) -> Flash { +pub fn forget_wifi(network: Form, auth: Authenticated) -> Flash { let ssid = &network.ssid; let url = uri!(network_home); match network_client::forget("wlan0", ssid) { @@ -86,7 +87,7 @@ pub fn forget_wifi(network: Form) -> Flash { } #[get("/network/wifi/modify?")] -pub fn wifi_password(ssid: &str, flash: Option) -> Template { +pub fn wifi_password(ssid: &str, flash: Option, auth: Authenticated) -> Template { let mut context = NetworkAddContext { back: Some("/network/wifi".to_string()), flash_name: None, @@ -105,7 +106,7 @@ pub fn wifi_password(ssid: &str, flash: Option) -> Template { } #[post("/network/wifi/modify", data = "")] -pub fn wifi_set_password(wifi: Form) -> Flash { +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)); @@ -273,7 +274,7 @@ impl NetworkContext { } #[get("/network")] -pub fn network_home(flash: Option) -> Template { +pub fn network_home(flash: Option, auth: Authenticated) -> Template { // assign context through context_builder call let mut context = NetworkContext::build(); // set back button (nav) url @@ -293,7 +294,7 @@ pub fn network_home(flash: Option) -> Template { // HELPERS AND ROUTES FOR /network/ap/activate #[get("/network/ap/activate")] -pub fn deploy_ap() -> Flash { +pub fn deploy_ap(auth: Authenticated) -> Flash { // activate the wireless access point debug!("Activating WiFi access point."); match network_client::activate_ap() { @@ -375,7 +376,7 @@ impl NetworkListContext { } #[get("/network/wifi")] -pub fn wifi_list(flash: Option) -> Template { +pub fn wifi_list(flash: Option, auth: Authenticated) -> Template { // assign context through context_builder call let mut context = NetworkListContext::build(); context.back = Some("/network".to_string()); @@ -540,7 +541,7 @@ impl NetworkDetailContext { } #[get("/network/wifi?")] -pub fn network_detail(ssid: &str, flash: Option) -> Template { +pub fn network_detail(ssid: &str, flash: Option, auth: Authenticated) -> Template { // assign context through context_builder call let mut context = NetworkDetailContext::build(); context.back = Some("/network/wifi".to_string()); @@ -559,7 +560,7 @@ pub fn network_detail(ssid: &str, flash: Option) -> Template { // HELPERS AND ROUTES FOR /network/wifi/activate #[get("/network/wifi/activate")] -pub fn deploy_client() -> Flash { +pub fn deploy_client(auth: Authenticated) -> Flash { // activate the wireless client debug!("Activating WiFi client mode."); match network_client::activate_client() { @@ -571,7 +572,7 @@ pub fn deploy_client() -> Flash { // HELPERS AND ROUTES FOR /network/wifi/add #[get("/network/wifi/add")] -pub fn network_add_wifi(flash: Option) -> Template { +pub fn network_add_wifi(flash: Option, auth: Authenticated) -> Template { let mut context = NetworkContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); @@ -609,7 +610,7 @@ impl NetworkAddContext { } #[get("/network/wifi/add?")] -pub fn network_add_ssid(ssid: &str, flash: Option) -> Template { +pub fn network_add_ssid(ssid: &str, flash: Option, auth: Authenticated) -> Template { let mut context = NetworkAddContext::build(); context.back = Some("/network/wifi".to_string()); context.selected = Some(ssid.to_string()); @@ -625,7 +626,7 @@ pub fn network_add_ssid(ssid: &str, flash: Option) -> Template { } #[post("/network/wifi/add", data = "")] -pub fn add_credentials(wifi: Form) -> Template { +pub fn add_credentials(wifi: Form, auth: Authenticated) -> Template { // 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) @@ -719,7 +720,7 @@ impl NetworkAlertContext { } #[get("/network/wifi/usage")] -pub fn wifi_usage(flash: Option) -> Template { +pub fn wifi_usage(flash: Option, auth: Authenticated) -> Template { let mut context = NetworkAlertContext::build(); // set back icon link to network route context.back = Some("/network".to_string()); @@ -735,7 +736,7 @@ pub fn wifi_usage(flash: Option) -> Template { } #[post("/network/wifi/usage", data = "")] -pub fn wifi_usage_alerts(thresholds: Form) -> Flash { +pub fn wifi_usage_alerts(thresholds: Form, auth: Authenticated) -> Flash { match monitor::update_store(thresholds.into_inner()) { Ok(_) => { debug!("WiFi data usage thresholds updated."); @@ -755,7 +756,7 @@ pub fn wifi_usage_alerts(thresholds: Form) -> Flash { } #[post("/api/v1/network/wifi/usage", data = "")] -pub fn update_wifi_alerts(thresholds: Json) -> Value { +pub fn update_wifi_alerts(thresholds: Json, auth: Authenticated) -> Value { match monitor::update_store(thresholds.into_inner()) { Ok(_) => { debug!("WiFi data usage thresholds updated."); @@ -773,7 +774,7 @@ pub fn update_wifi_alerts(thresholds: Json) -> Value { } #[post("/api/v1/network/wifi/usage/reset")] -pub fn reset_data_total() -> Value { +pub fn reset_data_total(auth: Authenticated) -> Value { match monitor::reset_data() { Ok(_) => { debug!("Reset network data usage total."); @@ -805,7 +806,7 @@ pub fn reset_data_total() -> Value { // HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION #[post("/api/v1/network/activate_ap")] -pub fn activate_ap() -> Value { +pub fn activate_ap(auth: Authenticated) -> Value { // activate the wireless access point debug!("Activating WiFi access point."); match network_client::activate_ap() { @@ -824,7 +825,7 @@ pub fn activate_ap() -> Value { // HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT #[post("/api/v1/network/activate_client")] -pub fn activate_client() -> Value { +pub fn activate_client(auth: Authenticated) -> Value { // activate the wireless client debug!("Activating WiFi client mode."); match network_client::activate_client() { @@ -841,7 +842,7 @@ pub fn activate_client() -> Value { } #[post("/api/v1/network/wifi", data = "")] -pub fn add_wifi(wifi: Json) -> Value { +pub fn add_wifi(wifi: Json, auth: Authenticated) -> Value { // generate and write wifi config to wpa_supplicant match network_client::add(&wifi.ssid, &wifi.pass) { Ok(_) => { @@ -867,7 +868,7 @@ pub fn add_wifi(wifi: Json) -> Value { } #[post("/api/v1/network/wifi/connect", data = "")] -pub fn connect_ap(ssid: Json) -> Value { +pub fn connect_ap(ssid: Json, auth: Authenticated) -> Value { // retrieve the id for the given network ssid match network_client::id("wlan0", &ssid.ssid) { // attempt connection with the given network @@ -892,7 +893,7 @@ pub fn connect_ap(ssid: Json) -> Value { } #[post("/api/v1/network/wifi/disconnect", data = "")] -pub fn disconnect_ap(ssid: Json) -> Value { +pub fn disconnect_ap(ssid: Json, auth: Authenticated) -> Value { // attempt to disable the current network for wlan0 interface match network_client::disable("wlan0", &ssid.ssid) { Ok(_) => { @@ -909,7 +910,7 @@ pub fn disconnect_ap(ssid: Json) -> Value { } #[post("/api/v1/network/wifi/forget", data = "")] -pub fn forget_ap(network: Json) -> Value { +pub fn forget_ap(network: Json, auth: Authenticated) -> Value { let ssid = &network.ssid; match network_client::forget("wlan0", ssid) { Ok(_) => { @@ -928,7 +929,7 @@ pub fn forget_ap(network: Json) -> Value { } #[post("/api/v1/network/wifi/modify", data = "")] -pub fn modify_password(wifi: Json) -> Value { +pub fn modify_password(wifi: Json, auth: Authenticated) -> Value { let ssid = &wifi.ssid; let pass = &wifi.pass; // we are using a helper function (`update`) to delete the old @@ -953,7 +954,7 @@ pub fn modify_password(wifi: Json) -> Value { // HELPERS AND ROUTES FOR NETWORK STATE QUERIES #[get("/api/v1/network/ip")] -pub fn return_ip() -> Value { +pub fn return_ip(auth: Authenticated) -> Value { // retrieve ip for wlan0 or set to x.x.x.x if not found let wlan_ip = match network_client::ip("wlan0") { Ok(ip) => ip, @@ -973,7 +974,7 @@ pub fn return_ip() -> Value { } #[get("/api/v1/network/rssi")] -pub fn return_rssi() -> Value { +pub fn return_rssi(auth: Authenticated) -> Value { // retrieve rssi for connected network match network_client::rssi("wlan0") { Ok(rssi) => { @@ -990,7 +991,7 @@ pub fn return_rssi() -> Value { } #[get("/api/v1/network/ssid")] -pub fn return_ssid() -> Value { +pub fn return_ssid(auth: Authenticated) -> Value { // retrieve ssid for connected network match network_client::ssid("wlan0") { Ok(network) => { @@ -1007,7 +1008,7 @@ pub fn return_ssid() -> Value { } #[get("/api/v1/network/state")] -pub fn return_state() -> Value { +pub fn return_state(auth: Authenticated) -> Value { // retrieve state of wlan0 or set to x.x.x.x if not found let wlan_state = match network_client::state("wlan0") { Ok(state) => state, @@ -1027,7 +1028,7 @@ pub fn return_state() -> Value { } #[get("/api/v1/network/status")] -pub fn return_status() -> Value { +pub fn return_status(auth: Authenticated) -> Value { // retrieve status info for wlan0 interface match network_client::status("wlan0") { Ok(network) => { @@ -1044,7 +1045,7 @@ pub fn return_status() -> Value { } #[get("/api/v1/network/wifi")] -pub fn scan_networks() -> Value { +pub fn scan_networks(auth: Authenticated) -> Value { // retrieve scan results for access-points within range of wlan0 match network_client::available_networks("wlan0") { Ok(networks) => { diff --git a/peach-web/static/js/common.js b/peach-web/static/js/common.js index 9a5d8a4..05167d2 100644 --- a/peach-web/static/js/common.js +++ b/peach-web/static/js/common.js @@ -43,14 +43,5 @@ PEACH.flashMsg = function(status, msg) { } } -// add click event to logout button which logs out of http basic auth -// by "trying to login" with invalid credentials (user@logout) -document.getElementById('logoutButton').onclick = function(e){ - e.preventDefault(); - var logoutUrl = "http://user:logout@" + window.location.hostname - window.location = logoutUrl; -} - var addInstance = PEACH; addInstance.add(); -addInstance.logout(); diff --git a/peach-web/templates/login.html.tera b/peach-web/templates/login.html.tera index 97390ed..c64943b 100644 --- a/peach-web/templates/login.html.tera +++ b/peach-web/templates/login.html.tera @@ -5,9 +5,9 @@
- + - +
Cancel diff --git a/peach-web/templates/nav.html.tera b/peach-web/templates/nav.html.tera index 004ca7b..33c50e7 100644 --- a/peach-web/templates/nav.html.tera +++ b/peach-web/templates/nav.html.tera @@ -6,7 +6,7 @@ Back

{{ title }}

- + Enter