From 2b31e36060a6159d9b14fb30c7df4ca1369e44ed Mon Sep 17 00:00:00 2001 From: Hector van der Aa Date: Fri, 5 Dec 2025 22:17:24 +0100 Subject: [PATCH] Pre pull fix --- src/backend/Cargo.toml | 2 +- src/backend/migrations/0003_create_perms.sql | 3 +- src/backend/src/config.rs | 44 +++++++++---------- src/backend/src/domain/user_prems.rs | 14 +++--- src/backend/src/router/middleware.rs | 46 +++++++++----------- src/backend/src/router/mod.rs | 7 +++ 6 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/backend/Cargo.toml b/src/backend/Cargo.toml index c2a8b15..4d03454 100644 --- a/src/backend/Cargo.toml +++ b/src/backend/Cargo.toml @@ -22,7 +22,7 @@ tower = { version = "0.5.2", features = ["tokio", "tracing"] } tower-http = { version = "0.6.7", features = ["cors"] } tracing = { version = "0.1.43", features = ["max_level_debug"] } tracing-subscriber = "0.3.22" -uuid = { version = "1.18.1", features = ["v4", "serde"] } +uuid = { version = "1.19.0", features = ["v4", "serde"] } validator = { version = "0.20.0", features = ["derive"] } mineguard = {path = "../../../MineGuard/"} diff --git a/src/backend/migrations/0003_create_perms.sql b/src/backend/migrations/0003_create_perms.sql index d5139d0..2f896c2 100644 --- a/src/backend/migrations/0003_create_perms.sql +++ b/src/backend/migrations/0003_create_perms.sql @@ -1,6 +1,5 @@ CREATE TABLE user_permissions( uuid UUID PRIMARY KEY, root BOOL NOT NULL, - manage_users BOOL NOT NULL, - login BOOL NOT NULL + permissions JSON NOT NULL, ); diff --git a/src/backend/src/config.rs b/src/backend/src/config.rs index 75e378c..f48a53f 100644 --- a/src/backend/src/config.rs +++ b/src/backend/src/config.rs @@ -1,7 +1,10 @@ use axum::http::Method; use std::collections::HashMap; -use crate::domain::user_prems::UserActions; +use crate::domain::{ + user::User, + user_prems::{UserActions, UserPermissions}, +}; #[derive(Debug, Hash, Clone, PartialEq, Eq)] pub struct RouteKey { @@ -12,7 +15,7 @@ pub struct RouteKey { #[derive(Debug)] pub struct AppCfg { pub db_path: String, - pub route_perms: HashMap>, + pub route_perms: HashMap, } impl AppCfg { @@ -27,7 +30,7 @@ impl AppCfg { &mut self, method: Method, path: impl Into, - perms: Vec, + perms: UserPermissions, ) { let key = RouteKey { method, @@ -37,7 +40,7 @@ impl AppCfg { self.route_perms.insert(key, perms); } - pub fn get_route_perms(&self, method: &Method, path: &str) -> Option<&Vec> { + pub fn get_route_perms(&self, method: &Method, path: &str) -> Option { let key = RouteKey { method: method.clone(), path: path.to_string(), @@ -46,25 +49,22 @@ impl AppCfg { self.route_perms.get(&key) } - pub fn route_allows(&self, method: &Method, path: &str, user_perms: &[UserActions]) -> bool { - if user_perms.contains(&UserActions::Root) { - return true; + pub fn route_allows(&self, method: &Method, path: &str, user_perms: UserPermissions) -> bool { + let req_perms = self + .get_route_perms(method, path) + .ok_or_else(return false)?; + + if req_perms.root == true { + if user_perms.root == true { + return true; + } else { + return false; + } } - let key = RouteKey { - method: method.clone(), - path: path.to_string(), - }; - - let required = match self.route_perms.get(&key) { - Some(perms) => perms, - None => return true, // no perms required → allow - }; - - if required.contains(&UserActions::Root) { - return false; - } - - required.iter().all(|p| user_perms.contains(p)) + req_perms + .permissions + .iter() + .all(|action| user_perms.permissions.contains(action)) } } diff --git a/src/backend/src/domain/user_prems.rs b/src/backend/src/domain/user_prems.rs index d73f096..b3b2092 100644 --- a/src/backend/src/domain/user_prems.rs +++ b/src/backend/src/domain/user_prems.rs @@ -1,10 +1,11 @@ +use std::collections::HashSet; + use serde::{Deserialize, Serialize}; use sqlx::prelude::FromRow; use uuid::Uuid; -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum UserActions { - Root, ManageUsers, Login, } @@ -12,16 +13,14 @@ pub enum UserActions { #[derive(Debug, Clone, Deserialize, Serialize, FromRow)] pub struct UserPermissions { pub root: bool, - pub manage_users: bool, - pub login: bool, + pub permissions: HashSet, } impl Default for UserPermissions { fn default() -> Self { Self { root: false, - manage_users: false, - login: false, + permissions: Vec::new(), } } } @@ -30,8 +29,7 @@ impl UserPermissions { pub fn root() -> Self { Self { root: true, - manage_users: true, - login: true, + permissions: Vec::new(), } } } diff --git a/src/backend/src/router/middleware.rs b/src/backend/src/router/middleware.rs index 475fe60..bc407d5 100644 --- a/src/backend/src/router/middleware.rs +++ b/src/backend/src/router/middleware.rs @@ -24,33 +24,28 @@ pub async fn auth( debug!(method = ?request_method, path = request_path, "authenticate request started"); - // 1) Extract Authorization header let auth_header = req .headers() .get(http::header::AUTHORIZATION) - .ok_or(StatusCode::FORBIDDEN)?; // no header at all + .ok_or(StatusCode::FORBIDDEN)?; let auth_header = auth_header.to_str().map_err(|e| { error!(error = %e, method = ?request_method, path = request_path, "authorization header parse failed"); StatusCode::FORBIDDEN })?; - // 2) Expect "Bearer " let mut parts = auth_header.split_whitespace(); let (scheme, token) = match (parts.next(), parts.next()) { (Some(scheme), Some(token)) if scheme.eq_ignore_ascii_case("bearer") => (scheme, token), _ => { - // either wrong scheme or missing token warn!(method = ?request_method, path = request_path, "authorization header missing bearer token"); return Err(StatusCode::UNAUTHORIZED); } }; - // 3) Verify JWT - let token_data = verify_jwt(token.to_string())?; // verify_jwt(&str) -> Result, StatusCode> + let token_data = verify_jwt(token.to_string())?; let username = &token_data.claims.username; - // 4) Load current user from DB let current_user = match user_routines::get_by_username(state, username) .await .map_err(|e| { @@ -63,27 +58,8 @@ pub async fn auth( return Err(StatusCode::INTERNAL_SERVER_ERROR); } }; - // 5) Attach user to request extensions so handlers can grab it req.extensions_mut().insert(current_user); - // 6) Continue down the stack - Ok(next.run(req).await) -} - -pub async fn perms( - State(state): State>, - Extension(user): Extension, - mut req: Request, - next: Next, -) -> Result { - let method: Method = req.method().clone(); - - let path = req - .extensions() - .get::() - .map(|p| p.as_str().to_string()) - .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; - Ok(next.run(req).await) } @@ -94,3 +70,21 @@ pub fn cors() -> CorsLayer { .allow_methods([Method::GET, Method::POST]) .allow_headers([AUTHORIZATION]) } + +pub async fn permissions( + State(state): State>, + Extension(user): Extension, + mut req: Request, + next: Next, +) -> Result { + warn!("Calling into permissions with user {}", user); + let method: Method = req.method().clone(); + + let path = req + .extensions() + .get::() + .map(|p| p.as_str().to_string()) + .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(next.run(req).await) +} diff --git a/src/backend/src/router/mod.rs b/src/backend/src/router/mod.rs index 4cda22b..8ec6040 100644 --- a/src/backend/src/router/mod.rs +++ b/src/backend/src/router/mod.rs @@ -24,6 +24,13 @@ macro_rules! middleware { axum::middleware::from_fn_with_state($state, crate::router::middleware::auth), ) }; + (cors_auth_perms: $state:expr) => { + ( + crate::router::middleware::cors(), + axum::middleware::from_fn_with_state($state, crate::router::middleware::auth), + axum::middleware::from_fn_with_state($state, crate::router::middleware::perms), + ) + }; } pub async fn init_router(app_state: Arc) -> Router {