From 166ae172d0678dd390fec041641e2422a9e7e7b3 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 23 Feb 2025 13:05:33 +0100 Subject: [PATCH] feat: added logout POST route --- src/db/models/session.rs | 24 +++++++++++++++++++- src/server/gpodder/auth.rs | 45 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/db/models/session.rs b/src/db/models/session.rs index ac8fc3c..8534410 100644 --- a/src/db/models/session.rs +++ b/src/db/models/session.rs @@ -23,12 +23,34 @@ impl Session { .get_result(&mut pool.get()?)?) } - pub fn user_from_id(pool: &DbPool, id: i64) -> DbResult> { + pub fn user_from_id(pool: &DbPool, id: i64) -> DbResult { Ok(sessions::dsl::sessions .inner_join(users::table) .filter(sessions::id.eq(id)) .select(User::as_select()) + .get_result(&mut pool.get()?)?) + } + + pub fn user(&self, pool: &DbPool) -> DbResult { + Self::user_from_id(pool, self.id) + } + + pub fn by_id(pool: &DbPool, id: i64) -> DbResult> { + Ok(sessions::dsl::sessions + .find(id) .get_result(&mut pool.get()?) .optional()?) } + + pub fn remove(self, pool: &DbPool) -> DbResult { + Self::remove_by_id(pool, self.id) + } + + pub fn remove_by_id(pool: &DbPool, id: i64) -> DbResult { + Ok( + diesel::delete(sessions::dsl::sessions.filter(sessions::id.eq(id))) + .execute(&mut pool.get()?)? + > 0, + ) + } } diff --git a/src/server/gpodder/auth.rs b/src/server/gpodder/auth.rs index c907a77..a839c36 100644 --- a/src/server/gpodder/auth.rs +++ b/src/server/gpodder/auth.rs @@ -20,8 +20,12 @@ use crate::{ }, }; +const SESSION_ID_COOKIE: &str = "sessionid"; + pub fn router() -> Router { - Router::new().route("/{username}/login.json", post(post_login)) + Router::new() + .route("/{username}/login.json", post(post_login)) + .route("/{username}/logout.json", post(post_logout)) } async fn post_login( @@ -47,5 +51,42 @@ async fn post_login( .await .unwrap()?; - Ok(jar.add(Cookie::build(("sessionid", session.id.to_string())).expires(Expiration::Session))) + Ok(jar.add( + Cookie::build((SESSION_ID_COOKIE, session.id.to_string())).expires(Expiration::Session), + )) +} + +async fn post_logout( + State(ctx): State, + Path(username): Path, + jar: CookieJar, +) -> AppResult { + if let Some(session_id) = jar.get(SESSION_ID_COOKIE) { + let session_id: i64 = session_id + .value() + .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)?; + + // 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()?; + + Ok(jar.remove(SESSION_ID_COOKIE)) + } else { + Ok(jar) + } }