1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-26 07:19:22 +00:00

Can create new admin accounts from command line

This commit is contained in:
Pierre HUBERT 2021-05-08 19:17:33 +02:00
parent d84b7051fb
commit c0489613fb
7 changed files with 170 additions and 4 deletions

View File

@ -60,6 +60,10 @@ pub mod database_tables_names {
/// Forez presence table /// Forez presence table
pub const FOREZ_PRESENCE_TABLE: &str = "forez_presence"; pub const FOREZ_PRESENCE_TABLE: &str = "forez_presence";
/// Administrators tables
pub const ADMIN_LIST_TABLE: &str = "comunic_admin";
pub const ADMIN_KEYS_TABLE: &str = "comunic_admin_key";
} }
/// Push Notifications Database prefix /// Push Notifications Database prefix
@ -153,6 +157,12 @@ pub const PASSWORD_RESET_TOKEN_LENGTH: usize = 255;
/// Duration of the validity of a password reset token (6 hours) /// Duration of the validity of a password reset token (6 hours)
pub const PASSWORD_RESET_TOKEN_LIFETIME: u64 = 60 * 60 * 6; pub const PASSWORD_RESET_TOKEN_LIFETIME: u64 = 60 * 60 * 6;
/// Length of admin reset tokens
pub const ADMIN_RESET_TOKEN_LENGTH: usize = 255;
/// Duration of the validity of a password reset token (1 hour)
pub const ADMIN_RESET_TOKEN_LIFETIME: u64 = 60 * 60;
/// Minimum password length /// Minimum password length
pub const PASSWORD_MIN_LENGTH: usize = 3; pub const PASSWORD_MIN_LENGTH: usize = 3;

41
src/data/admin.rs Normal file
View File

@ -0,0 +1,41 @@
//! # Comunic administrator
//!
//! @author Pierre Hubert
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct AdminID(u64);
impl AdminID {
pub fn new(id: u64) -> Self {
Self(id)
}
pub fn id(&self) -> u64 {
self.0
}
}
pub struct NewAdmin {
pub name: String,
pub email: String,
}
pub struct AdminResetToken {
pub token: String,
pub expire: u64,
}
pub struct Admin {
pub id: AdminID,
pub time_create: u64,
pub name: String,
pub email: String,
pub reset_token: Option<AdminResetToken>,
}
pub struct AdminKey {
pub id: u64,
pub admin_id: AdminID,
pub name: String,
pub key: String,
}

View File

@ -40,4 +40,5 @@ pub mod user_ws_connection;
pub mod call_signal; pub mod call_signal;
pub mod new_notifications_settings; pub mod new_notifications_settings;
pub mod push_notification; pub mod push_notification;
pub mod presence; pub mod presence;
pub mod admin;

View File

@ -0,0 +1,73 @@
//! # Administration accounts helper
//!
//! @author Pierre Hubert
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};
use crate::data::error::{ExecError, Res};
use crate::helpers::database;
use crate::utils::crypt_utils::rand_str;
use crate::utils::date_utils::time;
/// Create a new admin account
pub fn create(new_admin: &NewAdmin) -> Res<AdminID> {
if find_admin_by_email(&new_admin.email).is_ok() {
return Err(ExecError::boxed_new("An other admin account already holds the same email address!"));
}
database::InsertQuery::new(ADMIN_LIST_TABLE)
.add_u64("time_create", time())
.add_str("name", &new_admin.name)
.add_str("email", &new_admin.email)
.insert_expect_result()
.map(|i| AdminID::new(i))
}
/// Get admin information by admin email address
pub fn find_admin_by_email(email: &str) -> Res<Admin> {
database::QueryInfo::new(ADMIN_LIST_TABLE)
.cond("email", email)
.query_row(db_to_admin)
}
/// Create a new reset token for an admin
pub fn create_new_reset_token(id: AdminID) -> Res<AdminResetToken> {
let token = AdminResetToken {
token: rand_str(ADMIN_RESET_TOKEN_LENGTH),
expire: time() + ADMIN_RESET_TOKEN_LIFETIME,
};
database::UpdateInfo::new(ADMIN_LIST_TABLE)
.cond_admin_id("id", id)
.set_str("reset_token", &token.token)
.set_u64("reset_token_expire", token.expire)
.exec()?;
Ok(token)
}
/// Turn a database entry into an admin structure
fn db_to_admin(row: &database::RowResult) -> Res<Admin> {
let reset_token_expire = row.get_optional_u64("reset_token_expire")?
.unwrap_or(0);
let reset_token = if reset_token_expire < time() {
None
} else {
Some(AdminResetToken {
token: row.get_str("reset_token")?,
expire: row.get_u64("reset_token_expire")?,
})
};
Ok(Admin {
id: row.get_admin_id("id")?,
time_create: row.get_u64("time_create")?,
name: row.get_str("name")?,
email: row.get_str("email")?,
reset_token,
})
}

