jean-marie/backend/src/middlewares.rs

118 lines
4.4 KiB
Rust

use super::{AppError, UserData};
use axum::{
body::Body,
extract::State,
http::Request,
middleware::Next,
response::{IntoResponse, Redirect},
};
use axum_extra::TypedHeader;
use chrono::Utc;
use headers::Cookie;
use sqlx::SqlitePool;
pub async fn inject_user_data(
State(db_pool): State<SqlitePool>,
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<(i64, i64, String), _> = sqlx::query_as(
r#"SELECT user_id,expires_at,session_token_p2 FROM user_sessions WHERE session_token_p1=?"#,
)
.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().timestamp() {
let row = sqlx::query_as!(UserData, "SELECT * FROM users WHERE id = ?", id)
.fetch_one(&db_pool)
.await?;
request.extensions_mut().insert(Some(UserData {
id: row.id,
email: row.email,
name: row.name,
family_name: row.family_name,
given_name: row.given_name,
}));
}
}
}
}
}
}
}
Ok(next.run(request).await)
}
pub async fn check_auth(State(app_state): State<SqlitePool>, request: Request<Body>, next: Next) -> Result<impl IntoResponse, AppError> {
if request
.extensions()
.get::<Option<UserData>>()
.ok_or("check_auth: extensions have no UserData")?
.is_some()
{
let path = &*request.uri().to_string();
println!("{}", path);
println!("{}",&*request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email);
let query: Result<(i64,), _> = match path {
"/profile" =>
sqlx::query_as(r#"select u.id from users u where email =?"#)
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
.fetch_one(&app_state)
.await,
_ => 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 = ? and email =?"#)
.bind(&*request.uri().to_string())
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
.fetch_one(&app_state)
.await,
};
// user is logged in
// check if user has the proper role
// if not, display banner and return to home page
let user_id = if let Ok(query) = query {
query.0
} else {
// user does not have the proper role
0
};
println!("{}", user_id);
if user_id == 0 {
// user does not have the proper role
// display banner and return to home page
return Ok(Redirect::to("/").into_response());
}
Ok(next.run(request).await)
} else {
// user is not logged in
// redirect to login page with return_url
let login_url = "/login?return_url=".to_owned() + &*request.uri().to_string();
Ok(Redirect::to(login_url.as_str()).into_response())
}
}