lyrs/src/state.rs
2024-07-14 20:21:52 -05:00

85 lines
2 KiB
Rust

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<Self> {
Ok(Self {
db: Data::try_new()?,
})
}
}
#[derive(Deserialize, Debug, Clone)]
pub struct Creds {
pub username: String,
pub password: Secret<String>,
}
#[derive(Debug)]
pub struct AuthnError {}
impl std::fmt::Display for AuthnError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("authentication error");
Ok(())
}
}
impl From<Error> for AuthnError {
fn from(_value: Error) -> Self {
Self {}
}
}
impl std::error::Error for AuthnError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
fn description(&self) -> &str {
"description() is deprecated; use Display"
}
fn cause(&self) -> Option<&dyn std::error::Error> {
self.source()
}
fn provide<'a>(&'a self, request: &mut std::error::Request<'a>) {}
}
#[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<Option<Self::User>, Self::Error> {
if let Some(user) = self.db.get::<String, User>(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<Self>) -> Result<Option<Self::User>, Self::Error> {
match self.db.get::<&str, User>(User::tree(), username)? {
Some(user) => Ok(Some(user)),
None => Ok(None),
}
}
}