Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
administrator.rs 2.96 KiB
Newer Older
Pierre Jarriges's avatar
Pierre Jarriges committed
use crate::AppState;
use actix_web::http::Cookie;
use serde::{Deserialize, Serialize};
use wither::{
    bson::{doc, oid::ObjectId},
    prelude::Model,
};

#[derive(Debug, Serialize, Deserialize)]
/// The data type that must sent by form data POST to authenticate an administrator.
pub struct AdminAuthCredentials {
    pub username: String,
    pub password: String,
}

#[derive(Debug, Deserialize, Serialize, Model)]
#[model(index(
    keys = r#"doc!{"email": 1, "username": 1}"#,
    options = r#"doc!{"unique": true}"#
))]
/// An administrator is a user with registered authentication credentials access right to the admin-panel and has ability to perform admin actions such as gam review, moderation, etc.
pub struct Administrator {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub username: String,
    pub password_hash: String,
    pub auth_token: Option<String>,
}

impl Administrator {
    /// Creates an administrator with values for username and password.
    /// The auth_token fields remains None as it must be created if the user authenticates itself with the provided credentials
    /// The password is stored as password_hash, it is encrypted with the AppState::Encryption.
    pub fn from_values(app_state: &AppState, username: String, password: String) -> Self {
        Administrator {
            id: None,
            password_hash: app_state.encryption.encrypt(&password),
            username,
            auth_token: None,
        }
    }

    /// Performs authentication with form data <username, password>.
    /// Returns a Result with either an authenticated Administrator instance or an error.
    pub async fn authenticated(
        app_state: &AppState,
        credentials: AdminAuthCredentials,
    ) -> Result<Self, ()> {
        let filter_doc = doc! {
            "password_hash": app_state.encryption.encrypt(&credentials.password),
            "username": credentials.username
        };

        match Administrator::find_one(&app_state.db, filter_doc, None).await {
            Ok(user_option) => match user_option {
                Some(admin) => Ok(admin),
                None => Err(()),
            },
            Err(_) => Err(()),
        }
    }

    /// Performs authenticattion with auth cookie. The cookie value must match the Administrator auth_token value.
    /// Returns a result with either the authenticated admin, or an empty Err.
    pub async fn authenticated_with_cookie(
        app_state: &AppState,
        auth_cookie: &Cookie<'_>,
    ) -> Result<Self, ()> {
        let cookie_value = auth_cookie.value().to_string();

        let filter_doc = doc! {
            "auth_token": app_state.encryption.encrypt(&cookie_value),
        };

        match Administrator::find_one(&app_state.db, filter_doc, None).await {
            Ok(user_option) => match user_option {
                Some(admin) => Ok(admin),
                None => Err(()),
            },
            Err(_) => Err(()),
        }
    }
}