From 8f282febc830afe222032dd6fcd4ce9fd83ff753 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Thu, 24 Nov 2022 20:08:40 +0100 Subject: [PATCH 1/3] fix: not deleting sessions --- core/src/database/query/session.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/database/query/session.rs b/core/src/database/query/session.rs index 0361997..6a1eb14 100644 --- a/core/src/database/query/session.rs +++ b/core/src/database/query/session.rs @@ -18,9 +18,13 @@ impl Query { user_id: Option, admin_id: Option, ) -> Result, DbErr> { - Session::find() - .filter(session::Column::UserId.eq(user_id)) - .filter(session::Column::AdminId.eq(admin_id)) + if user_id.is_some() { + Session::find() + .filter(session::Column::UserId.eq(user_id)) + } else { + Session::find() + .filter(session::Column::AdminId.eq(admin_id)) + } .all(db) .await } From 35f591fb670855f997879a3d66b4a6ebc24777b6 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Thu, 24 Nov 2022 20:09:14 +0100 Subject: [PATCH 2/3] feat: candidate logout endpoint --- api/src/lib.rs | 1 + api/src/routes/candidate.rs | 13 +++++++++++++ core/src/services/candidate_service.rs | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/api/src/lib.rs b/api/src/lib.rs index d5752f4..b0f903e 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -40,6 +40,7 @@ pub fn rocket() -> Rocket{ "/candidate/", routes![ routes::candidate::login, + routes::candidate::logout, routes::candidate::whoami, routes::candidate::get_details, ], diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 7068bb6..905ef87 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -51,6 +51,19 @@ pub async fn login( return Ok(response); } +#[post("/logout")] +pub async fn logout(conn: Connection<'_, Db>, session: CandidateAuth, cookies: &CookieJar<'_>,) -> Result<(), Custom> { + let db = conn.into_inner(); + let candidate: entity::candidate::Model = session.into(); + + cookies.remove_private(Cookie::named("id")); + cookies.remove_private(Cookie::named("key")); + + CandidateService::logout(db, candidate.application) + .await + .map_err(|e| Custom(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), e.to_string())) +} + #[get("/whoami")] pub async fn whoami(session: CandidateAuth) -> Result> { let candidate: entity::candidate::Model = session.into(); diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 264535a..f4b6b1b 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -131,6 +131,11 @@ impl CandidateService { Ok(new_password_plain) } + pub async fn logout(db: &DbConn, id: i32) -> Result<(), ServiceError> { + SessionService::revoke_all_sessions(db, Some(id), None).await?; + Ok(()) + } + pub(in crate::services) async fn add_candidate_details( db: &DbConn, candidate: candidate::Model, From 492fc5618f59b581644c913a9cfd660b04985fbb Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Fri, 25 Nov 2022 23:02:25 +0100 Subject: [PATCH 3/3] feat: logout only current session, admin logout endpoint --- api/src/lib.rs | 1 + api/src/routes/admin.rs | 21 ++++++++++++++++++++- api/src/routes/candidate.rs | 17 ++++++++++++----- core/src/services/admin_service.rs | 7 ++++++- core/src/services/candidate_service.rs | 4 ++-- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index b0f903e..edd5814 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -68,6 +68,7 @@ pub fn rocket() -> Rocket{ "/admin/", routes![ routes::admin::login, + routes::admin::logout, routes::admin::whoami, routes::admin::hello, routes::admin::create_candidate, diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index a9348ba..3700704 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -2,7 +2,7 @@ use std::net::{SocketAddr, IpAddr, Ipv4Addr}; use portfolio_core::{ crypto::random_8_char_string, - services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::CandidateResponse, candidate_details::ApplicationDetails, + services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::CandidateResponse, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, }; use requests::{AdminLoginRequest, RegisterRequest}; use rocket::http::{Cookie, Status, CookieJar}; @@ -51,6 +51,25 @@ pub async fn login( return Ok(response); } +#[post("/logout")] +pub async fn logout(conn: Connection<'_, Db>, _session: AdminAuth, cookies: &CookieJar<'_>,) -> Result<(), Custom> { + let db = conn.into_inner(); + + let cookie = cookies.get_private("id") // unwrap would be safe here because of the auth guard + .ok_or(Custom(Status::Unauthorized, "No session cookie".to_string()))?; + let session_id = Uuid::try_parse(cookie.value()) // unwrap would be safe here because of the auth guard + .map_err(|e| Custom(Status::BadRequest, e.to_string()))?; + + let res = AdminService::logout(db, session_id) + .await + .map_err(|e| Custom(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), e.to_string()))?; + + cookies.remove_private(Cookie::named("id")); + cookies.remove_private(Cookie::named("key")); + + Ok(res) +} + #[get("/whoami")] pub async fn whoami(session: AdminAuth) -> Result> { diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 905ef87..6328b23 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -1,6 +1,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use portfolio_core::candidate_details::ApplicationDetails; +use portfolio_core::sea_orm::prelude::Uuid; use portfolio_core::services::application_service::ApplicationService; use portfolio_core::services::candidate_service::CandidateService; use portfolio_core::services::portfolio_service::{PortfolioService, SubmissionProgress}; @@ -52,16 +53,22 @@ pub async fn login( } #[post("/logout")] -pub async fn logout(conn: Connection<'_, Db>, session: CandidateAuth, cookies: &CookieJar<'_>,) -> Result<(), Custom> { +pub async fn logout(conn: Connection<'_, Db>, _session: CandidateAuth, cookies: &CookieJar<'_>,) -> Result<(), Custom> { let db = conn.into_inner(); - let candidate: entity::candidate::Model = session.into(); + + let cookie = cookies.get_private("id") // unwrap would be safe here because of the auth guard + .ok_or(Custom(Status::Unauthorized, "No session cookie".to_string()))?; + let session_id = Uuid::try_parse(cookie.value()) // unwrap would be safe here because of the auth guard + .map_err(|e| Custom(Status::BadRequest, e.to_string()))?; + + let res = CandidateService::logout(db, session_id) + .await + .map_err(|e| Custom(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), e.to_string()))?; cookies.remove_private(Cookie::named("id")); cookies.remove_private(Cookie::named("key")); - CandidateService::logout(db, candidate.application) - .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), e.to_string())) + Ok(res) } #[get("/whoami")] diff --git a/core/src/services/admin_service.rs b/core/src/services/admin_service.rs index 9e23b65..fd7a62a 100644 --- a/core/src/services/admin_service.rs +++ b/core/src/services/admin_service.rs @@ -1,7 +1,7 @@ use entity::admin; use sea_orm::{prelude::Uuid, DbConn}; -use crate::{crypto, error::ServiceError, Query}; +use crate::{crypto, error::ServiceError, Query, Mutation}; use super::session_service::{AdminUser, SessionService}; @@ -38,6 +38,11 @@ impl AdminService { Ok((session_id, private_key)) } + pub async fn logout(db: &DbConn, session_id: Uuid) -> Result<(), ServiceError> { + Mutation::delete_session(db, session_id).await?; + Ok(()) + } + pub async fn auth(db: &DbConn, session_uuid: Uuid) -> Result { match SessionService::auth_user_session(db, session_uuid).await? { AdminUser::Admin(admin) => Ok(admin), diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index f4b6b1b..a62a9e6 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -131,8 +131,8 @@ impl CandidateService { Ok(new_password_plain) } - pub async fn logout(db: &DbConn, id: i32) -> Result<(), ServiceError> { - SessionService::revoke_all_sessions(db, Some(id), None).await?; + pub async fn logout(db: &DbConn, session_id: Uuid) -> Result<(), ServiceError> { + Mutation::delete_session(db, session_id).await?; Ok(()) }