use crate::{db::Data, prelude::*, user::User}; use axum::async_trait; use axum_login::{AuthnBackend, UserId}; use redact::Secret; use serde::Deserialize; #[derive(Clone)] pub struct State { pub db: Data, } impl State { pub async fn try_new() -> AnyResult { Ok(Self { db: Data::try_new()?, }) } } #[derive(Deserialize, Debug, Clone)] pub struct Creds { pub username: String, pub password: Secret, } #[derive(thiserror::Error, Debug)] pub enum AuthnError { #[error("{0}")] Eyre(#[from] Error), } #[async_trait] impl AuthnBackend for State { type User = User; type Credentials = Creds; type Error = AuthnError; async fn authenticate( &self, Creds { username, password }: Self::Credentials, ) -> Result, Self::Error> { if let Some(user) = self.db.get::(User::tree(), username)? { if let Err(err) = user.verify(password.expose_secret()) { Err(err.into()) } else { Ok(Some(user)) } } else { Ok(None) } } async fn get_user(&self, username: &UserId) -> Result, Self::Error> { match self.db.get::<&str, User>(User::tree(), username)? { Some(user) => Ok(Some(user)), None => Ok(None), } } }