From 940de575ca40e906c714c6b4ae1d1cbb6b4fc3d6 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Mon, 15 Apr 2024 20:51:43 -0500 Subject: refactor(api): move login/logout into account mod --- src/api/users.rs | 150 +++---------------------------------------------------- 1 file changed, 6 insertions(+), 144 deletions(-) (limited to 'src/api/users.rs') diff --git a/src/api/users.rs b/src/api/users.rs index 3ac72d9..2440e6e 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -3,35 +3,20 @@ use std::str::FromStr; use axum::{ extract::{Path, State}, response::IntoResponse, - routing::get, - Json, Router, -}; -use axum_extra::{ - extract::{cookie::Cookie, CookieJar}, - headers::{authorization::Basic, Authorization}, - routing::Resource, - typed_header::TypedHeaderRejection, - TypedHeader, + Json, }; +use axum_extra::{headers::Authorization, routing::Resource, TypedHeader}; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use time::OffsetDateTime; use uuid::Uuid; -use crate::{ - auth::{AccessClaims, RefreshClaims}, - state::AppState, -}; +use crate::{auth::AccessClaims, state::AppState}; use super::error::Error; -pub fn router() -> Router { - let users = Resource::named("users").create(create).show(show); - - axum::Router::new() - .route("/users/login", get(login)) - .route("/users/logout", get(logout)) - .merge(users) +pub fn router() -> Resource { + Resource::named("users").create(create).show(show) } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromRow)] @@ -51,34 +36,6 @@ pub struct RegisterSchema { pub password: String, } -pub async fn login( - State(state): State, - auth: Result>, TypedHeaderRejection>, - claims: Option, -) -> Result<(AccessClaims, RefreshClaims), Error> { - if let Some(refresh_claims) = claims { - return Ok((refresh_claims.refresh(), refresh_claims)); - } - - let TypedHeader(Authorization(basic)) = auth?; - - let user_id = sqlx::query_scalar!("SELECT id FROM user_ WHERE email = $1", basic.username()) - .fetch_optional(&state.pool) - .await? - .ok_or(Error::UserNotFound)?; - - crate::auth::issue( - State(state.clone()), - TypedHeader(Authorization::basic(&user_id.to_string(), basic.password())), - ) - .await - .map_err(Into::into) -} - -pub async fn logout(claims: AccessClaims, jar: CookieJar) -> Result { - Ok(jar.remove(Cookie::try_from(claims)?)) -} - pub async fn create( State(state): State, Json(RegisterSchema { @@ -143,13 +100,12 @@ mod tests { use axum::{ body::Body, http::{ - header::{AUTHORIZATION, CONTENT_TYPE, COOKIE}, + header::{CONTENT_TYPE, COOKIE}, HeaderValue, Request, StatusCode, }, Router, }; - use axum_extra::headers::{authorization::Credentials, Header, HeaderMapExt, SetCookie}; use http_body_util::BodyExt; use sqlx::PgPool; use tower::ServiceExt; @@ -320,98 +276,4 @@ mod tests { Ok(()) } - - #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))] - async fn test_login_ok(pool: PgPool) -> TestResult { - setup_test_env(); - - let router = Router::new().merge(router()).with_state(AppState { pool }); - - let auth = Authorization::basic(USER_EMAIL, USER_PASSWORD); - - let request = Request::builder() - .uri("/users/login") - .method("GET") - .header(AUTHORIZATION, auth.0.encode()) - .body(Body::empty())?; - - let response = router.oneshot(request).await?; - - assert_eq!(StatusCode::OK, response.status()); - - Ok(()) - } - - #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))] - async fn test_issue_unauthorized(pool: PgPool) -> TestResult { - setup_test_env(); - - let router = Router::new().merge(router()).with_state(AppState { pool }); - - let auth = Authorization::basic(USER_EMAIL, "hunter2"); - - let request = Request::builder() - .uri("/users/login") - .method("GET") - .header(AUTHORIZATION, auth.0.encode()) - .body(Body::empty())?; - - let response = router.oneshot(request).await?; - - assert_eq!(StatusCode::UNAUTHORIZED, response.status()); - - Ok(()) - } - - #[sqlx::test] - async fn test_login_not_found(pool: PgPool) -> TestResult { - setup_test_env(); - - let router = Router::new().merge(router()).with_state(AppState { pool }); - - let auth = Authorization::basic(USER_EMAIL, USER_PASSWORD); - - let request = Request::builder() - .uri("/users/login") - .method("GET") - .header(AUTHORIZATION, auth.0.encode()) - .body(Body::empty())?; - - let response = router.oneshot(request).await?; - - assert_eq!(StatusCode::NOT_FOUND, response.status()); - - Ok(()) - } - - #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))] - async fn test_logout_ok(pool: PgPool) -> TestResult { - setup_test_env(); - - let router = Router::new().merge(router()).with_state(AppState { pool }); - - let request = Request::builder() - .uri("/users/logout") - .method("GET") - .header(COOKIE, HeaderValue::try_from(AccessClaims::new(USER_ID))?) - .body(Body::empty())?; - - let response = router.oneshot(request).await?; - - assert_eq!(StatusCode::OK, response.status()); - - if let Some(set_cookie) = response.headers().typed_get::() { - let mut values = Vec::new(); - set_cookie.encode(&mut values); - for value in values { - let cookie: Cookie = value.to_str()?.parse().unwrap(); - if cookie.name() == "token" { - assert_eq!(cookie.value(), ""); - assert_eq!(cookie.max_age(), Some(time::Duration::ZERO)); - } - } - } - - Ok(()) - } } -- cgit v1.2.3-70-g09d2