use std::path::Path; 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, cookie: Option>, mut request: Request, next: Next, ) -> Result { println!("Injecting user data"); if let Some(cookie) = cookie { println!("{:#?}", cookie.get("session_token")); if let Some(session_token) = cookie.get("session_token") { println!("Found session token: {}", 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; println!("Found user: {}", id); 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, })); } else { println!("Session expired"); } } } } } } } Ok(next.run(request).await) } pub async fn check_auth( State(app_state): State, request: Request, next: Next, ) -> Result { println!("check_auth"); println!("{:#?}", request); if request .extensions() .get::>() .ok_or("check_auth: extensions have no UserData")? .is_some() { let path = &*request.uri().to_string(); println!("{}", path); println!( "{}", &*request .extensions() .get::>() .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::>() .unwrap() .as_ref() .unwrap() .email .as_str(), ) .fetch_one(&app_state) .await } _ => { // 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 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(remaining_path.to_str().unwrap()) .bind(request.extensions().get::>().unwrap().as_ref().unwrap().email.as_str()) .fetch_one(&app_state) .await; if let Ok(query) = query { if query.0 != "" { break; } } if remaining_path.parent().is_none() { break; } remaining_path = remaining_path.parent().unwrap(); println!("{}", remaining_path.to_str().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 = ? and email =?"#) .bind(remaining_path.to_str().unwrap()) .bind(request.extensions().get::>().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()) } } fn access_auth (_uri: &str, _userid: i64) { // Check uri and userid for access and build the menu for links to the allowed resources let _user_auth = true; let _menu: Vec = vec![]; }