From dfbf60525707f755ce20b679f78c1c462eca2184 Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Mon, 18 Dec 2023 16:48:54 -0800 Subject: [PATCH] minor re-org and tidy --- src/auth.rs | 21 +++++++++++++++------ src/lib.rs | 6 +++--- src/login.rs | 20 +++++++++++--------- src/main.rs | 1 - src/users.rs | 23 ++++------------------- 5 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index a22f51b..0eae37c 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,7 @@ use argon2::Argon2; use async_trait::async_trait; -use axum_login::{AuthnBackend, UserId}; +use axum_login::{AuthUser, AuthnBackend, UserId}; +use julid::Julid; use password_hash::{PasswordHash, PasswordVerifier}; use sqlx::SqlitePool; use tower_sessions::{cookie::time::Duration, Expiry, SessionManagerLayer, SqliteStore}; @@ -46,9 +47,7 @@ pub struct AuthError; #[async_trait] impl AuthnBackend for AuthStore { type User = User; - type Credentials = Credentials; - type Error = AuthError; async fn authenticate( @@ -57,9 +56,7 @@ impl AuthnBackend for AuthStore { ) -> Result, Self::Error> { let username = creds.username.trim(); let password = creds.password.trim(); - let user = User::try_get(username, &self) - .await - .map_err(|_| AuthError)?; + let user = User::try_get(username, self).await.map_err(|_| AuthError)?; let verifier = Argon2::default(); let hash = PasswordHash::new(&user.pwhash).map_err(|_| AuthError)?; @@ -79,6 +76,18 @@ impl AuthnBackend for AuthStore { } } +impl AuthUser for User { + type Id = Julid; + + fn id(&self) -> Self::Id { + self.id + } + + fn session_auth_hash(&self) -> &[u8] { + self.pwhash.as_bytes() + } +} + pub async fn session_layer(pool: SqlitePool) -> SessionManagerLayer { let store = SqliteStore::new(pool); store diff --git a/src/lib.rs b/src/lib.rs index 7a5c429..65e4496 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,6 @@ use sqlx::SqlitePool; #[macro_use] extern crate justerror; -#[cfg(test)] -pub mod test_utils; - /// Some public interfaces for interacting with the database outside of the web /// app pub use db::get_db_pool; @@ -89,6 +86,9 @@ pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService { .into_make_service() } +#[cfg(test)] +pub mod test_utils; + //-************************************************************************ // tests for the proc macro for optional user //-************************************************************************ diff --git a/src/login.rs b/src/login.rs index 6a1dc6f..c0962cc 100644 --- a/src/login.rs +++ b/src/login.rs @@ -1,4 +1,3 @@ - use axum::{ http::StatusCode, response::{IntoResponse, Redirect, Response}, @@ -6,7 +5,6 @@ use axum::{ }; use serde::{Deserialize, Serialize}; - use crate::{auth::Credentials, AuthSession, LoginPage, LogoutPage, LogoutSuccessPage}; //-************************************************************************ @@ -44,7 +42,7 @@ impl IntoResponse for LoginError { } // for receiving form submissions -#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] pub struct LoginPostForm { pub username: String, pub password: String, @@ -52,10 +50,10 @@ pub struct LoginPostForm { } impl From for Credentials { - fn from(value: LoginPostForm) -> Self { + fn from(form: LoginPostForm) -> Self { Self { - username: value.username, - password: value.password, + username: form.username, + password: form.password, } } } @@ -68,9 +66,10 @@ impl From for Credentials { #[axum::debug_handler] pub async fn post_login( mut auth: AuthSession, - Form(login): Form, + Form(mut login_form): Form, ) -> Result { - let user = auth.authenticate(login.into()).await.map_err(|e| { + let dest = login_form.destination.take(); + let user = auth.authenticate(login_form.into()).await.map_err(|e| { tracing::debug!("{e}"); LoginErrorKind::Unknown })?; @@ -81,7 +80,10 @@ pub async fn post_login( auth.login(&user) .await .map_err(|_| LoginErrorKind::Internal)?; - Ok(Redirect::to("/")) + match dest { + Some(dest) => Ok(Redirect::to(&dest)), + _ => Ok(Redirect::to("/")), + } } _ => Err(LoginErrorKind::BadPassword.into()), } diff --git a/src/main.rs b/src/main.rs index 4f0a871..0864318 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,6 @@ fn main() { rt.block_on(async { let addr: SocketAddr = ([0, 0, 0, 0], 3000).into(); tracing::debug!("binding to {addr:?}"); - let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); }); diff --git a/src/users.rs b/src/users.rs index bb76578..86381ed 100644 --- a/src/users.rs +++ b/src/users.rs @@ -1,19 +1,15 @@ -use std::{ - fmt::{Debug, Display}, - time::{SystemTime, UNIX_EPOCH}, -}; +use std::fmt::{Debug, Display}; use axum::{ extract::{Request, State}, middleware::Next, response::IntoResponse, }; -use axum_login::AuthUser; use julid::Julid; use serde::{Deserialize, Serialize}; use sqlx::SqlitePool; -use crate::auth::AuthSession; +use crate::AuthSession; const USERNAME_QUERY: &str = "select * from users where username = $1"; const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1"; @@ -53,20 +49,8 @@ impl Display for User { } } -impl AuthUser for User { - type Id = Julid; - - fn id(&self) -> Self::Id { - self.id - } - - fn session_auth_hash(&self) -> &[u8] { - self.pwhash.as_bytes() - } -} - impl User { - pub async fn try_get(username: &str, db: &SqlitePool) -> Result { + pub async fn try_get(username: &str, db: &SqlitePool) -> Result { sqlx::query_as(USERNAME_QUERY) .bind(username) .fetch_one(db) @@ -98,6 +82,7 @@ pub async fn handle_update_last_seen( request: Request, next: Next, ) -> impl IntoResponse { + use std::time::{SystemTime, UNIX_EPOCH}; if let Some(user) = auth.user { if let Some(then) = user.last_seen { let now = SystemTime::now()