diff --git a/backend/src/main.rs b/backend/src/main.rs index ada29a3..b38514e 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -13,7 +13,7 @@ mod middlewares; mod routes; use error_handling::AppError; -use middlewares::{check_auth, inject_user_data}; +use middlewares::inject_user_data; use google_oauth::{login, logout, google_auth_return}; use routes::{dashboard, index, about, profile, user_profile, useradmin}; @@ -66,7 +66,7 @@ async fn main() { .route("/login", get(login)) .route("/logout", get(logout)) .route("/google_auth_return", get(google_auth_return)) - .route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), check_auth)) + //.route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), check_auth)) .route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), inject_user_data)) .with_state(app_state.db_pool) .layer(Extension(user_data)) diff --git a/backend/src/middlewares.rs b/backend/src/middlewares.rs index 68b67c9..96771ac 100644 --- a/backend/src/middlewares.rs +++ b/backend/src/middlewares.rs @@ -6,7 +6,7 @@ use axum::{ extract::State, http::Request, middleware::Next, - response::{IntoResponse, Redirect}, + response::IntoResponse, }; use axum_extra::TypedHeader; use chrono::Utc; @@ -19,11 +19,8 @@ pub async fn inject_user_data( mut request: Request, next: Next, ) -> Result { - println!("inject_user_data : Injecting user data"); if let Some(cookie) = cookie { - println!("inject_user_data : {:#?}", cookie.get("session_token")); if let Some(session_token) = cookie.get("session_token") { - println!("inject_user_data : 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=?"#, @@ -46,7 +43,6 @@ pub async fn inject_user_data( session_token_p2_db, ) { let id = query.0; - println!("inject_user_data : Found user: {}", id); let expires_at = query.1; if expires_at > Utc::now().timestamp() { let row = sqlx::query_as!( @@ -62,10 +58,8 @@ pub async fn inject_user_data( email: row.email, name: row.name, family_name: row.family_name, - given_name: row.given_name, + given_name: row.given_name })); - } else { - println!("inject_user_data : Session expired"); } } } @@ -77,59 +71,22 @@ pub async fn inject_user_data( Ok(next.run(request).await) } -pub async fn check_auth( - State(app_state): State, - request: Request, - next: Next, -) -> Result { - println!("check_auth : Starting"); - //println!("{:#?}", request); - if request - .extensions() - .get::>() - .ok_or("check_auth: extensions have no UserData")? - .is_some() - { - let path = &*request.uri().to_string(); - println!( - "check_auth : {}", - &*request - .extensions() - .get::>() - .unwrap() - .as_ref() - .unwrap() - .email - ); - +pub async fn is_authorized(path: &str, user_data: Option, db_pool: SqlitePool) -> bool { + if let Some(user_data) = user_data { 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 + 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 join user_roles ur on ur.role_id = r.role_id left join users u on u.id = ur.user_id where item = ? and (email = ? or r.role_id = 1)"#) + 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 left join users u on u.id = ur.user_id where item = ?"#) .bind(remaining_path.to_str().unwrap()) - .bind(request.extensions().get::>().unwrap().as_ref().unwrap().email.as_str()) - .fetch_one(&app_state) + .fetch_one(&db_pool) .await; if let Ok(query) = query { if query.0 != "" { - println!("check_auth : found auth for {}", query.0); break; } } @@ -138,40 +95,19 @@ pub async fn check_auth( } 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 = ? and (email = ? or r.role_id = 1)"#) + 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) + .bind(user_data.email.as_str()) + .fetch_one(&db_pool) .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!("check_auth : Authenticated user {}", 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()); + if let Ok(query) = query { + if query.0 == user_data.id { + return true; + } } - - 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(); - //let login_url = "/login".to_owned(); - //Ok(Redirect::to(login_url.as_str()).into_response()) - //println!("check_auth : {:#?}", request.headers().get("referer").unwrap()); - println!("check_auth : No user data in the request"); - Ok(next.run(request).await) } -} + return false; +} \ No newline at end of file diff --git a/backend/src/routes.rs b/backend/src/routes.rs index da78ed4..3752818 100644 --- a/backend/src/routes.rs +++ b/backend/src/routes.rs @@ -1,9 +1,9 @@ use askama_axum::{Response, Template}; -use axum::{extract::{Path, State}, response::{Html, IntoResponse}, Extension}; +use axum::{extract::{Path, State}, response::{Html, IntoResponse, Redirect}, Extension}; use http::StatusCode; use sqlx::SqlitePool; -use crate::UserData; +use crate::{middlewares::is_authorized, UserData}; #[derive(Template)] #[template(path = "profile.html")] @@ -46,44 +46,57 @@ struct DashboardTemplate { } pub async fn index( + State(db_pool): State, Extension(user_data): Extension>, ) -> impl IntoResponse { - let user_name = user_data.map(|s| s.name); + let user_name = user_data.as_ref().map(|s| s.name.clone()); let logged_in = user_name.is_some(); let name = user_name.unwrap_or_default(); - println!("index : logged_in = {}, name = {}", logged_in, name); - - let template = IndexTemplate { logged_in, name }; - HtmlTemplate(template) + if is_authorized("/dashboard", user_data, db_pool).await { + Redirect::to("/dashboard").into_response() + } else { + let template = IndexTemplate { logged_in, name }; + HtmlTemplate(template).into_response() + } } pub async fn dashboard( + State(db_pool): State, Extension(user_data): Extension>, ) -> impl IntoResponse { - let user_name = user_data.map(|s| s.name); + let user_name = user_data.as_ref().map(|s| s.name.clone()); let logged_in = user_name.is_some(); let name = user_name.unwrap_or_default(); - let template = DashboardTemplate { logged_in, name}; - HtmlTemplate(template) + if is_authorized("/dashboard", user_data, db_pool).await { + let template = DashboardTemplate { logged_in, name}; + HtmlTemplate(template).into_response() + } else { + Redirect::to("/").into_response() + } } /// Handles the profile page. pub async fn profile( + State(db_pool): State, Extension(user_data): Extension>, ) -> impl IntoResponse { // Extract the user's name from the user data. let user_name = user_data.as_ref().map(|s| s.name.clone()); - let logged_in = user_data.is_some(); + let logged_in = user_name.is_some(); let name = user_name.unwrap_or_default(); // Extract the user data. - let user = user_data.as_ref().unwrap(); + let user = user_data.as_ref().unwrap().clone(); - // Create the profile template. - let template = ProfileTemplate { logged_in, name, user: user.clone() }; - return HtmlTemplate(template) + if is_authorized("/profile", user_data, db_pool).await { + // Create the profile template. + let template = ProfileTemplate { logged_in, name, user: user.clone() }; + return HtmlTemplate(template).into_response() + } else { + Redirect::to("/").into_response() + } } pub async fn user_profile( @@ -106,9 +119,13 @@ pub async fn profile( .await .unwrap(); - // Create the profile template. - let template = ProfileTemplate { logged_in, name, user: user }; - return HtmlTemplate(template) + if is_authorized("/users", user_data, db_pool).await { + // Create the profile template. + let template = ProfileTemplate { logged_in, name, user: user }; + return HtmlTemplate(template).into_response() + } else { + Redirect::to("/").into_response() + } } #[derive(Template)] @@ -124,17 +141,21 @@ pub async fn useradmin( State(db_pool): State, ) -> impl IntoResponse { - let user_email = user_data.map(|s| s.email); - let logged_in = user_email.is_some(); - let name = user_email.unwrap_or_default(); + let user_name = user_data.as_ref().map(|s| s.name.clone()); + let logged_in = user_name.is_some(); + let name = user_name.unwrap_or_default(); let users = sqlx::query_as::<_, UserData>("SELECT * FROM users") .fetch_all(&db_pool) .await .unwrap(); - let template = UserAdminTemplate { logged_in, name, users }; - HtmlTemplate(template) + if is_authorized("/useradmin", user_data, db_pool).await { + let template = UserAdminTemplate { logged_in, name, users }; + HtmlTemplate(template).into_response() + } else { + Redirect::to("/").into_response() + } } #[derive(Template)] diff --git a/backend/templates/index.html b/backend/templates/index.html index 3b61532..5de4cf6 100644 --- a/backend/templates/index.html +++ b/backend/templates/index.html @@ -2,10 +2,10 @@ {% block content %} {% if logged_in %} - + +

Your account has not yet been verified

{% else %} +{% endif %} -{% endif %} {% endblock content %} \ No newline at end of file