Started perms middleware UNFINISHED
This commit is contained in:
@@ -1,4 +1,70 @@
|
||||
use axum::http::Method;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::domain::user_prems::UserActions;
|
||||
|
||||
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
||||
pub struct RouteKey {
|
||||
pub method: Method,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppCfg {
|
||||
pub db_path: String,
|
||||
pub route_perms: HashMap<RouteKey, Vec<UserActions>>,
|
||||
}
|
||||
|
||||
impl AppCfg {
|
||||
pub fn new(db_path: String) -> Self {
|
||||
Self {
|
||||
db_path,
|
||||
route_perms: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_route_perms(
|
||||
&mut self,
|
||||
method: Method,
|
||||
path: impl Into<String>,
|
||||
perms: Vec<UserActions>,
|
||||
) {
|
||||
let key = RouteKey {
|
||||
method,
|
||||
path: path.into(),
|
||||
};
|
||||
|
||||
self.route_perms.insert(key, perms);
|
||||
}
|
||||
|
||||
pub fn get_route_perms(&self, method: &Method, path: &str) -> Option<&Vec<UserActions>> {
|
||||
let key = RouteKey {
|
||||
method: method.clone(),
|
||||
path: path.to_string(),
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::prelude::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum UserActions {
|
||||
Root,
|
||||
ManageUsers,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use anyhow::{Ok, Result};
|
||||
use axum::http::Method;
|
||||
use rustymine_daemon::{
|
||||
config::AppCfg,
|
||||
domain::user_prems::UserActions,
|
||||
router,
|
||||
state::{AppState, check_root},
|
||||
};
|
||||
@@ -56,11 +58,15 @@ async fn main() -> Result<()> {
|
||||
);
|
||||
|
||||
let db_path: String = "postgres://rustymine:minecraft@localhost:5432/rustymine_dev".to_string();
|
||||
let config = AppCfg {
|
||||
let mut config = AppCfg {
|
||||
db_path: db_path.clone(),
|
||||
route_perms: HashMap::new(),
|
||||
};
|
||||
|
||||
let state = Arc::new(AppState::new(&config).await);
|
||||
config.insert_route_perms(Method::GET, "/api/login", vec![UserActions::Login]);
|
||||
config.insert_route_perms(Method::GET, "/api/users", vec![UserActions::Login]);
|
||||
|
||||
let state = Arc::new(AppState::new(config).await);
|
||||
check_root(state.clone()).await;
|
||||
|
||||
let app_result = router::init_router(state.clone()).await;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::{core::user_routines, prelude::*};
|
||||
use crate::{core::user_routines, domain::user::InternalUser, prelude::*};
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
extract::{Request, State},
|
||||
Extension,
|
||||
extract::{MatchedPath, Request, State},
|
||||
http::{self, Method, StatusCode, header::AUTHORIZATION},
|
||||
middleware::{Next, from_fn_with_state},
|
||||
response::Response,
|
||||
@@ -69,6 +70,23 @@ pub async fn auth(
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
|
||||
pub async fn perms(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Extension(user): Extension<InternalUser>,
|
||||
mut req: Request,
|
||||
next: Next,
|
||||
) -> Result<Response, StatusCode> {
|
||||
let method: Method = req.method().clone();
|
||||
|
||||
let path = req
|
||||
.extensions()
|
||||
.get::<MatchedPath>()
|
||||
.map(|p| p.as_str().to_string())
|
||||
.ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
|
||||
pub fn cors() -> CorsLayer {
|
||||
debug!("build cors layer");
|
||||
CorsLayer::new()
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::{process::exit, sync::Arc};
|
||||
use std::{collections::HashMap, process::exit, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
core,
|
||||
domain::user::{InternalNewUser, NewUser},
|
||||
domain::{
|
||||
user::{InternalNewUser, NewUser},
|
||||
user_prems::UserActions,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
@@ -12,10 +15,11 @@ use crate::{config::AppCfg, infra::db};
|
||||
|
||||
pub struct AppState {
|
||||
pub db_pool: PgPool,
|
||||
pub config: AppCfg,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub async fn new(config: &AppCfg) -> Self {
|
||||
pub async fn new(config: AppCfg) -> Self {
|
||||
debug!("init app state");
|
||||
debug!("establish database connection");
|
||||
let db_pool = db::connect(&config.db_path)
|
||||
@@ -36,7 +40,10 @@ impl AppState {
|
||||
.unwrap();
|
||||
info!("database ready after connect and migrate");
|
||||
|
||||
Self { db_pool: db_pool }
|
||||
Self {
|
||||
db_pool: db_pool,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user