From 82f9098ed5c52a5cf40bc8aadf5f81a6ce841af8 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Fri, 28 Oct 2022 18:48:08 +0200 Subject: [PATCH] feat: candidate refresh token auth --- api/src/guard/candidate_refresh_token.rs | 27 ++++++++++++++++++++++++ api/src/guard/mod.rs | 3 ++- api/src/lib.rs | 15 ++++++++++++- core/src/error.rs | 5 ++++- core/src/services/candidate_service.rs | 24 +++++++++++++++++++-- 5 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 api/src/guard/candidate_refresh_token.rs diff --git a/api/src/guard/candidate_refresh_token.rs b/api/src/guard/candidate_refresh_token.rs new file mode 100644 index 0000000..dee824d --- /dev/null +++ b/api/src/guard/candidate_refresh_token.rs @@ -0,0 +1,27 @@ +use portfolio_core::sea_orm::prelude::Uuid; +use rocket::http::Status; +use rocket::outcome::Outcome; +use rocket::request::{FromRequest, Request}; + + +pub struct UUIDCookie(Uuid); + +impl UUIDCookie { + pub fn value(self) -> Uuid { + self.0 + } +} + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for UUIDCookie { + type Error = Status; + async fn from_request(req: &'r Request<'_>) -> Outcome { + let session_id = req.cookies().get("id").unwrap().name_value().1; + println!("session_id: {}", session_id); + + match Uuid::parse_str(&session_id) { + Ok(uuid) => Outcome::Success(UUIDCookie(uuid)), + Err(_) => return Outcome::Failure((Status::BadRequest, Status::BadRequest)), + } + } +} diff --git a/api/src/guard/mod.rs b/api/src/guard/mod.rs index f2318e8..6503da6 100644 --- a/api/src/guard/mod.rs +++ b/api/src/guard/mod.rs @@ -1 +1,2 @@ -pub mod candidate_jwt; \ No newline at end of file +pub mod candidate_jwt; +pub mod candidate_refresh_token; \ No newline at end of file diff --git a/api/src/lib.rs b/api/src/lib.rs index 1dde6de..75fe90d 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -28,6 +28,8 @@ pub use entity::candidate::Entity as Candidate; use portfolio_core::crypto::random_8_char_string; +use crate::guard::candidate_refresh_token::UUIDCookie; + fn custom_err_from_service_err(service_err: ServiceError) -> Custom { Custom(Status::from_code(service_err.0.code).unwrap_or_default(), service_err.1.to_string()) } @@ -54,7 +56,18 @@ async fn refresh_token(conn: Connection<'_, Db>, token_req: Result, uuid_cookie: Result) -> Result> { + let db = conn.into_inner(); + let user = CandidateService::auth_user_session(db, uuid_cookie.ok().unwrap().value()).await; + + + match user { + Ok(user) => Ok(user.application.to_string()), + Err(err) => Err(custom_err_from_service_err(err)) + } } #[post("/login", data = "")] @@ -112,7 +125,7 @@ async fn start() -> Result<(), rocket::Error> { .attach(Db::init()) .attach(AdHoc::try_on_ignite("Migrations", run_migrations)) //.mount("/", FileServer::from(relative!("/static"))) - .mount("/", routes![create, login, hello, whoami, refresh_token]) + .mount("/", routes![create, login, hello, whoami, refresh_token, validate]) .register("/", catchers![]) .launch() .await diff --git a/core/src/error.rs b/core/src/error.rs index b2093a7..e70cba8 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -13,6 +13,9 @@ pub const USER_NOT_FOUND_ERROR: ServiceError = ServiceError(Status { code: 404 } pub const DB_ERROR: ServiceError = ServiceError(Status { code: 500 }, "Database error"); -pub const USER_NOT_FOUND_BY_JWT_ID: ServiceError = ServiceError(Status { code: 500 }, // User got somehow +pub const USER_NOT_FOUND_BY_JWT_ID: ServiceError = ServiceError(Status { code: 500 }, // User got somehow deleted + "User not found, please contact technical support"); // Shouldn't ever happen + +pub const USER_NOT_FOUND_BY_SESSION_ID: ServiceError = ServiceError(Status { code: 500 }, // User got somehow deleted "User not found, please contact technical support"); // Shouldn't ever happen pub struct ServiceError<'a>(pub Status, pub &'a str); \ No newline at end of file diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 3ba2e8b..7e28180 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -1,7 +1,7 @@ use entity::candidate; -use sea_orm::DatabaseConnection; +use sea_orm::{DatabaseConnection, prelude::Uuid, ModelTrait}; -use crate::{crypto, Query, token::{generate_candidate_token, candidate_token::CandidateToken}, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID}}; +use crate::{crypto, Query, token::{generate_candidate_token, candidate_token::CandidateToken}, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID, USER_NOT_FOUND_BY_SESSION_ID}}; pub struct CandidateService; @@ -40,4 +40,24 @@ impl CandidateService { Ok(candidate) } + + pub async fn auth_user_session(db: &DatabaseConnection, uuid: Uuid) -> Result { + let session = match Query::find_session_by_uuid(db, uuid).await { + Ok(session) => match session { + Some(session) => session, + None => return Err(USER_NOT_FOUND_BY_SESSION_ID) + }, + Err(_) => {return Err(DB_ERROR)} + }; + + let candidate = match session.find_related(candidate::Entity).one(db).await { + Ok(candidate) => match candidate { + Some(candidate) => candidate, + None => return Err(USER_NOT_FOUND_BY_JWT_ID) + }, + Err(_) => {return Err(DB_ERROR)} + }; + + Ok(candidate) + } }