userp 0.0.4

Userp is a user account system inspired by Next Auth, with OAuth, password and email support, a ready-made Axum router with Askama templates, and more on the way!
Documentation
use crate::{
    config::Allow,
    core::CoreUserp,
    enums::LoginMethod,
    traits::{User, UserpCookies, UserpStore},
};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum PasswordLoginError<T: std::error::Error> {
    #[error("Password login not allowed")]
    NotAllowed,
    #[error("User doesn't exists")]
    NoUser,
    #[error("Wrong password")]
    WrongPassword,
    #[error(transparent)]
    StoreError(#[from] T),
}

impl<S: UserpStore, C: UserpCookies> CoreUserp<S, C> {
    #[must_use = "Don't forget to return the auth session as part of the response!"]
    pub async fn password_login(
        self,
        password_id: &str,
        password: &str,
    ) -> Result<Self, PasswordLoginError<S::Error>> {
        if self.pass.allow_login.as_ref().unwrap_or(&self.allow_login) == &Allow::Never {
            return Err(PasswordLoginError::NotAllowed);
        };

        let allow_signup = self
            .pass
            .allow_signup
            .as_ref()
            .unwrap_or(&self.allow_signup)
            == &Allow::OnEither;

        let user = match self
            .store
            .password_get_user_by_password_id(password_id)
            .await?
        {
            Some(user) => match user.get_password_hash() {
                Some(hash) => {
                    if self
                        .pass
                        .hasher
                        .verify_password(password.into(), hash)
                        .await
                    {
                        Ok(user)
                    } else {
                        Err(PasswordLoginError::WrongPassword)
                    }
                }
                None => Err(PasswordLoginError::NotAllowed),
            },
            None if allow_signup => Ok(self
                .store
                .password_create_user(
                    password_id,
                    &self.pass.hasher.genereate_hash(password.to_string()).await,
                )
                .await?),
            None => Err(PasswordLoginError::NoUser),
        }?;

        Ok(self.log_in(LoginMethod::Password, user.get_id()).await?)
    }
}