diff --git a/src/service/acl/data.rs b/src/service/acl/data.rs index 30fd5442..984eddd4 100644 --- a/src/service/acl/data.rs +++ b/src/service/acl/data.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use clap::ValueEnum; use serde::{Serialize, Deserialize}; use url::Host; @@ -17,11 +18,20 @@ pub trait Data: Send + Sync { fn get_all_acls(&self) -> HashSet; } -#[derive(Serialize,Deserialize, Debug, Clone, Copy, Hash, Eq, PartialEq)] +#[derive(Serialize,Deserialize, Debug, Clone, Copy, Hash, Eq, PartialEq, ValueEnum)] pub enum AclMode{ Block, Allow } + +impl AclMode { + pub fn to_emoji(&self)-> char { + match self { + AclMode::Block => '❎', + AclMode::Allow => '✅', + } + } +} #[derive(Serialize,Deserialize, Debug, Clone, Hash, Eq,PartialEq)] pub struct AclDatabaseEntry { diff --git a/src/service/acl/mod.rs b/src/service/acl/mod.rs index 4178181c..738131c7 100644 --- a/src/service/acl/mod.rs +++ b/src/service/acl/mod.rs @@ -1,6 +1,6 @@ -use std::{sync::Arc, collections::HashSet}; +use std::sync::Arc; use ruma::ServerName; use tracing::{warn, debug, error}; diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index fb905fd1..92ec7f09 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -30,6 +30,8 @@ use ruma::{ }; use serde_json::value::to_raw_value; use tokio::sync::{mpsc, Mutex}; +use tracing::{warn, error}; +use url::Host; use crate::{ api::client_server::{leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH}, @@ -38,7 +40,7 @@ use crate::{ Error, PduEvent, Result, }; -use super::pdu::PduBuilder; +use super::{pdu::PduBuilder, acl::AclMode}; const PAGE_SIZE: usize = 100; @@ -72,6 +74,23 @@ enum AdminCommand { // this is more like a "miscellaneous" category than a debug one /// Commands for debugging things Debug(DebugCommand), + /// commands for manging ACL + #[command(subcommand)] + Acl(AclCommand), +} +#[cfg_attr(test, derive(Debug))] +#[derive(Subcommand)] +enum AclCommand { + Add { + mode: AclMode, + hostname: String + }, + Remove { + hostname: String + }, + List{ + filter: Option + } } #[cfg_attr(test, derive(Debug))] @@ -1257,6 +1276,45 @@ impl Service { ) } }, + AdminCommand::Acl(AclCommand::Add { mode, hostname }) => { + let host = match Host::parse(&hostname) { + Ok(host) => host, + Err(error) => return Ok(RoomMessageEventContent::text_plain(format!("failed to parse hostname with error {}",error))), + }; + if let Err(error) = services().acl.add_acl(host.clone(), mode) { + error!("encountered {} while trying to add acl with host {} and mode {:?}",error,host,mode); + RoomMessageEventContent::text_plain("error, couldn't add acl") + } else { + RoomMessageEventContent::text_plain("successfully added ACL") + } + + }, + AdminCommand::Acl(AclCommand::Remove { hostname }) => { + let host = match Host::parse(&hostname) { + Ok(host) => host, + Err(error) => return Ok(RoomMessageEventContent::text_plain(format!("failed to parse hostname with error {}",error))), + }; + + if let Err(error) = services().acl.remove_acl(host.clone()) { + error!("encountered {} while trying to remove acl with host {}",error,host); + RoomMessageEventContent::text_plain("error, couldn't remove acl") + } else { + RoomMessageEventContent::text_plain("successfully removed ACL") + } + }, + AdminCommand::Acl(AclCommand::List { filter}) => { + let results = services().acl.list_acls(filter); + let mut results_html = String::new(); + results.iter().for_each(|it| { + results_html.push_str(&format!("* {} | {}\n",it.hostname,it.mode.to_emoji())); + }); + RoomMessageEventContent::text_plain(format!(" + List of services: \n + ❎ = blocked\n + ✅ = allowed\n + {} + ",results_html)) + }, }; Ok(reply_message_content)