use dioxus::prelude::*; use crate::models::user::{User, UserCredentials}; use crate::util::error::Result; cfg_if::cfg_if! { if #[cfg(feature = "server")] { use dioxus::server::axum::Extension; use crate::server::{auth::{AuthSession, create_user}, config::Config, database::DbPool}; use crate::util::error::{AuthError, Contextualize, Error, ErrorType}; } } #[post("/api/v1/auth/signup", mut auth: Extension, db_pool: Extension, config: Extension)] pub async fn signup(credentials: UserCredentials) -> Result { if !config.auth.open_signup { return Err(Error::new_here(ErrorType::Auth(AuthError::Unauthorized))); } // Don't allow signup when already logged in if auth.user.is_some() { return Err(Error::new_here(ErrorType::Auth(AuthError::Unauthorized))); } let hashed_creds = credentials .try_hash() .map_err(|e| Error::message_here(e.to_string())) .err_context("Error hashing new user credentials")?; let mut db_conn = db_pool .get() .await .err_context("Failed to get database pool connection")?; let new_user = create_user(&mut db_conn, &hashed_creds) .await .err_context("Error creating user")?; // Don't return this to the client, logging in immediately isn't strictly necessary if let Err(e) = auth.login(&new_user).await { tracing::warn!("Failed to log in user after creating: {e}"); } Ok(new_user.into()) } #[post("/api/v1/auth/login", mut auth: Extension)] pub async fn login(credentials: UserCredentials) -> Result { let db_user = match auth.authenticate(credentials).await { Ok(Some(db_user)) => Ok(db_user), Ok(None) => Err(Error::new_here(ErrorType::Auth( AuthError::InvalidCredentials, ))), Err(axum_login::Error::Session(e)) => Err(Error::new_here(ErrorType::Auth( AuthError::Error(format!("Session error: {e}")), ))), Err(axum_login::Error::Backend(e)) => Err(e), } .err_context("Error authenticating")?; auth.login(&db_user) .await .map_err(|e| Error::new_here(ErrorType::Auth(AuthError::Error(e.to_string())))) .err_context("Error logging in")?; Ok(db_user.into()) } #[post("/api/v1/auth/logout", mut auth: Extension)] pub async fn logout() -> Result<()> { match auth.logout().await { Ok(_) => Ok(()), Err(axum_login::Error::Session(e)) => Err(Error::new_here(ErrorType::Auth( AuthError::Error(format!("Session error: {e}")), ))), Err(axum_login::Error::Backend(e)) => Err(e), } .err_context("Error logging out") } /// Retrieve the currently logged-in user, or `None` if unauthenticated #[get("/api/v1/auth/user", auth: Extension)] pub async fn get_user() -> Result> { Ok(auth.user.clone().map(Into::into)) }