diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs index 0ec8541..37ce4db 100644 --- a/src/core/botinstance.rs +++ b/src/core/botinstance.rs @@ -22,7 +22,7 @@ use crate::core::ratelimiter; use crate::core::botmodules; use crate::core::botmodules::ModulesManager; -use crate::core::identity::IdentityManager; +use crate::core::identity::{IdentityManager,Permissible}; #[derive(Debug, PartialEq, Eq, Hash, Clone)] @@ -222,7 +222,7 @@ impl BotInstance while let Some(message) = self.incoming_messages.recv().await { // Below can be used to debug if I want to capture all messages - println!("Received message: {:?}", message); + // println!("Received message: {:?}", message); match message { ServerMessage::Notice(msg) => { @@ -271,7 +271,8 @@ impl BotInstance // PRIVATE FUNCTIONS - async fn listener_main_prvmsg(&mut self,msg:PrivmsgMessage) -> () { + // async fn listener_main_prvmsg(&mut self,msg:PrivmsgMessage) -> () { + async fn listener_main_prvmsg(&self,msg:PrivmsgMessage) -> () { // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); @@ -286,6 +287,11 @@ impl BotInstance /* BotCommand handling - - [x] Checks if the input message is a prefix with command name or alias + - [ ] Validate User can run based on identityModule(From_Bot)::can_user_run( + _usr:String, + _channelname:ChType, + _chat_badge:ChatBadge, + _cmdreqroles:Vec) */ let inpt = msg.message_text.split("\n").next().expect("ERROR during BotCommand"); @@ -293,20 +299,40 @@ impl BotInstance // [x] Check if a bot command based on ... // [x] prefix + command - let mut exec_bot_command = false; + let mut confirmed_bot_command = false; if inpt == self.prefix.to_string() + c.command.as_str() { - exec_bot_command = true; + confirmed_bot_command = true; } // [x] prefix + alias for alias in &c.alias { if inpt == self.prefix.to_string() + alias.as_str() { - exec_bot_command = true; + confirmed_bot_command = true; } } - if exec_bot_command { - c.execute(self.chat.clone(), msg.clone()).await; + if confirmed_bot_command { + + // self.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()); + + // [ ] Around here, validate if permissable before executing + // match self.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()) { + // Ok(Permissible::Allow) => c.execute(self.chat.clone(), msg.clone()).await, + // Ok(Permissible::Block) => println!("User Not allowed to run command"), + // _ => (), + // } + + match self.identity.to_owned().can_user_run_PRVMSG(&msg, c.required_roles.clone()) { + // Ok(Permissible::Allow) => (), + Permissible::Allow => { + println!("Executed as permissible"); + c.execute(self.chat.clone(), msg.clone()).await; + } + Permissible::Block => println!("User Not allowed to run command"), + // _ => (), + } + + // c.execute(self.chat.clone(), msg.clone()).await; } }, diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index ae50cb7..7be3673 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -34,7 +34,7 @@ pub enum ModType { pub use ModType::BotModule; -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum ChType { Channel(String), } diff --git a/src/core/identity.rs b/src/core/identity.rs index 797f058..3c02c88 100644 --- a/src/core/identity.rs +++ b/src/core/identity.rs @@ -6,7 +6,7 @@ use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait, use crate::core::botmodules::bot_actions::actions_util; use crate::core::botinstance::{self}; -use twitch_irc::message::PrivmsgMessage; +use twitch_irc::message::{Badge, PrivmsgMessage}; use crate::core::botmodules::ChType; @@ -29,7 +29,7 @@ pub fn init(mgr:&mut ModulesManager) async fn cmd_promote(mut _chat:botinstance::Chat,_msg:PrivmsgMessage) { //println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - + println!("Called cmd promote"); } @@ -44,13 +44,19 @@ pub fn init(mgr:&mut ModulesManager) async fn cmd_demote(mut _chat:botinstance::Chat,_msg:PrivmsgMessage) { - + println!("Called cmd demote"); } } +// #[derive(Debug, PartialEq, Eq, Hash, Clone)] +// pub enum ChType { +// Channel(String), +// } + +#[derive(Debug, PartialEq, Eq , Clone)] pub enum UserRole { Chatter, Mod(ChType), // String specifies Channel @@ -61,16 +67,17 @@ pub enum UserRole { } -enum Permissible { +pub enum Permissible { Allow, Block } +#[derive(Clone)] pub struct IdentityManager { - special_roles_users : HashMap>, + special_roles_users : HashMap>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel } -enum ChatBadge { +pub enum ChatBadge { Broadcaster, Mod, } @@ -89,19 +96,57 @@ impl IdentityManager { } } - pub fn canUserRun(self, + // [ ] Maybe I should create a can_user_run version that simply takes PrvMsg, but then calls can_user_run directly + + // pub fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Result> + pub fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Permissible + { + // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); + + // [ ] Check what Badges in PrivmsgMessage + + let mut sender_badge:Option = None; + + for b in &msg.badges { + if b.name == "moderator" { + sender_badge = Some(ChatBadge::Mod); + } else if b.name == "broadcaster" { + sender_badge = Some(ChatBadge::Broadcaster); + } + } + + // if &msg.badges.contains(Badge{}) { + + // } + + if let Some(sender_badge) = sender_badge { + return self.can_user_run(msg.sender.name.to_owned(), + ChType::Channel(msg.channel_login.to_owned()), + sender_badge, + cmdreqroles + ) ; + } + + + + // [ ] Call can_user_run() + Permissible::Block + } + + pub fn can_user_run(mut self, usr:String, channelname:ChType, - chatBadge:ChatBadge, + chat_badge:ChatBadge, cmdreqroles:Vec - ) -> Result> { + // ) -> Result> { + ) -> Permissible { /* canUserRun - Input : usr:String, channelname:ChType, - chatBadge:ChatBadge, + chat_badge:ChatBadge, cmdreqroles:Vec Output : Result> @@ -118,18 +163,125 @@ impl IdentityManager { // Requirements /* - [ ] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) - [ ] If chatBadge::Broadcaster ... - [ ] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow) - [ ] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow) - [ ] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) to determine if Ok(Permissible::Allow) - [ ] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) - [ ] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) - [ ] Otherwise, Ok(Permissible::Block) + [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) + [x] If chatBadge::Broadcaster ... + [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow) + [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow) + [x] If chatBadge::Mod ... + [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) + [x] If not, assign them UserRole::Mod(channelname::ChType) + [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) + [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) + [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) + [x] Otherwise, Ok(Permissible::Block) */ + // [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) - Ok(Permissible::Allow) + if cmdreqroles.len() == 0 { + // return Ok(Permissible::Allow) + return Permissible::Allow + } + + + + match chat_badge { + + // [x] If chatBadge::Broadcaster ... + // [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow) + // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow) + + ChatBadge::Broadcaster => { + if cmdreqroles.contains(&UserRole::Broadcaster) || + cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) || + cmdreqroles.contains(&UserRole::SupMod(ChType::Channel(String::new()))) { + // return Ok(Permissible::Allow) + return Permissible::Allow + } + }, + + // [x] If chatBadge::Mod ... + // [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) + // [x] If not, assign them UserRole::Mod(channelname::ChType) + + ChatBadge::Mod => { + + println!("Mod Chatbadge detected"); + + println!("debug special roles : {:?}",self.special_roles_users); + println!("debug usr : {}",&usr.to_lowercase()); + + // let Some((k,v)) = self.special_roles_users.get_key_value(usr); + match self.special_roles_users.get_mut(&usr.to_lowercase()) { + Some(usrroles) => { + println!("contains mod : {}", usrroles.contains(&UserRole::Mod(channelname.clone()))); + println!("contains supmod : {}", usrroles.contains(&UserRole::SupMod(channelname.clone()))); + if usrroles.contains(&UserRole::Mod(channelname.clone())) || + usrroles.contains(&UserRole::SupMod(channelname.clone())) { + // Do nothing - this is expected + } else { + // in this case, they have a ChatBadge::Mod but should have this for the channel + usrroles.push(UserRole::Mod(channelname.clone())); + println!("debug special roles : {:?}",self.special_roles_users); + } + }, + _ => () + } + + }, + // _ => (), + } + + // [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) + + println!("cmd required roles : {:?}",cmdreqroles); + + if cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) { + // match self.special_roles_users.get(&channelname) { + // Some(usrroles) => {}, + // None => (), + + // } + + println!("Mod Role required"); + + if let Some(a) = self.special_roles_users.get(&usr.to_lowercase()) { + if a.contains(&UserRole::Mod(channelname.clone())) || a.contains(&UserRole::SupMod(channelname.clone())){ + // return Ok(Permissible::Allow); + return Permissible::Allow + } + } + } + + + // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) + + + if cmdreqroles.contains(&UserRole::SupMod(ChType::Channel(String::new()))) { + if let Some(a) = self.special_roles_users.get(&usr.to_lowercase()) { + if a.contains(&UserRole::SupMod(channelname.clone())) { + // return Ok(Permissible::Allow); + return Permissible::Allow + } + } + } + + + // [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) + + println!("Eval cmdreqroles with botadmin : {}",cmdreqroles.contains(&UserRole::BotAdmin)); + + if cmdreqroles.contains(&UserRole::BotAdmin) { + println!("special roles get : {:?}",self.special_roles_users.get(&usr.to_lowercase())); + if let Some(a) = self.special_roles_users.get(&usr.to_lowercase()) { + println!("special roles contains BotAdmin: {}",a.contains(&UserRole::BotAdmin)); + if a.contains(&UserRole::BotAdmin) { + // return Ok(Permissible::Allow); + return Permissible::Allow + } + } + } + + Permissible::Block } } - diff --git a/src/modules/experiments.rs b/src/modules/experiments.rs index 79cd388..0078ea8 100644 --- a/src/modules/experiments.rs +++ b/src/modules/experiments.rs @@ -14,12 +14,14 @@ use std::future::Future; -use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait, BotCommand}; +use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait, BotCommand,ChType}; use crate::core::botmodules::bot_actions::actions_util; use crate::core::botinstance::{self}; use twitch_irc::message::PrivmsgMessage; +use crate::core::identity; + pub fn init(mgr:&mut ModulesManager) { @@ -30,7 +32,10 @@ pub fn init(mgr:&mut ModulesManager) alias : vec![String::from("tester1"),String::from("testy1")], // String of alternative names exec_body : actions_util::asyncbox(testy) , help : String::from("DUPCMD4 tester"), - required_roles : vec![], + required_roles : vec![ + //identity::UserRole::Mod(ChType::Channel(String::new())), + identity::UserRole::SupMod(ChType::Channel(String::new())) + ], }.add_to_modmgr(mgr); @@ -40,19 +45,21 @@ pub fn init(mgr:&mut ModulesManager) alias : vec![String::from("tester2"),String::from("testy2")], // String of alternative names exec_body : actions_util::asyncbox(testy) , help : String::from("DUPCMD4 tester"), - required_roles : vec![], + required_roles : vec![ + identity::UserRole::BotAdmin + ], }.add_to_modmgr(mgr); - let list1 = Listener { - module : BotModule(String::from("experiments 004")), - name : String::from("GoodGirl Listener"), - exec_body : actions_util::asyncbox(good_girl) , - help : String::from("") - }; + // let list1 = Listener { + // module : BotModule(String::from("experiments 004")), + // name : String::from("GoodGirl Listener"), + // exec_body : actions_util::asyncbox(good_girl) , + // help : String::from("") + // }; - list1.add_to_modmgr(mgr); + // list1.add_to_modmgr(mgr); }