mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-12-26 05:28:50 +00:00
Start to implement admin roles logic
This commit is contained in:
parent
57a5752fe7
commit
73837553c7
@ -288,4 +288,11 @@ CREATE TABLE `comunic_admin_key` (
|
||||
`name` VARCHAR(45) NULL,
|
||||
`time_add` INT NULL,
|
||||
`credential` TEXT NULL,
|
||||
PRIMARY KEY (`id`));
|
||||
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
|
||||
@ -259,4 +260,43 @@ 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";
|
||||
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 {
|
||||
@ -62,4 +65,21 @@ pub struct NewAdminGeneralSettings {
|
||||
pub id: AdminID,
|
||||
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)
|
||||
}
|
||||
}
|
@ -26,4 +26,5 @@ pub mod admin_account_helper;
|
||||
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_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
|
||||
@ -192,5 +209,33 @@ fn create_admin_reset_token(args: Vec<String>) -> Res {
|
||||
|
||||
println!("Reset token: {}", token.token);
|
||||
|
||||
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(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user