diff --git a/Cargo.toml b/Cargo.toml index 2673b98..d37015a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "MSDB" +name = "msdb" version = "0.1.0" edition = "2021" diff --git a/config.toml b/config.toml index 59585e1..8edbf8d 100644 --- a/config.toml +++ b/config.toml @@ -1,9 +1,12 @@ +[discord_settings] + # Discord bot token discord_token = "" # Ip of the mindustry server ip = "localhost" + # Port of the mindustry server socket # Run 'config socketInputPort' in the mindustry console to find this port port = "6859" @@ -12,11 +15,26 @@ port = "6859" # Can be any word letter or symbol prefix = ";" -# These are the roles needed in order to use the associated command -# If an invalid role is used it will be ignored. If all the roles are invalid or the list is empty then anyone can use the command -[roles] -# Auth command -auth = [""] -# console command -cons = ["738543444322156574", "822523680391037009"] +# These are the role ids needed in order to use the console command +# If an invalid role is used it will be ignored +# If all the roles are invalid or the list is empty the setting will be ignored +[admin_roles] + +# people with roles ids in the owner setting can use all console commands +# if left empty anyone can use any of the commands +owners = ["738543444322156574", "822523680391037009"] + +# list of admin roles +admins = [] + +# this controls which commands admins have access too +[console] + +# whether the command list is a whitelist or a blacklist +# true = whitelist +# false = blacklist +commands_whitelist = true + +# which commands are whitelisted/blacklisted to admins +commands = ["config"] diff --git a/src/main.rs b/src/main.rs index 3cc5772..31f9143 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,15 @@ -mod mindus; +pub mod mindus; +pub mod structs; +use crate::structs::*; use crate::mindus::*; use serenity::async_trait; -use serenity::model::prelude::{UserId, RoleId}; +use serenity::model::prelude::{UserId}; use serenity::prelude::*; use serenity::model::channel::Message; use serenity::framework::standard::macros::{command, group, help, hook}; use serenity::framework::standard::{StandardFramework, CommandResult, Args, HelpOptions, CommandGroup, help_commands}; use serenity::utils::Color; use std::collections::HashSet; -use std::str::FromStr; #[group] #[commands(ping, pong, console, git, discord, auth)] @@ -50,18 +51,18 @@ async fn main() { let conf = init_conf().await; - let sock = TcpSock::new(conf.ip.clone(), conf.port.clone()).unwrap(); + let sock = TcpSock::new(conf.discord_settings.ip.clone(), conf.discord_settings.port.clone()).unwrap(); let framework = StandardFramework::new() .configure(|c| c - .prefix(conf.prefix.clone()) + .prefix(conf.discord_settings.prefix.clone()) .case_insensitivity(true)) .unrecognised_command(unknown_command) .help(&MY_HELP) .group(&COMMANDS_GROUP); let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT; - let mut client = Client::builder(&conf.discord_token, intents) + let mut client = Client::builder(&conf.discord_settings.discord_token, intents) .event_handler(Handler) .framework(framework) .await @@ -103,25 +104,44 @@ async fn pong(ctx: &Context, msg: &Message) -> CommandResult { #[description("Send a command to the mindustry server console")] #[example("status")] #[min_args(1)] -async fn console(ctx: &Context, msg: &Message, args: Args) -> CommandResult { + +async fn console(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { let data = ctx.data.read().await; let sock = data.get::().unwrap(); let conf = data.get::().unwrap(); - - if !check_role(ctx, msg, &conf.roles.cons).await.unwrap_or_else(|_e| true) { - msg.channel_id.send_message(ctx, |m| { - m.content("") - .embed(|e| e - .title("No Permissions") - .description("You do not have permission to use this command") - .color(Color::RED)) - }).await?; - return Ok(()); + if !check_role(ctx, msg, &conf.admin_roles.owners).await.unwrap() { + + if check_role(ctx, msg, &conf.admin_roles.admins).await.unwrap() { + + let on_list = is_command(args.single::().unwrap(), &conf.console.commands); + + if !((on_list && conf.console.commands_whitelist) || (!on_list && !conf.console.commands_whitelist)) { + msg.channel_id.send_message(ctx, |m| { + m.content("") + .embed(|e| e + .title("No Permissions") + .description("You do not have permission to use this command") + .color(Color::RED)) + }).await.unwrap(); + return Ok(()); + } + } else { + msg.channel_id.send_message(ctx, |m| { + m.content("") + .embed(|e| e + .title("No Permissions") + .description("You do not have permission to use this command") + .color(Color::RED)) + }).await.unwrap(); + return Ok(()); + } } + + msg.channel_id.send_message(ctx, |m| { m.content("") .embed(|e| e @@ -143,20 +163,7 @@ async fn auth(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let data = ctx.data.read().await; let sock = data.get::().unwrap(); - let conf = data.get::().unwrap(); - - if !check_role(ctx, msg, &conf.roles.auth).await.unwrap_or_else(|_e| true) { - msg.channel_id.send_message(ctx, |m| { - m.content("") - .embed(|e| e - .title("No Permissions") - .description("You do not have permission to use this command") - .color(Color::RED)) - }).await?; - return Ok(()); - } - msg.channel_id.send_message(ctx, |m| { m.content("") .embed(|e| e @@ -179,28 +186,3 @@ async fn discord(ctx: &Context, msg: &Message) -> CommandResult { msg.reply(ctx, "https://discord.gg/sRKCKQAdU4").await?; Ok(()) } - -async fn check_role(ctx: &Context, msg: &Message, roles: &Vec) -> Result { - let mut invalid_roles = 0; - for v_id in roles { - let u_id = match u64::from_str(&v_id) { - Ok(n) => n, - Err(_e) => - { - invalid_roles += 1; - continue - }, - }; - - let check = msg.author.has_role(ctx, msg.guild_id.unwrap(), RoleId::from(u_id)).await?; - if check { - return Ok(check) - } - } - - if invalid_roles == roles.len() { - return Ok(true) - } - - Ok(false) -} \ No newline at end of file diff --git a/src/mindus.rs b/src/mindus.rs index dd013cc..9b3e4f0 100644 --- a/src/mindus.rs +++ b/src/mindus.rs @@ -1,48 +1,14 @@ +use crate::structs::*; +use std::str::FromStr; use std::fs::{File, OpenOptions}; use std::io::{Read, Write, Seek, BufRead}; -use std::time::Duration; -use std::net::TcpStream; -use serenity::prelude::TypeMapKey; -use std::str; +use serenity::model::prelude::{Message, RoleId}; +use serenity::prelude::{Context}; +use std::{str}; +use serenity::prelude::SerenityError; use indoc::indoc; -pub struct TcpSock { - pub stream: TcpStream, -} -impl TcpSock { - pub fn new(ip: String, port: String) -> std::io::Result { - let stream = TcpStream::connect(format!("{}:{}", ip, port)).expect("Tcp connection fail"); - stream.set_read_timeout(Some(Duration::from_millis(25)))?; - println!("Socket Connected!!"); - Ok(TcpSock { stream }) - } -} - -impl TypeMapKey for TcpSock { - type Value = TcpSock; -} - - -#[derive(serde::Deserialize, serde::Serialize)] -pub struct Config { - pub discord_token: String, - pub ip: String, - pub port: String, - pub prefix: String, - pub roles: Roles -} - - -#[derive(serde::Deserialize, serde::Serialize)] -pub struct Roles { - pub auth: Vec, - pub cons: Vec -} - -impl TypeMapKey for Config { - type Value = Config; -} pub fn cons_rw(sock: &TcpSock, input: &str) -> String { @@ -60,6 +26,7 @@ pub fn cons_rw(sock: &TcpSock, input: &str) -> String { Err(_) => break(), }; } + output = String::from_utf8(strip_ansi_escapes::strip(&output).unwrap()).unwrap(); output.truncate(4000); output @@ -93,45 +60,88 @@ let mut toml_file = OpenOptions::new() .open("config.toml") .unwrap(); - let fill_conf = - indoc! {r#" - # Discord bot token - discord_token = "" - - # Ip of the mindustry server - ip = "localhost" - - # Port of the mindustry server socket - # Run 'config socketInputPort' in the mindustry console to find this port - port = "6859" - - # Prefix used to call commands - # Can be any word letter or symbol - prefix = ";" - - # These are the roles needed in order to use the associated command - # If an invalid role is used it will be ignored. If all the roles are invalid or the list is empty then anyone can use the command - [roles] - # Auth command - auth = [""] - - # console command - cons = ["738543444322156574", "822523680391037009"] - "#}; + let fill_conf = indoc! {r#" +[discord_settings] - // let fill_conf = Config { - // discord_token: String::from(""), - // ip: String::from("localhost"), - // port: String::from("6859"), - // prefix: String::from(";"), - // roles: Roles { - // auth: vec![String::from(""), String::from("")], - // cons: vec![String::from("")] - // } - // }; +# Discord bot token +discord_token = "" - toml_file.write(fill_conf.as_bytes()).expect("Unable to write to new file"); +# Ip of the mindustry server +ip = "localhost" + + +# Port of the mindustry server socket +# Run 'config socketInputPort' in the mindustry console to find this port +port = "6859" + +# Prefix used to call commands +# Can be any word letter or symbol +prefix = ";" + + +# These are the role ids needed in order to use the console command +# If an invalid role is used it will be ignored +# If all the roles are invalid or the list is empty the setting will be ignored +[admin_roles] + +# people with roles ids in the owner setting can use all console commands +# if left empty anyone can use any of the commands +owners = ["738543444322156574", "822523680391037009"] + +# list of admin roles +admins = [] + +# this controls which commands admins have access too +[console] + +# whether the command list is a whitelist or a blacklist +# true = whitelist +# false = blacklist +commands_whitelist = true + +# which commands are whitelisted/blacklisted to admins +commands = ["config"] +"#}; + + + toml_file.write(&fill_conf.as_bytes()).expect("Unable to write to new file"); toml_file.flush().unwrap(); toml_file.rewind().unwrap(); toml_file -} \ No newline at end of file +} + + +pub async fn check_role(ctx: &Context, msg: &Message, roles: &Vec) -> Result { + let mut invalid_roles = 0; + + for v_id in roles { + let u_id = match u64::from_str(&v_id) { + Ok(n) => n, + Err(_e) => + { + invalid_roles += 1; + continue + }, + }; + + let check = msg.author.has_role(ctx, msg.guild_id.unwrap(), RoleId::from(u_id)).await?; + if check { + return Ok(check); + } + } + + if invalid_roles == roles.len() { + return Ok(true) + } + + Ok(false) +} + +pub fn is_command(command: String, command_vec: &Vec) -> bool { + for r in command_vec { + if r == &command { + return true; + } + } + false +} diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 0000000..1c551c7 --- /dev/null +++ b/src/structs.rs @@ -0,0 +1,53 @@ +use std::time::Duration; +use std::net::TcpStream; +use serenity::prelude::{TypeMapKey}; +use std::{str}; + +pub struct TcpSock { + pub stream: TcpStream, +} + +impl TcpSock { + pub fn new(ip: String, port: String) -> std::io::Result { + let stream = TcpStream::connect(format!("{}:{}", ip, port)).expect("Tcp connection fail"); + stream.set_read_timeout(Some(Duration::from_millis(25)))?; + println!("Socket Connected!!"); + Ok(TcpSock { stream }) + } +} + +impl TypeMapKey for TcpSock { + type Value = TcpSock; +} + +#[derive(serde::Deserialize, serde::Serialize, Default)] +pub struct Config { + pub discord_settings: DiscordSettings, + pub admin_roles: PermissionRoles, + pub console: AdminConsole, +} + +#[derive(serde::Deserialize, serde::Serialize, Default)] +pub struct DiscordSettings { + pub discord_token: String, + pub ip: String, + pub port: String, + pub prefix: String, +} + +#[derive(serde::Deserialize, serde::Serialize, Default)] +pub struct PermissionRoles { + pub owners: Vec, + pub admins: Vec +} + +#[derive(serde::Deserialize, serde::Serialize, Default)] +pub struct AdminConsole { + pub commands_whitelist: bool, + pub commands: Vec, +} + + +impl TypeMapKey for Config { + type Value = Config; +} \ No newline at end of file