mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 09:34:04 +00:00 
			
		
		
		
	Start to implement admin roles logic
This commit is contained in:
		@@ -289,3 +289,10 @@ CREATE TABLE `comunic_admin_key` (
 | 
			
		||||
  `time_add` INT NULL,
 | 
			
		||||
  `credential` TEXT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `comunic_admin_roles` (
 | 
			
		||||
  `id` INT NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `admin_id` INT NOT NULL,
 | 
			
		||||
  `role_id` VARCHAR(25) NULL,
 | 
			
		||||
  `time_insert` INT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 
 | 
			
		||||
@@ -15,3 +15,10 @@ CREATE TABLE `comunic_admin_key` (
 | 
			
		||||
  `time_add` INT NULL,
 | 
			
		||||
  `credential` TEXT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `comunic_admin_roles` (
 | 
			
		||||
  `id` INT NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `admin_id` INT NOT NULL,
 | 
			
		||||
  `role_id` VARCHAR(25) NULL,
 | 
			
		||||
  `time_insert` INT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@ pub mod database_tables_names {
 | 
			
		||||
    /// Administrators tables
 | 
			
		||||
    pub const ADMIN_LIST_TABLE: &str = "comunic_admin";
 | 
			
		||||
    pub const ADMIN_KEYS_TABLE: &str = "comunic_admin_key";
 | 
			
		||||
    pub const ADMIN_ROLES_TABLE: &str = "comunic_admin_roles";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Push Notifications Database prefix
 | 
			
		||||
@@ -260,3 +261,42 @@ pub mod accounts_info_policy {
 | 
			
		||||
 | 
			
		||||
/// Url where Firebase push notifications can be sent
 | 
			
		||||
pub const FIREBASE_PUSH_MESSAGE_URL: &str = "https://fcm.googleapis.com/v1/projects/{PROJECT_ID}/messages:send";
 | 
			
		||||
 | 
			
		||||
/// Admin-specific constants
 | 
			
		||||
pub mod admin {
 | 
			
		||||
    #[derive(Copy, Clone, Eq, PartialEq)]
 | 
			
		||||
    #[allow(non_camel_case_types)]
 | 
			
		||||
    pub enum AdminRole {
 | 
			
		||||
        MANAGE_ADMINS,
 | 
			
		||||
        MANAGE_USERS,
 | 
			
		||||
        ACCESS_FULL_ADMIN_LOGS,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub struct AdminRoleMetadata {
 | 
			
		||||
        pub role: AdminRole,
 | 
			
		||||
        pub id: &'static str,
 | 
			
		||||
        pub name: &'static str,
 | 
			
		||||
        pub description: &'static str,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub const ADMIN_ROLES_LIST: [AdminRoleMetadata; 3] = [
 | 
			
		||||
        AdminRoleMetadata {
 | 
			
		||||
            role: AdminRole::MANAGE_ADMINS,
 | 
			
		||||
            id: "manage_admins",
 | 
			
		||||
            name: "Manage administrators",
 | 
			
		||||
            description: "Allow the admin to create, list and update all administrators",
 | 
			
		||||
        },
 | 
			
		||||
        AdminRoleMetadata {
 | 
			
		||||
            role: AdminRole::MANAGE_USERS,
 | 
			
		||||
            id: "manage_users",
 | 
			
		||||
            name: "Manage Comunic users",
 | 
			
		||||
            description: "Allow the admin to list, reset password and delete Comunic users",
 | 
			
		||||
        },
 | 
			
		||||
        AdminRoleMetadata {
 | 
			
		||||
            role: AdminRole::ACCESS_FULL_ADMIN_LOGS,
 | 
			
		||||
            id: "access_full_admin_logs",
 | 
			
		||||
            name: "Access full admin logs",
 | 
			
		||||
            description: "Allow the admin to access the action history of all admins",
 | 
			
		||||
        }
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
@@ -4,6 +4,8 @@
 | 
			
		||||
 | 
			
		||||
use webauthn_rs::proto::Credential;
 | 
			
		||||
 | 
			
		||||
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
 | 
			
		||||
pub struct AdminID(u64);
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +39,7 @@ pub struct Admin {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub email: String,
 | 
			
		||||
    pub reset_token: Option<AdminResetToken>,
 | 
			
		||||
    pub roles: Vec<AdminRole>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AdminKey {
 | 
			
		||||
@@ -63,3 +66,20 @@ pub struct NewAdminGeneralSettings {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub email: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AdminRole {
 | 
			
		||||
    pub fn from_id(id: &str) -> Option<Self> {
 | 
			
		||||
        ADMIN_ROLES_LIST.iter()
 | 
			
		||||
            .filter(|r| r.id.eq(id))
 | 
			
		||||
            .map(|r| r.role)
 | 
			
		||||
            .next()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn to_id(&self) -> &'static str {
 | 
			
		||||
        ADMIN_ROLES_LIST.iter()
 | 
			
		||||
            .filter(|r| r.role.eq(self))
 | 
			
		||||
            .map(|r| r.id)
 | 
			
		||||
            .next()
 | 
			
		||||
            .expect("Should have found a role!!!")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@ use crate::constants::{ADMIN_RESET_TOKEN_LENGTH, ADMIN_RESET_TOKEN_LIFETIME};
 | 
			
		||||
use crate::constants::database_tables_names::ADMIN_LIST_TABLE;
 | 
			
		||||
use crate::data::admin::{Admin, AdminID, AdminResetToken, NewAdmin, NewAdminGeneralSettings};
 | 
			
		||||
use crate::data::error::{ExecError, Res};
 | 
			
		||||
use crate::helpers::database;
 | 
			
		||||
use crate::helpers::{admin_roles_helper, database};
 | 
			
		||||
use crate::utils::crypt_utils::rand_str;
 | 
			
		||||
use crate::utils::date_utils::time;
 | 
			
		||||
 | 
			
		||||
@@ -85,12 +85,14 @@ fn db_to_admin(row: &database::RowResult) -> Res<Admin> {
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let admin_id = row.get_admin_id("id")?;
 | 
			
		||||
 | 
			
		||||
    Ok(Admin {
 | 
			
		||||
        id: row.get_admin_id("id")?,
 | 
			
		||||
        id: admin_id,
 | 
			
		||||
        time_create: row.get_u64("time_create")?,
 | 
			
		||||
        name: row.get_str("name")?,
 | 
			
		||||
        email: row.get_str("email")?,
 | 
			
		||||
        reset_token,
 | 
			
		||||
        roles: admin_roles_helper::get_roles(admin_id)?,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/helpers/admin_roles_helper.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/helpers/admin_roles_helper.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
//! # Admin roles helper
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use crate::constants::admin::AdminRole;
 | 
			
		||||
use crate::constants::database_tables_names::ADMIN_ROLES_TABLE;
 | 
			
		||||
use crate::data::admin::AdminID;
 | 
			
		||||
use crate::data::error::{ExecError, Res};
 | 
			
		||||
use crate::helpers::database;
 | 
			
		||||
use crate::utils::date_utils::time;
 | 
			
		||||
 | 
			
		||||
/// Get the list of roles of a given administrator
 | 
			
		||||
pub fn get_roles(id: AdminID) -> Res<Vec<AdminRole>> {
 | 
			
		||||
    database::QueryInfo::new(ADMIN_ROLES_TABLE)
 | 
			
		||||
        .cond_admin_id("id", id)
 | 
			
		||||
        .exec(db_to_role)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Add a new role to a user
 | 
			
		||||
pub fn add_role(id: AdminID, role: AdminRole) -> Res {
 | 
			
		||||
    database::InsertQuery::new(ADMIN_ROLES_TABLE)
 | 
			
		||||
        .add_admin_id("admin_id", id)
 | 
			
		||||
        .add_str("role_id", role.to_id())
 | 
			
		||||
        .add_u64("time_insert", time())
 | 
			
		||||
        .insert_drop_result()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn db_to_role(row: &database::RowResult) -> Res<AdminRole> {
 | 
			
		||||
    let role_id = row.get_str("role_id")?;
 | 
			
		||||
 | 
			
		||||
    let role = AdminRole::from_id(&role_id);
 | 
			
		||||
 | 
			
		||||
    match role {
 | 
			
		||||
        None => Err(ExecError::boxed_string(format!("Role {} from database not found in the list!", role_id))),
 | 
			
		||||
        Some(r) => Ok(r)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,3 +27,4 @@ pub mod admin_account_key_helper;
 | 
			
		||||
pub mod admin_access_token_helper;
 | 
			
		||||
pub mod admin_key_registration_challenges_helper;
 | 
			
		||||
pub mod admin_key_authentication_challenges_helper;
 | 
			
		||||
pub mod admin_roles_helper;
 | 
			
		||||
							
								
								
									
										81
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,17 +1,18 @@
 | 
			
		||||
use comunic_server::{cleanup_thread, server};
 | 
			
		||||
use comunic_server::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
 | 
			
		||||
use comunic_server::data::admin::NewAdmin;
 | 
			
		||||
use comunic_server::data::config::{conf, Config};
 | 
			
		||||
use comunic_server::data::error::Res;
 | 
			
		||||
use comunic_server::data::user::UserID;
 | 
			
		||||
use comunic_server::helpers::{account_helper, admin_account_helper, database};
 | 
			
		||||
use comunic_server::helpers::{account_helper, admin_account_helper, admin_roles_helper, database};
 | 
			
		||||
use comunic_server::utils::date_utils::current_year;
 | 
			
		||||
 | 
			
		||||
type MainActionFunction = Res;
 | 
			
		||||
 | 
			
		||||
struct Action {
 | 
			
		||||
    name: String,
 | 
			
		||||
    description: String,
 | 
			
		||||
    arguments: Vec<String>,
 | 
			
		||||
    name: &'static str,
 | 
			
		||||
    description: &'static str,
 | 
			
		||||
    arguments: Vec<&'static str>,
 | 
			
		||||
    function: Box<dyn Fn(Vec<String>) -> MainActionFunction>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -19,43 +20,59 @@ fn get_actions() -> Vec<Action> {
 | 
			
		||||
    vec![
 | 
			
		||||
        // Start server
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "serve".to_string(),
 | 
			
		||||
            description: "Start the Comunic Server (default action)".to_string(),
 | 
			
		||||
            name: "serve",
 | 
			
		||||
            description: "Start the Comunic Server (default action)",
 | 
			
		||||
            arguments: vec![],
 | 
			
		||||
            function: Box::new(serve),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Show help
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "help".to_string(),
 | 
			
		||||
            description: "Show this help".to_string(),
 | 
			
		||||
            name: "help",
 | 
			
		||||
            description: "Show this help",
 | 
			
		||||
            arguments: vec![],
 | 
			
		||||
            function: Box::new(help),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Reset password
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "reset_password".to_string(),
 | 
			
		||||
            description: "Create a password reset URL for a user".to_string(),
 | 
			
		||||
            arguments: vec!["user_id".to_string()],
 | 
			
		||||
            name: "reset_password",
 | 
			
		||||
            description: "Create a password reset URL for a user",
 | 
			
		||||
            arguments: vec!["user_id"],
 | 
			
		||||
            function: Box::new(reset_password),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Create a new administrator
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "create_admin".to_string(),
 | 
			
		||||
            description: "Create a new administrator account".to_string(),
 | 
			
		||||
            arguments: vec!["name".to_string(), "email".to_string()],
 | 
			
		||||
            name: "create_admin",
 | 
			
		||||
            description: "Create a new administrator account",
 | 
			
		||||
            arguments: vec!["name", "email"],
 | 
			
		||||
            function: Box::new(create_admin),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Create a reset token for an admin
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "create_admin_reset_token".to_string(),
 | 
			
		||||
            description: "Create a new reset token to register a new access key to an admin account".to_string(),
 | 
			
		||||
            arguments: vec!["email".to_string()],
 | 
			
		||||
            name: "create_admin_reset_token",
 | 
			
		||||
            description: "Create a new reset token to register a new access key to an admin account",
 | 
			
		||||
            arguments: vec!["email"],
 | 
			
		||||
            function: Box::new(create_admin_reset_token),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Get the list of available admin roles
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "list_admin_roles",
 | 
			
		||||
            description: "Get the list of available admin roles",
 | 
			
		||||
            arguments: vec![],
 | 
			
		||||
            function: Box::new(list_admin_roles),
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        // Attribute a role to an admin
 | 
			
		||||
        Action {
 | 
			
		||||
            name: "grant_admin_role",
 | 
			
		||||
            description: "Grant a role to an admin",
 | 
			
		||||
            arguments: vec!["mail", "role_id"],
 | 
			
		||||
            function: Box::new(grant_admin_role),
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -143,7 +160,7 @@ fn help(_a: Vec<String>) -> Res {
 | 
			
		||||
    println!("Usage: {} [conf-file] [action] [args...]", std::env::args().next().unwrap());
 | 
			
		||||
    println!("Available actions:");
 | 
			
		||||
    for action in get_actions() {
 | 
			
		||||
        println!("\t{}\t{} - {}",
 | 
			
		||||
        println!("\t{} {}\t- {}",
 | 
			
		||||
                 action.name,
 | 
			
		||||
                 action.arguments.iter().map(|s| format!("[{}]", s)).collect::<Vec<String>>().join(" "),
 | 
			
		||||
                 action.description
 | 
			
		||||
@@ -194,3 +211,31 @@ fn create_admin_reset_token(args: Vec<String>) -> Res {
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn list_admin_roles(_a: Vec<String>) -> Res {
 | 
			
		||||
    println!("Here are the currently defined roles in the code:\n");
 | 
			
		||||
 | 
			
		||||
    for role in Vec::from(ADMIN_ROLES_LIST) {
 | 
			
		||||
        println!("* {} - {}\n{}\n", role.id, role.name, role.description);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn grant_admin_role(args: Vec<String>) -> Res {
 | 
			
		||||
    let role = AdminRole::from_id(&args[1])
 | 
			
		||||
        .expect("Requested role does not exist!");
 | 
			
		||||
 | 
			
		||||
    let admin = admin_account_helper::find_admin_by_email(&args[0])
 | 
			
		||||
        .expect("Failed to load admin information!");
 | 
			
		||||
 | 
			
		||||
    if admin.roles.contains(&role) {
 | 
			
		||||
        eprintln!("The administrator has already this role!");
 | 
			
		||||
        std::process::exit(-3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    admin_roles_helper::add_role(admin.id, role)?;
 | 
			
		||||
 | 
			
		||||
    println!("Success.");
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user