diff --git a/peach-web/.gitignore b/peach-web/.gitignore index 8f0bd8f..c3e9867 100644 --- a/peach-web/.gitignore +++ b/peach-web/.gitignore @@ -1,8 +1,5 @@ *.bak static/icons/optimized/* -api_docs.md -js_docs.md -hashmap_notes -notes target **/*.rs.bk +leftovers diff --git a/peach-web/src/routes/authentication.rs_old b/peach-web/src/routes/authentication.rs_old deleted file mode 100644 index 3ff8f2b..0000000 --- a/peach-web/src/routes/authentication.rs_old +++ /dev/null @@ -1,333 +0,0 @@ -use log::info; -use rocket::{ - form::{Form, FromForm}, - get, - http::{Cookie, CookieJar, Status}, - post, - request::{self, FlashMessage, FromRequest, Request}, - response::{Flash, Redirect}, -}; -use rocket_dyn_templates::{tera::Context, Template}; - -use peach_lib::{error::PeachError, password_utils}; - -use crate::error::PeachWebError; -use crate::utils; -use crate::utils::TemplateOrRedirect; -use crate::RocketConfig; - -// HELPERS AND STRUCTS FOR AUTHENTICATION WITH COOKIES - -pub const AUTH_COOKIE_KEY: &str = "peachweb_auth"; -pub const ADMIN_USERNAME: &str = "admin"; - -/// Note: Currently we use an empty struct for the Authenticated request guard -/// because there is only one user to be authenticated, and no data needs to be stored here. -/// In a multi-user authentication scheme, we would store the user_id in this struct, -/// and retrieve the correct user via the user_id stored in the cookie. -pub struct Authenticated; - -#[derive(Debug)] -pub enum LoginError { - UserNotLoggedIn, -} - -/// Request guard which returns an empty Authenticated struct from the request -/// if and only if the user has a cookie which proves they are authenticated with peach-web. -/// -/// Note that cookies.get_private uses encryption, which means that this private cookie -/// cannot be inspected, tampered with, or manufactured by clients. -#[rocket::async_trait] -impl<'r> FromRequest<'r> for Authenticated { - type Error = LoginError; - - 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: bool = *req - .rocket() - .state::() - .map(|config| (&config.disable_auth)) - .unwrap_or(&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)), - } - } - } -} - -// HELPERS AND ROUTES FOR /login - -#[get("/login")] -pub fn login(flash: Option) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Login".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("login", &context.into_json()) -} - -#[derive(Debug, FromForm)] -pub struct LoginForm { - pub password: String, -} - -/// Takes in a LoginForm and returns Ok(()) if the password is correct. -/// -/// Note: there is currently only one user, therefore we don't need a username. -pub fn verify_login_form(login_form: LoginForm) -> Result<(), PeachError> { - password_utils::verify_password(&login_form.password) -} - -#[post("/login", data = "")] -pub fn login_post(login_form: Form, cookies: &CookieJar<'_>) -> TemplateOrRedirect { - match verify_login_form(login_form.into_inner()) { - Ok(_) => { - // if successful login, add a cookie indicating the user is authenticated - // and redirect to home page - // 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. - cookies.add_private(Cookie::new(AUTH_COOKIE_KEY, ADMIN_USERNAME)); - - TemplateOrRedirect::Redirect(Redirect::to("/")) - } - Err(e) => { - let err_msg = format!("Invalid password: {}", e); - // if unsuccessful login, render /login page again - let mut context = Context::new(); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Login".to_string())); - context.insert("flash_name", &("error".to_string())); - context.insert("flash_msg", &(err_msg)); - - TemplateOrRedirect::Template(Template::render("login", &context.into_json())) - } - } -} - -// HELPERS AND ROUTES FOR /logout - -#[get("/logout")] -pub fn logout(cookies: &CookieJar<'_>) -> Flash { - // logout authenticated user - info!("Attempting deauthentication of user."); - cookies.remove_private(Cookie::named(AUTH_COOKIE_KEY)); - Flash::success(Redirect::to("/login"), "Logged out") -} - -// HELPERS AND ROUTES FOR /reset_password - -#[derive(Debug, FromForm)] -pub struct ResetPasswordForm { - pub temporary_password: String, - pub new_password1: String, - pub new_password2: String, -} - -/// Verify, validate and save the submitted password. This function is publicly exposed for users who have forgotten their password. -pub fn save_reset_password_form(password_form: ResetPasswordForm) -> Result<(), PeachWebError> { - info!( - "reset password!: {} {} {}", - password_form.temporary_password, password_form.new_password1, password_form.new_password2 - ); - password_utils::verify_temporary_password(&password_form.temporary_password)?; - // if the previous line did not throw an error, then the secret_link is correct - password_utils::validate_new_passwords( - &password_form.new_password1, - &password_form.new_password2, - )?; - // if the previous line did not throw an error, then the new password is valid - password_utils::set_new_password(&password_form.new_password1)?; - Ok(()) -} - -/// Password reset request handler. This route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password. -#[get("/reset_password")] -pub fn reset_password(flash: Option) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Reset Password".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("settings/admin/reset_password", &context.into_json()) -} - -/// Password reset form request handler. This route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password. -#[post("/reset_password", data = "")] -pub fn reset_password_post(reset_password_form: Form) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Reset Password".to_string())); - - let (flash_name, flash_msg) = match save_reset_password_form(reset_password_form.into_inner()) { - Ok(_) => ( - "success".to_string(), - "New password has been saved. Return home to login".to_string(), - ), - Err(err) => ( - "error".to_string(), - format!("Failed to reset password: {}", err), - ), - }; - - context.insert("flash_name", &Some(flash_name)); - context.insert("flash_msg", &Some(flash_msg)); - - Template::render("settings/admin/reset_password", &context.into_json()) -} - -// HELPERS AND ROUTES FOR /send_password_reset - -/// Page for users who have forgotten their password. -/// This route is used by a user who is not logged in -/// to initiate the sending of a new password reset. -#[get("/forgot_password")] -pub fn forgot_password_page(flash: Option) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Send Password Reset".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/admin/forgot_password", &context.into_json()) -} - -/// Send password reset request handler. This route is used by a user who is not logged in -/// and is specifically for users who have forgotten their password. A successful request results -/// in a Scuttlebutt private message being sent to the account of the device admin. -#[post("/send_password_reset")] -pub fn send_password_reset_post() -> Template { - info!("++ send password reset post"); - let mut context = Context::new(); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Send Password Reset".to_string())); - - let (flash_name, flash_msg) = match password_utils::send_password_reset() { - Ok(_) => ( - "success".to_string(), - "A password reset link has been sent to the admin of this device".to_string(), - ), - Err(err) => ( - "error".to_string(), - format!("Failed to send password reset link: {}", err), - ), - }; - - context.insert("flash_name", &Some(flash_name)); - context.insert("flash_msg", &Some(flash_msg)); - - Template::render("settings/admin/forgot_password", &context.into_json()) -} - -// HELPERS AND ROUTES FOR /settings/change_password - -#[derive(Debug, FromForm)] -pub struct PasswordForm { - pub current_password: String, - pub new_password1: String, - pub new_password2: String, -} - -/// Password save form request handler. This function is for use by a user who is already logged in to change their password. -pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebError> { - info!( - "change password!: {} {} {}", - password_form.current_password, password_form.new_password1, password_form.new_password2 - ); - password_utils::verify_password(&password_form.current_password)?; - // if the previous line did not throw an error, then the old password is correct - password_utils::validate_new_passwords( - &password_form.new_password1, - &password_form.new_password2, - )?; - // if the previous line did not throw an error, then the new password is valid - password_utils::set_new_password(&password_form.new_password1)?; - Ok(()) -} - -/// Change password request handler. This is used by a user who is already logged in. -#[get("/change_password")] -pub fn change_password(flash: Option, _auth: Authenticated) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/settings/admin".to_string())); - context.insert("title", &Some("Change Password".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/admin/change_password", &context.into_json()) -} - -/// Change password form request handler. This route is used by a user who is already logged in. -#[post("/change_password", data = "")] -pub fn change_password_post(password_form: Form, _auth: Authenticated) -> Template { - let mut context = Context::new(); - context.insert("back", &Some("/settings/admin".to_string())); - context.insert("title", &Some("Change Password".to_string())); - - let (flash_name, flash_msg) = match save_password_form(password_form.into_inner()) { - Ok(_) => ( - "success".to_string(), - "New password has been saved".to_string(), - ), - Err(err) => ( - "error".to_string(), - format!("Failed to save new password: {}", err), - ), - }; - - context.insert("flash_name", &Some(flash_name)); - context.insert("flash_msg", &Some(flash_msg)); - - Template::render("settings/admin/change_password", &context.into_json()) -} diff --git a/peach-web/src/routes/catchers.rs b/peach-web/src/routes/catchers.rs deleted file mode 100644 index 0c3523e..0000000 --- a/peach-web/src/routes/catchers.rs +++ /dev/null @@ -1,60 +0,0 @@ -use log::debug; -use rocket::catch; -use rocket::response::Redirect; -use rocket_dyn_templates::Template; -use serde::Serialize; - -// HELPERS AND ROUTES FOR 404 ERROR - -#[derive(Debug, Serialize)] -pub struct ErrorContext { - pub back: Option, - pub flash_name: Option, - pub flash_msg: Option, - pub title: Option, -} - -impl ErrorContext { - pub fn build() -> ErrorContext { - ErrorContext { - back: None, - flash_name: None, - flash_msg: None, - title: None, - } - } -} - -#[catch(404)] -pub fn not_found() -> Template { - debug!("404 Page Not Found"); - let mut context = ErrorContext::build(); - context.back = Some("/".to_string()); - context.title = Some("404: Page Not Found".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some("No resource found for given URL".to_string()); - - Template::render("catchers/not_found", context) -} - -// HELPERS AND ROUTES FOR 500 ERROR - -#[catch(500)] -pub fn internal_error() -> Template { - debug!("500 Internal Server Error"); - let mut context = ErrorContext::build(); - context.back = Some("/".to_string()); - context.title = Some("500: Internal Server Error".to_string()); - context.flash_name = Some("error".to_string()); - context.flash_msg = Some("Internal server error".to_string()); - - Template::render("catchers/internal_error", context) -} - -// HELPERS AND ROUTES FOR 403 FORBIDDEN - -#[catch(403)] -pub fn forbidden() -> Redirect { - debug!("403 Forbidden"); - Redirect::to("/login") -} diff --git a/peach-web/src/routes/index.rs b/peach-web/src/routes/index.rs deleted file mode 100644 index 45eb21c..0000000 --- a/peach-web/src/routes/index.rs +++ /dev/null @@ -1,51 +0,0 @@ -use peach_lib::sbot::SbotStatus; -use rocket::{get, request::FlashMessage, State}; -use rocket_dyn_templates::{tera::Context, Template}; - -use crate::routes::authentication::Authenticated; -use crate::utils; -use crate::RocketConfig; - -// HELPERS AND ROUTES FOR / (HOME PAGE) - -#[get("/")] -pub fn home(_auth: Authenticated, config: &State) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - // retrieve go-sbot systemd process status - let sbot_status = SbotStatus::read().ok(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("sbot_status", &sbot_status); - context.insert("flash_name", &None::<()>); - context.insert("flash_msg", &None::<()>); - context.insert("title", &None::<()>); - - // 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()) -} - -// HELPERS AND ROUTES FOR /guide - -#[get("/guide")] -pub fn guide(flash: Option) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/".to_string())); - context.insert("title", &Some("Guide".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("guide", &context.into_json()) -} diff --git a/peach-web/src/routes/settings/admin.rs_old b/peach-web/src/routes/settings/admin.rs_old deleted file mode 100644 index c5d437a..0000000 --- a/peach-web/src/routes/settings/admin.rs_old +++ /dev/null @@ -1,124 +0,0 @@ -/* -use rocket::{ - form::{Form, FromForm}, - get, post, - request::FlashMessage, - response::{Flash, Redirect}, - uri, -}; -use rocket_dyn_templates::{tera::Context, Template}; - -use peach_lib::config_manager; - -use crate::error::PeachWebError; -use crate::routes::authentication::Authenticated; -use crate::utils; - -// HELPERS AND ROUTES FOR /settings/admin - -/// Administrator settings menu. -#[get("/")] -pub fn admin_menu(flash: Option, _auth: Authenticated) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/settings".to_string())); - context.insert("title", &Some("Administrator Settings".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - Template::render("settings/admin/menu", &context.into_json()) -} - -// HELPERS AND ROUTES FOR /settings/admin/configure - -/// View and delete currently configured admin. -#[get("/configure")] -pub fn configure_admin(flash: Option, _auth: Authenticated) -> Template { - // retrieve current ui theme - let theme = utils::get_theme(); - - let mut context = Context::new(); - context.insert("theme", &theme); - context.insert("back", &Some("/settings/admin".to_string())); - context.insert("title", &Some("Configure Admin".to_string())); - - // check to see if there is a flash message to display - if let Some(flash) = flash { - context.insert("flash_name", &Some(flash.kind().to_string())); - context.insert("flash_msg", &Some(flash.message().to_string())); - }; - - // load the peach configuration vector - match config_manager::load_peach_config() { - Ok(config) => { - // retrieve the vector of ssb admin ids - let ssb_admin_ids = config.ssb_admin_ids; - context.insert("ssb_admin_ids", &ssb_admin_ids); - } - // if load fails, overwrite the flash_name and flash_msg - Err(e) => { - context.insert("flash_name", &Some("error".to_string())); - context.insert( - "flash_msg", - &Some(format!("Failed to load Peach config: {}", e)), - ); - } - } - - Template::render("settings/admin/configure_admin", &context.into_json()) -} - -// HELPERS AND ROUTES FOR /settings/admin/add - -#[derive(Debug, FromForm)] -pub struct AddAdminForm { - pub ssb_id: String, -} - -pub fn save_add_admin_form(admin_form: AddAdminForm) -> Result<(), PeachWebError> { - let _result = config_manager::add_ssb_admin_id(&admin_form.ssb_id)?; - - // if the previous line didn't throw an error then it was a success - Ok(()) -} - -#[post("/add", data = "")] -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!("/settings/admin/configure"); - match result { - Ok(_) => Flash::success(Redirect::to(url), "Added SSB administrator"), - Err(e) => Flash::error(Redirect::to(url), format!("Failed to add new admin: {}", e)), - } -} - -// HELPERS AND ROUTES FOR /settings/admin/delete - -#[derive(Debug, FromForm)] -pub struct DeleteAdminForm { - pub ssb_id: String, -} - -#[post("/delete", data = "")] -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!("/settings/admin", configure_admin); - match result { - Ok(_) => Flash::success(Redirect::to(url), "Removed SSB administrator"), - Err(e) => Flash::error( - Redirect::to(url), - format!("Failed to remove admin id: {}", e), - ), - } -} -*/ diff --git a/peach-web/src/routes/status/scuttlebutt.rs_old b/peach-web/src/routes/status/scuttlebutt.rs_old deleted file mode 100644 index 34aa61d..0000000 --- a/peach-web/src/routes/status/scuttlebutt.rs_old +++ /dev/null @@ -1,37 +0,0 @@ -use rocket::{get, State}; -use rocket_dyn_templates::Template; - -use crate::routes::authentication::Authenticated; -use crate::{context::scuttlebutt::StatusContext, RocketConfig}; - -// HELPERS AND ROUTES FOR /status/scuttlebutt - -#[get("/scuttlebutt")] -pub async fn scuttlebutt_status(_auth: Authenticated, config: &State) -> Template { - let context = StatusContext::build().await; - - let back = if config.standalone_mode { - // return to home page - Some("/".to_string()) - } else { - // return to status menu - Some("/status".to_string()) - }; - - match context { - Ok(mut context) => { - // define back arrow url based on mode - context.back = back; - - Template::render("status/scuttlebutt", &context) - } - Err(_) => { - let mut context = StatusContext::default(); - - // define back arrow url based on mode - context.back = back; - - Template::render("status/scuttlebutt", &context) - } - } -} diff --git a/peach-web/src/utils/monitor.rs b/peach-web/src/utils/monitor.rs deleted file mode 100644 index fd896cf..0000000 --- a/peach-web/src/utils/monitor.rs +++ /dev/null @@ -1,198 +0,0 @@ -// Monitor data transmission totals, set thresholds and check alert flags - -use std::convert::TryInto; - -use nest::{Error, Store, Value}; -use rocket::form::FromForm; -use rocket::serde::{Deserialize, Serialize}; -use serde_json::json; - -/// Network traffic data total -#[derive(Debug, Serialize)] -pub struct Data { - pub total: u64, // total traffic in bytes -} - -impl Data { - /// Retrieve network traffic data values from the store - fn get(store: &Store) -> Data { - // retrieve previous network traffic statistics - let data_stored = match store.get(&["net", "traffic", "total"]) { - Ok(total) => total, - // return 0 if no value exists - Err(_) => Value::Uint(u64::MIN), - }; - - let mut data = Vec::new(); - // retrieve u64 from Value type - if let Value::Uint(total) = data_stored { - data.push(total); - }; - - Data { total: data[0] } - } -} - -/// Network traffic notification thresholds and flags (user-defined) -#[derive(Debug, Deserialize, Serialize, FromForm)] -pub struct Threshold { - warn: u64, // traffic warning threshold - cut: u64, // traffic cutoff threshold - warn_flag: bool, // traffic warning notification flag - cut_flag: bool, // traffic cutoff notification flag -} - -impl Threshold { - /// Retrieve notification thresholds and flags from the store - fn get(store: &Store) -> Threshold { - let mut threshold = Vec::new(); - - let warn_val = store - .get(&["net", "notify", "warn"]) - .unwrap_or(Value::Uint(0)); - if let Value::Uint(val) = warn_val { - threshold.push(val); - }; - - let cut_val = store - .get(&["net", "notify", "cut"]) - .unwrap_or(Value::Uint(0)); - if let Value::Uint(val) = cut_val { - threshold.push(val); - }; - - let mut flag = Vec::new(); - - let warn_flag = store - .get(&["net", "notify", "warn_flag"]) - .unwrap_or(Value::Bool(false)); - if let Value::Bool(state) = warn_flag { - flag.push(state); - } - - let cut_flag = store - .get(&["net", "notify", "cut_flag"]) - .unwrap_or(Value::Bool(false)); - if let Value::Bool(state) = cut_flag { - flag.push(state); - } - - Threshold { - warn: threshold[0], - cut: threshold[1], - warn_flag: flag[0], - cut_flag: flag[1], - } - } - - /// Store notification flags from user data - fn set(self, store: &Store) { - store - .set(&["net", "notify", "warn"], &Value::Uint(self.warn)) - .unwrap(); - store - .set(&["net", "notify", "cut"], &Value::Uint(self.cut)) - .unwrap(); - store - .set( - &["net", "notify", "warn_flag"], - &Value::Bool(self.warn_flag), - ) - .unwrap(); - store - .set(&["net", "notify", "cut_flag"], &Value::Bool(self.cut_flag)) - .unwrap(); - } -} - -/// Warning and cutoff network traffic alert flags (programatically-defined) -#[derive(Debug, Serialize)] -pub struct Alert { - warn: bool, - cut: bool, -} - -impl Alert { - /// Retrieve latest alert flags from the store - fn get(store: &Store) -> Alert { - let mut alert = Vec::new(); - - let warn_flag = store - .get(&["net", "alert", "warn"]) - .unwrap_or(Value::Bool(false)); - if let Value::Bool(flag) = warn_flag { - alert.push(flag); - } - - let cut_flag = store - .get(&["net", "alert", "cut"]) - .unwrap_or(Value::Bool(false)); - if let Value::Bool(flag) = cut_flag { - alert.push(flag); - } - - Alert { - warn: alert[0], - cut: alert[1], - } - } -} - -fn create_store() -> std::result::Result { - // define the path - let path = xdg::BaseDirectories::new() - .unwrap() - .create_data_directory("peachcloud") - .unwrap(); - - // define the schema - let schema = json!({ - "net": { - "traffic": "json", - "alert": "json", - "notify": "json", - } - }) - .try_into()?; - - // create the data store - let store = Store::new(path, schema); - - Ok(store) -} - -pub fn get_alerts() -> std::result::Result { - let store = create_store()?; - let alerts = Alert::get(&store); - - Ok(alerts) -} - -pub fn get_data() -> std::result::Result { - let store = create_store()?; - let data = Data::get(&store); - - Ok(data) -} - -pub fn get_thresholds() -> std::result::Result { - let store = create_store()?; - let thresholds = Threshold::get(&store); - - Ok(thresholds) -} - -// set stored traffic total to 0 -pub fn reset_data() -> std::result::Result<(), Error> { - let store = create_store()?; - store.set(&["net", "traffic", "total"], &Value::Uint(0))?; - - Ok(()) -} - -pub fn update_store(threshold: Threshold) -> std::result::Result<(), Error> { - let store = create_store()?; - Threshold::set(threshold, &store); - - Ok(()) -}