rocket_auth2 0.6.2

A high level authentication management library for Rocket applications. It supports both SQLite and Postgres.
Documentation
pub mod auth;
pub mod roles;
mod user_impl;
mod users;

use crate::prelude::*;
use argon2::verify_encoded as verify;

use crate::Roles;
use rand::random;

pub fn rand_string(size: usize) -> String {
    (0..)
        .map(|_| random::<char>())
        .filter(|c| c.is_ascii())
        .map(char::from)
        .take(size)
        .collect()
}

impl Users {
    fn is_auth(&self, session: &Session) -> bool {
        let option = self.sess.get(session.id);
        if let Some(auth_key) = option {
            auth_key == session.auth_key
        } else {
            false
        }
    }

    async fn login(&self, form: &Login) -> Result<String> {
        let form_pwd = &form.password.as_bytes();
        let user = self
            .conn
            .get_user_by_email(&form.email.to_lowercase())
            .await
            .map_err(|_| Error::EmailDoesNotExist(form.email.clone()))?;
        let user_pwd = &user.password;

        if verify(user_pwd, form_pwd)? {
            self.set_auth_key(user.id)
        } else {
            Err(Error::UnauthorizedError)
        }
    }

    fn logout(&self, session: &Session) -> Result<()> {
        if self.is_auth(session) {
            self.sess.remove(session.id)?;
        }

        Ok(())
    }

    fn set_auth_key_for(&self, user_id: i32, time: Duration) -> Result<String> {
        let key = rand_string(10);
        self.sess.insert_for(user_id, key.clone(), time)?;
        Ok(key)
    }

    fn set_auth_key(&self, user_id: i32) -> Result<String> {
        let key = rand_string(15);
        self.sess.insert(user_id, key.clone())?;
        Ok(key)
    }

    async fn signup(&self, form: &Signup) -> Result<()> {
        form.validate()?;
        let email = &form.email.to_lowercase();
        let password = &form.password;
        let result = self.create_user(email, password, &Roles::default()).await;
        match result {
            Ok(_) => Ok(()),
            #[cfg(feature = "sqlx")]
            Err(Error::SqlxError(sqlx::Error::Database(error))) => {
                if error.code() == Some("23000".into()) {
                    Err(Error::EmailAlreadyExists)
                } else {
                    Err(Error::SqlxError(sqlx::Error::Database(error)))
                }
            }
            Err(error) => Err(error),
        }
    }

    async fn login_for(&self, form: &Login, time: Duration) -> Result<String> {
        let form_pwd = &form.password.as_bytes();
        let user = self
            .conn
            .get_user_by_email(&form.email.to_lowercase())
            .await?;
        let user_pwd = &user.password;

        if verify(user_pwd, form_pwd)? {
            self.set_auth_key_for(user.id, time)
        } else {
            Err(Error::UnauthorizedError)
        }
    }
}