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)]
|
#[derive(Debug)]
|
||||||
pub struct AppCfg {
|
pub struct AppCfg {
|
||||||
pub db_path: String,
|
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 sqlx::prelude::FromRow;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum UserActions {
|
pub enum UserActions {
|
||||||
Root,
|
Root,
|
||||||
ManageUsers,
|
ManageUsers,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{Ok, Result};
|
use anyhow::{Ok, Result};
|
||||||
|
use axum::http::Method;
|
||||||
use rustymine_daemon::{
|
use rustymine_daemon::{
|
||||||
config::AppCfg,
|
config::AppCfg,
|
||||||
|
domain::user_prems::UserActions,
|
||||||
router,
|
router,
|
||||||
state::{AppState, check_root},
|
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 db_path: String = "postgres://rustymine:minecraft@localhost:5432/rustymine_dev".to_string();
|
||||||
let config = AppCfg {
|
let mut config = AppCfg {
|
||||||
db_path: db_path.clone(),
|
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;
|
check_root(state.clone()).await;
|
||||||
|
|
||||||
let app_result = router::init_router(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 std::sync::Arc;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Request, State},
|
Extension,
|
||||||
|
extract::{MatchedPath, Request, State},
|
||||||
http::{self, Method, StatusCode, header::AUTHORIZATION},
|
http::{self, Method, StatusCode, header::AUTHORIZATION},
|
||||||
middleware::{Next, from_fn_with_state},
|
middleware::{Next, from_fn_with_state},
|
||||||
response::Response,
|
response::Response,
|
||||||
@@ -69,6 +70,23 @@ pub async fn auth(
|
|||||||
Ok(next.run(req).await)
|
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 {
|
pub fn cors() -> CorsLayer {
|
||||||
debug!("build cors layer");
|
debug!("build cors layer");
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use std::{process::exit, sync::Arc};
|
use std::{collections::HashMap, process::exit, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core,
|
core,
|
||||||
domain::user::{InternalNewUser, NewUser},
|
domain::{
|
||||||
|
user::{InternalNewUser, NewUser},
|
||||||
|
user_prems::UserActions,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,10 +15,11 @@ use crate::{config::AppCfg, infra::db};
|
|||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub db_pool: PgPool,
|
pub db_pool: PgPool,
|
||||||
|
pub config: AppCfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub async fn new(config: &AppCfg) -> Self {
|
pub async fn new(config: AppCfg) -> Self {
|
||||||
debug!("init app state");
|
debug!("init app state");
|
||||||
debug!("establish database connection");
|
debug!("establish database connection");
|
||||||
let db_pool = db::connect(&config.db_path)
|
let db_pool = db::connect(&config.db_path)
|
||||||
@@ -36,7 +40,10 @@ impl AppState {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
info!("database ready after connect and migrate");
|
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