jean-marie/backend/src/middlewares.rs

113 lines
4.5 KiB
Rust

use std::path::Path;
use super::{AppError, UserData};
use axum::{body::Body, extract::State, http::Request, middleware::Next, response::IntoResponse};
use axum_extra::TypedHeader;
use chrono::Utc;
use headers::Cookie;
use sqlx::PgPool;
pub async fn inject_user_data(
State(db_pool): State<PgPool>,
cookie: Option<TypedHeader<Cookie>>,
mut request: Request<Body>,
next: Next,
) -> Result<impl IntoResponse, AppError> {
if let Some(cookie) = cookie {
if let Some(session_token) = cookie.get("session_token") {
let session_token: Vec<&str> = session_token.split('_').collect();
let query: Result<(uuid::Uuid, chrono::NaiveDateTime, String), _> = sqlx::query_as(
r#"SELECT user_id,expires_at,session_token_p2 FROM user_sessions WHERE session_token_p1=$1"#,
)
.bind(session_token[0])
.fetch_one(&db_pool)
.await;
if let Ok(query) = query {
if let Ok(session_token_p2_db) = query.2.as_bytes().try_into() {
if let Ok(session_token_p2_cookie) = session_token
.get(1)
.copied()
.unwrap_or_default()
.as_bytes()
.try_into()
{
if constant_time_eq::constant_time_eq_n::<36>(
session_token_p2_cookie,
session_token_p2_db,
) {
let id = query.0;
let expires_at = query.1;
if expires_at > Utc::now().naive_local() {
let row: UserData = sqlx::query_as(
r#"SELECT id, created_at, created_by, updated_at, updated_by, email, name, family_name, given_name FROM users WHERE id = $1"#,
)
.bind(id)
.fetch_one(&db_pool)
.await
.unwrap();
request.extensions_mut().insert(Some(UserData {
id: row.id,
created_at: row.created_at,
created_by: row.created_by,
updated_at: row.updated_at,
updated_by: row.updated_by,
email: row.email,
name: row.name,
family_name: row.family_name,
given_name: row.given_name,
}));
}
}
}
}
}
}
}
Ok(next.run(request).await)
}
pub async fn is_authorized(path: &str, user_data: Option<UserData>, db_pool: PgPool) -> bool {
if let Some(user_data) = user_data {
let query: Result<(uuid::Uuid,), _> = match path {
"/profile" => {
return true;
}
_ => {
// loop through path to find a permission
let mut remaining_path = Path::new(path);
loop {
let query: Result<(String,), _> =
sqlx::query_as(r#"select r.item from role_permissions r where item = $1"#)
.bind(remaining_path.to_str().unwrap())
.fetch_one(&db_pool)
.await;
if let Ok(query) = query {
if query.0 != "" {
break;
}
}
if remaining_path.parent().is_none() {
break;
}
remaining_path = remaining_path.parent().unwrap();
}
sqlx::query_as(r#"select u.id from role_permissions r join user_roles ur on ur.role_id = r.role_id join users u on u.id = ur.user_id where item = $1 and email = $2"#)
.bind(remaining_path.to_str().unwrap())
.bind(user_data.email.as_str())
.fetch_one(&db_pool)
.await
}
};
if let Ok(query) = query {
if query.0 == user_data.id {
return true;
}
}
}
return false;
}