2024-05-17 13:55:16 -05:00
|
|
|
use crate::{
|
|
|
|
db::{self, Data},
|
|
|
|
prelude::*,
|
2024-05-20 17:00:23 -05:00
|
|
|
user::{self, User},
|
2024-05-17 13:55:16 -05:00
|
|
|
};
|
2024-05-20 17:00:23 -05:00
|
|
|
use axum::async_trait;
|
|
|
|
use axum_login::{AuthnBackend, UserId};
|
|
|
|
use redact::Secret;
|
|
|
|
use serde::Deserialize;
|
2024-05-17 12:00:37 -05:00
|
|
|
use thiserror::Error;
|
2024-05-14 12:28:27 -05:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct State {
|
2024-05-20 11:35:39 -05:00
|
|
|
pub db: Data,
|
2024-05-14 12:28:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
2024-05-20 11:35:39 -05:00
|
|
|
pub async fn try_new() -> Result<Self, NewStateError> {
|
2024-05-17 12:00:37 -05:00
|
|
|
Ok(Self {
|
2024-05-20 11:35:39 -05:00
|
|
|
db: Data::try_new()?,
|
2024-05-17 12:00:37 -05:00
|
|
|
})
|
2024-05-14 12:28:27 -05:00
|
|
|
}
|
|
|
|
}
|
2024-05-15 16:48:23 -05:00
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
pub enum NewStateError {
|
2024-05-17 12:00:37 -05:00
|
|
|
#[error("database error: {0}")]
|
2024-05-20 11:35:39 -05:00
|
|
|
Database(#[from] db::Error),
|
2024-05-15 16:48:23 -05:00
|
|
|
}
|
2024-05-20 17:00:23 -05:00
|
|
|
|
|
|
|
#[derive(Deserialize, Debug, Clone)]
|
|
|
|
pub struct Creds {
|
|
|
|
pub username: String,
|
|
|
|
pub password: Secret<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
pub enum AuthError {
|
|
|
|
#[error("user error: {0}")]
|
|
|
|
User(#[from] user::Error),
|
|
|
|
|
|
|
|
#[error("data error: {0}")]
|
|
|
|
Db(#[from] db::Error),
|
|
|
|
|
|
|
|
#[error("data error: {0}")]
|
|
|
|
Argon2(#[from] argon2::password_hash::Error),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl AuthnBackend for State {
|
|
|
|
type User = User;
|
|
|
|
type Credentials = Creds;
|
|
|
|
type Error = AuthError;
|
|
|
|
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|