From 2be126a7b3090c2b2b60df1cb933e666ac1461a3 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Thu, 27 Feb 2025 23:08:53 +0100 Subject: [PATCH] feat: migrate auth to repository system --- src/db/repository/auth.rs | 26 +++++++++++++++++++++- src/gpodder/mod.rs | 2 ++ src/server/gpodder/advanced/auth.rs | 34 ++++++----------------------- src/server/gpodder/mod.rs | 32 +++++++++++---------------- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/db/repository/auth.rs b/src/db/repository/auth.rs index 72a3956..32cbf87 100644 --- a/src/db/repository/auth.rs +++ b/src/db/repository/auth.rs @@ -4,7 +4,7 @@ use rand::Rng; use super::SqliteRepository; use crate::{ db::{self, schema::*}, - gpodder, + gpodder::{self, AuthErr}, }; impl From for gpodder::AuthErr { @@ -72,4 +72,28 @@ impl gpodder::AuthRepository for SqliteRepository { Err(gpodder::AuthErr::UnknownUser) } } + + fn remove_session(&self, username: &str, session_id: i64) -> Result<(), gpodder::AuthErr> { + let conn = &mut self.pool.get()?; + + if let Some(user) = sessions::table + .inner_join(users::table) + .filter(sessions::id.eq(session_id)) + .select(db::User::as_select()) + .get_result(conn) + .optional()? + { + if user.username == username { + Ok( + diesel::delete(sessions::table.filter(sessions::id.eq(session_id))) + .execute(conn) + .map(|_| ())?, + ) + } else { + Err(AuthErr::UnknownUser) + } + } else { + Ok(()) + } + } } diff --git a/src/gpodder/mod.rs b/src/gpodder/mod.rs index 9a887e7..5c0a362 100644 --- a/src/gpodder/mod.rs +++ b/src/gpodder/mod.rs @@ -19,6 +19,8 @@ pub trait AuthRepository: Send + Sync { username: &str, password: &str, ) -> Result<(i64, models::User), AuthErr>; + + fn remove_session(&self, username: &str, session_id: i64) -> Result<(), AuthErr>; } pub trait DeviceRepository: Send + Sync { diff --git a/src/server/gpodder/advanced/auth.rs b/src/server/gpodder/advanced/auth.rs index 97fb048..abdb0d6 100644 --- a/src/server/gpodder/advanced/auth.rs +++ b/src/server/gpodder/advanced/auth.rs @@ -13,7 +13,7 @@ use axum_extra::{ }; use crate::{ - db::{Session, User}, + gpodder::AuthRepository, server::{ error::{AppError, AppResult}, gpodder::SESSION_ID_COOKIE, @@ -38,20 +38,14 @@ async fn post_login( return Err(AppError::BadRequest); } - let session = tokio::task::spawn_blocking(move || { - let user = User::by_username(&ctx.pool, auth.username())?.ok_or(AppError::NotFound)?; - - if user.verify_password(auth.password()) { - Ok(Session::new_for_user(&ctx.pool, user.id)?) - } else { - Err(AppError::Unauthorized) - } + let (session_id, _) = tokio::task::spawn_blocking(move || { + ctx.repo.create_session(auth.username(), auth.password()) }) .await .unwrap()?; Ok(jar.add( - Cookie::build((SESSION_ID_COOKIE, session.id.to_string())).expires(Expiration::Session), + Cookie::build((SESSION_ID_COOKIE, session_id.to_string())).expires(Expiration::Session), )) } @@ -66,23 +60,9 @@ async fn post_logout( .parse() .map_err(|_| AppError::BadRequest)?; - tokio::task::spawn_blocking(move || { - if let Some(session) = Session::by_id(&ctx.pool, session_id)? { - let user = session.user(&ctx.pool)?.ok_or(AppError::NotFound)?; - - // The requested user to logout should be the same as the one linked to the session - // ID - if username == user.username { - Ok(session.remove(&ctx.pool)?) - } else { - Err(AppError::BadRequest) - } - } else { - Ok(false) - } - }) - .await - .unwrap()?; + tokio::task::spawn_blocking(move || ctx.repo.remove_session(&username, session_id)) + .await + .unwrap()?; Ok(jar.remove(SESSION_ID_COOKIE)) } else { diff --git a/src/server/gpodder/mod.rs b/src/server/gpodder/mod.rs index 6cc3c8e..0b9dedd 100644 --- a/src/server/gpodder/mod.rs +++ b/src/server/gpodder/mod.rs @@ -20,7 +20,10 @@ use axum_extra::{ }; use tower_http::set_header::SetResponseHeaderLayer; -use crate::{db, gpodder, server::error::AppError}; +use crate::{ + gpodder::{self, AuthRepository}, + server::error::AppError, +}; use super::Context; @@ -50,13 +53,13 @@ pub async fn auth_middleware(State(ctx): State, mut req: Request, next: .get(SESSION_ID_COOKIE) .and_then(|c| c.value().parse::().ok()) { - match tokio::task::spawn_blocking(move || db::Session::user_from_id(&ctx.pool, session_id)) + match tokio::task::spawn_blocking(move || ctx.repo.validate_session(session_id)) .await .unwrap() - .map_err(AppError::Db) + .map_err(AppError::from) { Ok(user) => { - auth_user = user; + auth_user = Some(user); } Err(err) => { return err.into_response(); @@ -67,21 +70,15 @@ pub async fn auth_middleware(State(ctx): State, mut req: Request, next: .await { match tokio::task::spawn_blocking(move || { - let user = - db::User::by_username(&ctx.pool, auth.username())?.ok_or(AppError::NotFound)?; - - if user.verify_password(auth.password()) { - Ok((db::Session::new_for_user(&ctx.pool, user.id)?, user)) - } else { - Err(AppError::Unauthorized) - } + ctx.repo.create_session(auth.username(), auth.password()) }) .await .unwrap() + .map_err(AppError::from) { - Ok((session, user)) => { + Ok((session_id, user)) => { auth_user = Some(user); - new_session_id = Some(session.id); + new_session_id = Some(session_id); } Err(err) => { return err.into_response(); @@ -90,11 +87,8 @@ pub async fn auth_middleware(State(ctx): State, mut req: Request, next: } if let Some(user) = auth_user { - req.extensions_mut().insert(user.clone()); - req.extensions_mut().insert(gpodder::User { - username: user.username, - id: user.id, - }); + req.extensions_mut().insert(user); + let res = next.run(req).await; if let Some(session_id) = new_session_id {