From 8551a004a87966b91c3c29864e08b197971e7819 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Tue, 15 Jul 2025 16:13:52 +0200 Subject: [PATCH] sessions --- src/backend/auth.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/backend/mod.rs | 7 +++++-- src/dashboard.rs | 34 ++++------------------------------ src/utils.rs | 34 ++++++++++++++++++++++++++++++---- 4 files changed, 82 insertions(+), 38 deletions(-) diff --git a/src/backend/auth.rs b/src/backend/auth.rs index 770f9d7..8762549 100644 --- a/src/backend/auth.rs +++ b/src/backend/auth.rs @@ -6,9 +6,14 @@ pub struct User { password: String, } +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct Session { + uuid: String, +} + #[server] pub async fn login(username: String, password: String) -> Result { - let users = crate::backend::get_mongo::("users").await?; + let users = crate::backend::get_mongo::("users").await?; match users .find_one(mongodb::bson::doc! { @@ -17,7 +22,43 @@ pub async fn login(username: String, password: String) -> Result Ok(String::new()), + Some(v) => { + let sessions = crate::backend::get_mongo::("sessions").await?; + if let mongodb::bson::Bson::ObjectId(id) = sessions + .insert_one(Session { + uuid: v.get_object_id("_id")?.to_hex(), + }) + .await? + .inserted_id + { + Ok(id.to_hex()) + } else { + Err(ServerFnError::new(format!("Unable to extract session id"))) + } + } None => Err(ServerFnError::new(format!("Invalid credentials"))), } } + +#[cfg(feature = "server")] +pub async fn validate_session(id: String) -> bool { + use mongodb::bson::oid::ObjectId; + + if let Ok(sessions) = crate::backend::get_mongo::("sessions").await { + if let Some(obj_id) = ObjectId::parse_str(id).ok() { + match sessions + .find_one(mongodb::bson::doc! { + "_id": obj_id, + }) + .await + { + Ok(Some(_)) => true, + _ => false, + } + } else { + false + } + } else { + false + } +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 79f62c6..bf99891 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -48,7 +48,11 @@ fn build_or_filter(input: &str, fields: &[&str]) -> mongodb::bson::Document { } #[server] -pub async fn get_servers(search: String) -> Result, ServerFnError> { +pub async fn get_servers(session: String, search: String) -> Result, ServerFnError> { + if !auth::validate_session(session).await { + return Err(ServerFnError::new(format!("Invalid session"))); + } + let servers = get_mongo::("servers").await?; let filter = if search.trim().is_empty() { @@ -57,7 +61,6 @@ pub async fn get_servers(search: String) -> Result, ServerFnError> { build_or_filter(&search, &["name", "ip"]) }; - let mut cursor = servers.find(filter).await?; let mut svo = Vec::new(); diff --git a/src/dashboard.rs b/src/dashboard.rs index e46a737..1423380 100644 --- a/src/dashboard.rs +++ b/src/dashboard.rs @@ -1,26 +1,14 @@ use dioxus::prelude::*; -use crate::{ - backend, - components::{server::ServerComponent, sidebar::SideBar, LineChart, ProgressBar}, -}; +use crate::components::{server::ServerComponent, sidebar::SideBar, LineChart, ProgressBar}; use lucide_dioxus; const DASHBOARD_CSS: Asset = asset!("/assets/styles/dashboard.css"); #[component] pub fn Dashboard() -> Element { - let mut servers = use_signal(|| Vec::new()); - let server_search = use_signal(|| String::new()); - let session_id = crate::utils::use_cookie::("session_id", || "Guest".to_string()); - - use_effect(move || { - spawn(async move { - if let Ok(v) = backend::get_servers(String::new()).await { - servers.set(v); - } - }); - }); + let session = crate::utils::use_session(); + let (servers, server_query) = session.use_servers(); rsx! { document::Link { rel: "stylesheet", href: DASHBOARD_CSS } @@ -106,21 +94,7 @@ pub fn Dashboard() -> Element { div { class: "search-input", lucide_dioxus::Search { size: 16, color: "currentColor" } input { - onchange: {let mut server_search = server_search.clone(); move |e: Event| {server_search.set(e.value())}}, - onkeypress: { - let server_search = server_search.clone(); - let mut servers = servers.clone(); - move |e: Event| { - let query = (*server_search.read()).clone(); - async move { - if e.key() == Key::Enter { - if let Ok(v) = backend::get_servers(query).await { - servers.set(v); - } - } - } - } - }, + onchange: {let mut server_query = server_query.clone(); move |e: Event| {server_query.set(e.value())}}, placeholder: "Search servers by name, location, or IP..." } } diff --git a/src/utils.rs b/src/utils.rs index e9b99c0..b4751f7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,6 +3,8 @@ use std::str::FromStr; use wasm_bindgen::JsCast; use web_sys::{window, HtmlDocument}; +use crate::{backend, components::server::Server}; + pub fn set_cookie(name: &str, value: &str) { let Some(document) = window().and_then(|w| w.document()) else { return; @@ -38,10 +40,7 @@ pub fn get_cookie(name: &str) -> Option { None } -pub fn use_cookie( - name: &str, - default: fn() -> T, -) -> Signal { +pub fn use_cookie(name: &str, default: fn() -> T) -> Signal { let name = name.to_string(); let signal = use_signal(default); @@ -66,3 +65,30 @@ pub fn redirect(target: &str) { .set_href(target) .unwrap(); } + +pub struct Session(Signal); + +pub fn use_session() -> Session { + Session(use_cookie("session_id", || String::new())) +} + +impl Session { + pub fn use_servers(&self) -> (Signal>, Signal) { + let query = use_signal(|| String::new()); + let servers = use_signal(|| Vec::new()); + let id = self.0.clone(); + + use_effect(move || { + let query_value = query.read().clone(); + let mut servers = servers.clone(); + + spawn(async move { + if let Ok(v) = backend::get_servers(id.read().clone(), query_value).await { + servers.set(v); + } + }); + }); + + (servers, query) + } +}