mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-11-22 21:39:21 +00:00
Start to implement admin roles logic
This commit is contained in:
parent
57a5752fe7
commit
73837553c7
@ -289,3 +289,10 @@ CREATE TABLE `comunic_admin_key` (
|
|||||||
`time_add` INT NULL,
|
`time_add` INT NULL,
|
||||||
`credential` TEXT 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,
|
`time_add` INT NULL,
|
||||||
`credential` TEXT 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`));
|
||||||
|
@ -64,6 +64,7 @@ pub mod database_tables_names {
|
|||||||
/// Administrators tables
|
/// Administrators tables
|
||||||
pub const ADMIN_LIST_TABLE: &str = "comunic_admin";
|
pub const ADMIN_LIST_TABLE: &str = "comunic_admin";
|
||||||
pub const ADMIN_KEYS_TABLE: &str = "comunic_admin_key";
|
pub const ADMIN_KEYS_TABLE: &str = "comunic_admin_key";
|
||||||
|
pub const ADMIN_ROLES_TABLE: &str = "comunic_admin_roles";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push Notifications Database prefix
|
/// Push Notifications Database prefix
|
||||||
@ -260,3 +261,42 @@ pub mod accounts_info_policy {
|
|||||||
|
|
||||||
/// Url where Firebase push notifications can be sent
|
/// 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 webauthn_rs::proto::Credential;
|
||||||
|
|
||||||
|
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
||||||
pub struct AdminID(u64);
|
pub struct AdminID(u64);
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ pub struct Admin {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub reset_token: Option<AdminResetToken>,
|
pub reset_token: Option<AdminResetToken>,
|
||||||
|
pub roles: Vec<AdminRole>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AdminKey {
|
pub struct AdminKey {
|
||||||
@ -63,3 +66,20 @@ pub struct NewAdminGeneralSettings {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub email: 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::constants::database_tables_names::ADMIN_LIST_TABLE;
|
||||||
use crate::data::admin::{Admin, AdminID, AdminResetToken, NewAdmin, NewAdminGeneralSettings};
|
use crate::data::admin::{Admin, AdminID, AdminResetToken, NewAdmin, NewAdminGeneralSettings};
|
||||||
use crate::data::error::{ExecError, Res};
|
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::crypt_utils::rand_str;
|
||||||
use crate::utils::date_utils::time;
|
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 {
|
Ok(Admin {
|
||||||
id: row.get_admin_id("id")?,
|
id: admin_id,
|
||||||
time_create: row.get_u64("time_create")?,
|
time_create: row.get_u64("time_create")?,
|
||||||
name: row.get_str("name")?,
|
name: row.get_str("name")?,
|
||||||
email: row.get_str("email")?,
|
email: row.get_str("email")?,
|
||||||
reset_token,
|
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_access_token_helper;
|
||||||
pub mod admin_key_registration_challenges_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::{cleanup_thread, server};
|
||||||
|
use comunic_server::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
|
||||||
use comunic_server::data::admin::NewAdmin;
|
use comunic_server::data::admin::NewAdmin;
|
||||||
use comunic_server::data::config::{conf, Config};
|
use comunic_server::data::config::{conf, Config};
|
||||||
use comunic_server::data::error::Res;
|
use comunic_server::data::error::Res;
|
||||||
use comunic_server::data::user::UserID;
|
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;
|
use comunic_server::utils::date_utils::current_year;
|
||||||
|
|
||||||
type MainActionFunction = Res;
|
type MainActionFunction = Res;
|
||||||
|
|
||||||
struct Action {
|
struct Action {
|
||||||
name: String,
|
name: &'static str,
|
||||||
description: String,
|
description: &'static str,
|
||||||
arguments: Vec<String>,
|
arguments: Vec<&'static str>,
|
||||||
function: Box<dyn Fn(Vec<String>) -> MainActionFunction>,
|
function: Box<dyn Fn(Vec<String>) -> MainActionFunction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,43 +20,59 @@ fn get_actions() -> Vec<Action> {
|
|||||||
vec![
|
vec![
|
||||||
// Start server
|
// Start server
|
||||||
Action {
|
Action {
|
||||||
name: "serve".to_string(),
|
name: "serve",
|
||||||
description: "Start the Comunic Server (default action)".to_string(),
|
description: "Start the Comunic Server (default action)",
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
function: Box::new(serve),
|
function: Box::new(serve),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Show help
|
// Show help
|
||||||
Action {
|
Action {
|
||||||
name: "help".to_string(),
|
name: "help",
|
||||||
description: "Show this help".to_string(),
|
description: "Show this help",
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
function: Box::new(help),
|
function: Box::new(help),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Reset password
|
// Reset password
|
||||||
Action {
|
Action {
|
||||||
name: "reset_password".to_string(),
|
name: "reset_password",
|
||||||
description: "Create a password reset URL for a user".to_string(),
|
description: "Create a password reset URL for a user",
|
||||||
arguments: vec!["user_id".to_string()],
|
arguments: vec!["user_id"],
|
||||||
function: Box::new(reset_password),
|
function: Box::new(reset_password),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Create a new administrator
|
// Create a new administrator
|
||||||
Action {
|
Action {
|
||||||
name: "create_admin".to_string(),
|
name: "create_admin",
|
||||||
description: "Create a new administrator account".to_string(),
|
description: "Create a new administrator account",
|
||||||
arguments: vec!["name".to_string(), "email".to_string()],
|
arguments: vec!["name", "email"],
|
||||||
function: Box::new(create_admin),
|
function: Box::new(create_admin),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Create a reset token for an admin
|
// Create a reset token for an admin
|
||||||
Action {
|
Action {
|
||||||
name: "create_admin_reset_token".to_string(),
|
name: "create_admin_reset_token",
|
||||||
description: "Create a new reset token to register a new access key to an admin account".to_string(),
|
description: "Create a new reset token to register a new access key to an admin account",
|
||||||
arguments: vec!["email".to_string()],
|
arguments: vec!["email"],
|
||||||
function: Box::new(create_admin_reset_token),
|
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!("Usage: {} [conf-file] [action] [args...]", std::env::args().next().unwrap());
|
||||||
println!("Available actions:");
|
println!("Available actions:");
|
||||||
for action in get_actions() {
|
for action in get_actions() {
|
||||||
println!("\t{}\t{} - {}",
|
println!("\t{} {}\t- {}",
|
||||||
action.name,
|
action.name,
|
||||||
action.arguments.iter().map(|s| format!("[{}]", s)).collect::<Vec<String>>().join(" "),
|
action.arguments.iter().map(|s| format!("[{}]", s)).collect::<Vec<String>>().join(" "),
|
||||||
action.description
|
action.description
|
||||||
@ -194,3 +211,31 @@ fn create_admin_reset_token(args: Vec<String>) -> Res {
|
|||||||
|
|
||||||
Ok(())
|
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