mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 09:34:04 +00:00 
			
		
		
		
	Start to log administrator actions
This commit is contained in:
		@@ -296,3 +296,11 @@ CREATE TABLE `comunic_admin_roles` (
 | 
			
		||||
  `role_id` VARCHAR(25) NULL,
 | 
			
		||||
  `time_insert` INT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `comunic_admin_log` (
 | 
			
		||||
  `id` INT NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `admin_id` INT NULL,
 | 
			
		||||
  `ip` VARCHAR(40) NULL,
 | 
			
		||||
  `time` INT NULL,
 | 
			
		||||
  `action` VARCHAR(100) NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 
 | 
			
		||||
@@ -22,3 +22,11 @@ CREATE TABLE `comunic_admin_roles` (
 | 
			
		||||
  `role_id` VARCHAR(25) NULL,
 | 
			
		||||
  `time_insert` INT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 | 
			
		||||
CREATE TABLE `comunic_admin_log` (
 | 
			
		||||
  `id` INT NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `admin_id` INT NULL,
 | 
			
		||||
  `ip` VARCHAR(40) NULL,
 | 
			
		||||
  `time` INT NULL,
 | 
			
		||||
  `action` VARCHAR(100) NULL,
 | 
			
		||||
  PRIMARY KEY (`id`));
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@ pub mod database_tables_names {
 | 
			
		||||
    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";
 | 
			
		||||
    pub const ADMIN_LOGS_TABLE: &str = "comunic_admin_log";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Push Notifications Database prefix
 | 
			
		||||
 
 | 
			
		||||
@@ -9,20 +9,26 @@ use crate::api_data::admin::admin_id_api::AdminIDAPI;
 | 
			
		||||
use crate::api_data::admin::admin_info_api::AdminInfoAPI;
 | 
			
		||||
use crate::api_data::admin::admin_res_create_account::AdminResCreateAccount;
 | 
			
		||||
use crate::api_data::admin::admin_res_create_reset_token::AdminResCreateResetToken;
 | 
			
		||||
use crate::constants::admin::AdminRole;
 | 
			
		||||
use crate::data::admin::{NewAdmin, NewAdminGeneralSettings};
 | 
			
		||||
use crate::data::admin_action_log::AdminAction;
 | 
			
		||||
use crate::data::base_request_handler::BaseRequestHandler;
 | 
			
		||||
use crate::data::http_request_handler::HttpRequestHandler;
 | 
			
		||||
use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_account_key_helper};
 | 
			
		||||
use crate::helpers::admin_log_helper::log_admin_action;
 | 
			
		||||
use crate::routes::RequestResult;
 | 
			
		||||
use crate::utils::date_utils::time;
 | 
			
		||||
use crate::constants::admin::AdminRole;
 | 
			
		||||
 | 
			
		||||
/// Create a new administrator account
 | 
			
		||||
pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
    let email = r.post_email("mail")?;
 | 
			
		||||
    let name = r.post_string_opt("name", 3, true)?;
 | 
			
		||||
 | 
			
		||||
    let admin_id = admin_account_helper::create(&NewAdmin { name, email })?;
 | 
			
		||||
    let new_admin = NewAdmin { name, email };
 | 
			
		||||
    let admin_id = admin_account_helper::create(&new_admin)?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::CreatedAdmin { id: admin_id, name: new_admin.name, email: new_admin.email })?;
 | 
			
		||||
 | 
			
		||||
    r.set_response(AdminResCreateAccount::new(admin_id))
 | 
			
		||||
}
 | 
			
		||||
@@ -52,6 +58,9 @@ pub fn auth_with_reset_token(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    let token = admin_access_token_helper::create(admin.id)?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(admin.id, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::AuthWithResetToken)?;
 | 
			
		||||
 | 
			
		||||
    r.set_response(AdminAuthSuccess::new(token))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -102,10 +111,13 @@ pub fn update_general_settings(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    admin_account_helper::set_general_settings(NewAdminGeneralSettings {
 | 
			
		||||
        id: admin_id,
 | 
			
		||||
        name: new_name,
 | 
			
		||||
        email: new_email,
 | 
			
		||||
        name: new_name.to_string(),
 | 
			
		||||
        email: new_email.to_string(),
 | 
			
		||||
    })?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::UpdatedAdminGeneralSettings { target: admin_id, new_name, new_email })?;
 | 
			
		||||
 | 
			
		||||
    r.ok()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -119,5 +131,8 @@ pub fn generate_reset_token(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    let token = admin_account_helper::create_new_reset_token(admin_id)?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::GeneratedAdminResetToken { target: admin_id })?;
 | 
			
		||||
 | 
			
		||||
    r.set_response(AdminResCreateResetToken::new(token))
 | 
			
		||||
}
 | 
			
		||||
@@ -4,15 +4,17 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use crate::api_data::admin::admin_auth_success::AdminAuthSuccess;
 | 
			
		||||
use crate::api_data::admin::admin_keys_api::AdminKeyAPI;
 | 
			
		||||
use crate::constants::admin::AdminRole;
 | 
			
		||||
use crate::data::admin::AdminKey;
 | 
			
		||||
use crate::data::admin_action_log::AdminAction;
 | 
			
		||||
use crate::data::base_request_handler::BaseRequestHandler;
 | 
			
		||||
use crate::data::error::Res;
 | 
			
		||||
use crate::data::http_request_handler::HttpRequestHandler;
 | 
			
		||||
use crate::data::webauthn_config::get_wan;
 | 
			
		||||
use crate::helpers::{admin_access_token_helper, admin_account_helper, admin_account_key_helper, admin_key_authentication_challenges_helper, admin_key_registration_challenges_helper};
 | 
			
		||||
use crate::helpers::admin_log_helper::log_admin_action;
 | 
			
		||||
use crate::routes::RequestResult;
 | 
			
		||||
use crate::api_data::admin::admin_keys_api::AdminKeyAPI;
 | 
			
		||||
use crate::constants::admin::AdminRole;
 | 
			
		||||
 | 
			
		||||
impl HttpRequestHandler {
 | 
			
		||||
    pub fn post_admin_auth_key(&mut self, name_mail: &str, name_key_id: &str) -> Res<AdminKey> {
 | 
			
		||||
@@ -73,6 +75,9 @@ pub fn register_key(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    admin_account_key_helper::add_key(r.admin_id()?, &name, key)?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::RegisteredAdminKey { name, target: r.admin_id()? })?;
 | 
			
		||||
 | 
			
		||||
    r.ok()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -87,6 +92,9 @@ pub fn delete_auth_key(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    for key in admin_account_key_helper::get_admin_keys(admin_id)? {
 | 
			
		||||
        if key.id == key_id {
 | 
			
		||||
            log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                             AdminAction::DeletedAdminKey { name: key.name.to_string(), target: admin_id })?;
 | 
			
		||||
 | 
			
		||||
            admin_account_key_helper::delete_key(key)?;
 | 
			
		||||
 | 
			
		||||
            return r.ok();
 | 
			
		||||
@@ -125,5 +133,8 @@ pub fn auth_with_key(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
    // Generate access token
 | 
			
		||||
    let token = admin_access_token_helper::create(key.admin_id)?;
 | 
			
		||||
 | 
			
		||||
    log_admin_action(key.admin_id, &r.remote_ip(),
 | 
			
		||||
                     AdminAction::AuthWithAccessKey { key: key.name, key_id: key.id })?;
 | 
			
		||||
 | 
			
		||||
    r.set_response(AdminAuthSuccess::new(token))
 | 
			
		||||
}
 | 
			
		||||
@@ -4,8 +4,10 @@
 | 
			
		||||
 | 
			
		||||
use crate::api_data::admin::admin_role_api::AdminRoleDetailsAPI;
 | 
			
		||||
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
 | 
			
		||||
use crate::data::admin_action_log::AdminAction;
 | 
			
		||||
use crate::data::base_request_handler::BaseRequestHandler;
 | 
			
		||||
use crate::data::http_request_handler::HttpRequestHandler;
 | 
			
		||||
use crate::helpers::admin_log_helper::log_admin_action;
 | 
			
		||||
use crate::helpers::admin_roles_helper;
 | 
			
		||||
use crate::routes::RequestResult;
 | 
			
		||||
 | 
			
		||||
@@ -30,8 +32,13 @@ pub fn toggle(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    if !enable {
 | 
			
		||||
        admin_roles_helper::remove_role(admin_id, role)?;
 | 
			
		||||
        log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                         AdminAction::RemoveAdminRole { target: admin_id, role: role_str })?;
 | 
			
		||||
    } else if !admin_roles_helper::has_role(admin_id, role)? {
 | 
			
		||||
        admin_roles_helper::add_role(admin_id, role)?;
 | 
			
		||||
 | 
			
		||||
        log_admin_action(r.admin_id()?, &r.remote_ip(),
 | 
			
		||||
                         AdminAction::AddAdminRole { target: admin_id, role: role_str })?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r.ok()
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,12 @@
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use mysql::serde::{Deserializer, Serializer};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use webauthn_rs::proto::Credential;
 | 
			
		||||
 | 
			
		||||
use crate::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
 | 
			
		||||
use crate::data::u64_visitor::U64Visitor;
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
 | 
			
		||||
pub struct AdminID(u64);
 | 
			
		||||
@@ -83,3 +86,17 @@ impl AdminRole {
 | 
			
		||||
            .expect("Should have found a role!!!")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Serialize for AdminID {
 | 
			
		||||
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
 | 
			
		||||
        S: Serializer {
 | 
			
		||||
        serializer.serialize_u64(self.0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'de> Deserialize<'de> for AdminID {
 | 
			
		||||
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> where
 | 
			
		||||
        D: Deserializer<'de> {
 | 
			
		||||
        deserializer.deserialize_u64(U64Visitor {}).map(|id| AdminID::new(id))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/data/admin_action_log.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/data/admin_action_log.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
//! # Admin action log
 | 
			
		||||
 | 
			
		||||
use crate::data::admin::AdminID;
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub enum AdminAction {
 | 
			
		||||
    AuthWithResetToken,
 | 
			
		||||
    AuthWithAccessKey { key: String, key_id: u64 },
 | 
			
		||||
    RegisteredAdminKey { name: String, target: AdminID },
 | 
			
		||||
    DeletedAdminKey { name: String, target: AdminID },
 | 
			
		||||
    GeneratedAdminResetToken { target: AdminID },
 | 
			
		||||
    CreatedAdmin { id: AdminID, name: String, email: String },
 | 
			
		||||
    UpdatedAdminGeneralSettings { target: AdminID, new_email: String, new_name: String },
 | 
			
		||||
    AddAdminRole { target: AdminID, role: String },
 | 
			
		||||
    RemoveAdminRole { target: AdminID, role: String },
 | 
			
		||||
    UnsupportedAction,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct AdminActionLog {
 | 
			
		||||
    pub id: u64,
 | 
			
		||||
    pub admin_id: AdminID,
 | 
			
		||||
    pub ip: String,
 | 
			
		||||
    pub time: u64,
 | 
			
		||||
    pub action: AdminAction,
 | 
			
		||||
}
 | 
			
		||||
@@ -43,3 +43,5 @@ pub mod push_notification;
 | 
			
		||||
pub mod presence;
 | 
			
		||||
pub mod admin;
 | 
			
		||||
pub mod webauthn_config;
 | 
			
		||||
pub mod admin_action_log;
 | 
			
		||||
pub mod u64_visitor;
 | 
			
		||||
							
								
								
									
										20
									
								
								src/data/u64_visitor.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/data/u64_visitor.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::fmt::Formatter;
 | 
			
		||||
 | 
			
		||||
use mysql::serde::de::Error;
 | 
			
		||||
use serde::de::Visitor;
 | 
			
		||||
 | 
			
		||||
pub struct U64Visitor;
 | 
			
		||||
 | 
			
		||||
impl<'de> Visitor<'de> for U64Visitor {
 | 
			
		||||
    type Value = u64;
 | 
			
		||||
 | 
			
		||||
    fn expecting<'a>(&self, formatter: &mut Formatter<'a>) -> fmt::Result {
 | 
			
		||||
        formatter.write_str("An unsigned integer value")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where
 | 
			
		||||
        E: Error, {
 | 
			
		||||
        Ok(v)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/helpers/admin_log_helper.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/helpers/admin_log_helper.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
//! # Admin logs management
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use crate::constants::database_tables_names::ADMIN_LOGS_TABLE;
 | 
			
		||||
use crate::data::admin::AdminID;
 | 
			
		||||
use crate::data::admin_action_log::AdminAction;
 | 
			
		||||
use crate::data::error::Res;
 | 
			
		||||
use crate::helpers::database;
 | 
			
		||||
use crate::utils::date_utils::time;
 | 
			
		||||
 | 
			
		||||
/// Record an administrator action
 | 
			
		||||
pub fn log_admin_action(admin: AdminID, ip: &str, action: AdminAction) -> Res {
 | 
			
		||||
    database::InsertQuery::new(ADMIN_LOGS_TABLE)
 | 
			
		||||
        .add_admin_id("admin_id", admin)
 | 
			
		||||
        .add_str("ip", ip)
 | 
			
		||||
        .add_u64("time", time())
 | 
			
		||||
        .add_str("action", &serde_json::to_string(&action)?)
 | 
			
		||||
        .insert_drop_result()
 | 
			
		||||
}
 | 
			
		||||
@@ -28,3 +28,4 @@ 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;
 | 
			
		||||
pub mod admin_log_helper;
 | 
			
		||||
		Reference in New Issue
	
	Block a user