From ba592de54cd3dce52eb2096dabbe748107f5db2b Mon Sep 17 00:00:00 2001 From: gennyble Date: Fri, 25 Sep 2026 03:56:11 -0500 Subject: splorm auth --- splorm/src/handler/api/auth.rs | 87 ++++++++++++++++++++++++++++++++++++++++++ splorm/src/handler/api/mod.rs | 49 ++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 splorm/src/handler/api/auth.rs create mode 100644 splorm/src/handler/api/mod.rs (limited to 'splorm/src/handler/api') diff --git a/splorm/src/handler/api/auth.rs b/splorm/src/handler/api/auth.rs new file mode 100644 index 0000000..ff1e990 --- /dev/null +++ b/splorm/src/handler/api/auth.rs @@ -0,0 +1,87 @@ +use axum::{body::Body, extract::State, response::Response}; +use gny::web::cookie::{self, SetCookie}; +use sessionhash::RequestContext; + +use crate::{Query, RuntimeError, state::SplormState}; + +/// POST /auth/register +pub async fn register( + State(state): State, + ctx: RequestContext, + body: String, +) -> Result { + tracing::trace!("{ctx} GET /api/register"); + + macro_rules! get { + ($query:ident $field:literal) => { + $query + .get_first_value($field) + .ok_or(RuntimeError::incomplete_form($field)) + }; + } + + let query: Query = body.parse()?; + let name = get!(query "name")?; + let plaintext_password = get!(query "password")?.to_owned(); + + let result = knowing::user_register(state.database(), name, plaintext_password).await; + let _user = match result { + Ok(user) => user, + Err(knowing::Error::DatabaseError(dbe)) => return Err(dbe.into()), + _ => unreachable!(), + }; + + tracing::info!("registered user {name}"); + + Response::builder() + .status(302) + .header("Location", "/") + .body(Body::from(format!("registered user {name}"))) + .map_err(|_| RuntimeError::Unknown) +} + +/// POST /auth/login +pub async fn login( + State(state): State, + ctx: RequestContext, + body: String, +) -> Result { + tracing::trace!("{ctx} GET /api/login"); + + macro_rules! get { + ($query:ident $field:literal) => { + $query + .get_first_value($field) + .ok_or(RuntimeError::incomplete_form($field)) + }; + } + + let query: Query = body.parse()?; + let name = get!(query "name")?; + let plaintext_password = get!(query "password")?.to_owned(); + + let result = knowing::user_login(state.database(), name, plaintext_password).await; + let session = match result { + Ok(user) => user, + Err(knowing::Error::DatabaseError(dbe)) => return Err(dbe.into()), + Err(knowing::Error::AuthenticationFailed) => { + return Err(RuntimeError::authentication_failed(name.to_owned())); + } + _ => unreachable!(), + }; + + let session_cookie = SetCookie::new("sid", session.sessionid().as_str()) + .max_age(Some(cookie::WEEK)) + .secure(true) + .httponly(true) + .path(Some("/")); + + tracing::info!("user {name} logged in"); + + Response::builder() + .status(302) + .header("Location", "/") + .header("Set-Cookie", session_cookie.as_string()) + .body(Body::from(format!("registered user {name}"))) + .map_err(|_| RuntimeError::Unknown) +} diff --git a/splorm/src/handler/api/mod.rs b/splorm/src/handler/api/mod.rs new file mode 100644 index 0000000..a7bfd4b --- /dev/null +++ b/splorm/src/handler/api/mod.rs @@ -0,0 +1,49 @@ +mod auth; + +use axum::{ + Router, + body::Body, + extract::{Path, State}, + response::Response, + routing::{get, post}, +}; +use sessionhash::RequestContext; + +use crate::{RuntimeError, fs, state::SplormState}; + +/// Routes nested under /api +pub fn routes() -> Router { + Router::new() + .route("/auth/register", post(auth::register)) + .route("/auth/login", post(auth::login)) + .route("/stats/now/{name}", get(stats)) +} + +async fn stats( + Path(name): Path, + State(state): State, + ctx: RequestContext, +) -> Result { + tracing::trace!("{ctx} GET /api/stats/{name}"); + + let graphs = { + let mut connector = state.gatherer_thread().await; + connector.regular_graphs().await + }; + + let file_path = match name.as_str() { + "current_hostmeminfo.gif" => graphs.meminfo, + "current_hostnetinfo.gif" => graphs.meminfo, + "current_hostcpuinfo.gif" => graphs.cpuinfo, + _ => return Err(RuntimeError::generic_404()), + }; + + tracing::trace!("graph {name} system_path={file_path}"); + let file = fs::unsafe_read_file(file_path).await?; + + Response::builder() + .header("content-type", "image/gif") + .status(200) + .body(Body::from(file)) + .map_err(|_| RuntimeError::Unknown) +} -- cgit 1.4.1-3-g733a5