View File

@ -8,6 +8,7 @@ use chrono::{TimeZone, Utc};
use mysql::{Binary, Pool, ResultSet, Value}; use mysql::{Binary, Pool, ResultSet, Value};
use mysql::prelude::Queryable; use mysql::prelude::Queryable;
use crate::data::admin::AdminID;
use crate::data::config::{conf, DatabaseConfig}; use crate::data::config::{conf, DatabaseConfig};
use crate::data::conversation::ConvID; use crate::data::conversation::ConvID;
use crate::data::error::{ExecError, ResultBoxError}; use crate::data::error::{ExecError, ResultBoxError};
@ -376,6 +377,11 @@ impl<'a> RowResult<'a> {
Ok(UserID::new(self.get_u64(name)?)) Ok(UserID::new(self.get_u64(name)?))
} }
/// Get the ID of an admin included in the request
pub fn get_admin_id(&self, name: &str) -> ResultBoxError<AdminID> {
Ok(AdminID::new(self.get_u64(name)?))
}
/// Get the ID of a group included in the response /// Get the ID of a group included in the response
pub fn get_group_id(&self, name: &str) -> ResultBoxError<GroupID> { pub fn get_group_id(&self, name: &str) -> ResultBoxError<GroupID> {
Ok(GroupID::new(self.get_u64(name)?)) Ok(GroupID::new(self.get_u64(name)?))
@ -903,6 +909,12 @@ impl UpdateInfo {
self self
} }
/// Filter with an admin id
pub fn cond_admin_id(mut self, name: &str, val: AdminID) -> Self {
self.cond.insert(name.to_string(), Value::UInt(val.id()));
self
}
/// Filter with a group id /// Filter with a group id
pub fn cond_group_id(mut self, name: &str, val: &GroupID) -> UpdateInfo { pub fn cond_group_id(mut self, name: &str, val: &GroupID) -> UpdateInfo {
self.cond.insert(name.to_string(), Value::UInt(val.id())); self.cond.insert(name.to_string(), Value::UInt(val.id()));

View File

@ -21,4 +21,5 @@ pub mod calls_helper;
pub mod push_notifications_helper; pub mod push_notifications_helper;
pub mod independent_push_notifications_service_helper; pub mod independent_push_notifications_service_helper;
pub mod firebase_notifications_helper; pub mod firebase_notifications_helper;
pub mod forez_presence_helper; pub mod forez_presence_helper;
pub mod admin_account_helper;

View File

@ -1,8 +1,9 @@
use comunic_server::{cleanup_thread, server}; use comunic_server::{cleanup_thread, server};
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, database}; use comunic_server::helpers::{account_helper, admin_account_helper, database};
use comunic_server::utils::date_utils::current_year; use comunic_server::utils::date_utils::current_year;
type MainActionFunction = Res; type MainActionFunction = Res;
@ -38,7 +39,15 @@ fn get_actions() -> Vec<Action> {
description: "Create a password reset URL for a user".to_string(), description: "Create a password reset URL for a user".to_string(),
arguments: vec!["user_id".to_string()], arguments: vec!["user_id".to_string()],
function: Box::new(reset_password), 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()],
function: Box::new(create_admin),
},
] ]
} }
@ -142,5 +151,24 @@ fn reset_password(args: Vec<String>) -> Res {
println!("{}", conf().password_reset_url.replace("{TOKEN}", &token)); println!("{}", conf().password_reset_url.replace("{TOKEN}", &token));
Ok(())
}
fn create_admin(args: Vec<String>) -> Res {
let new_admin = NewAdmin {
name: args[0].to_string(),
email: args[1].to_string(),
};
if !mailchecker::is_valid(&new_admin.email) {
eprintln!("Specified email address is not valid!");
std::process::exit(-1);
}
let id = admin_account_helper::create(&new_admin)
.expect("Failed to create account!");
println!("* New admin ID: {}", id.id());
Ok(()) Ok(())
} }