Browse Source

Added timed devoice and ban/timed unban response for spam response.

tags/3.1.0
Teknikode 4 years ago
parent
commit
6210e073c6
2 changed files with 288 additions and 79 deletions
  1. 53
    23
      Modules/Spam Control/Module.Default.json
  2. 235
    56
      Modules/Spam Control/Spam_Control.cs

+ 53
- 23
Modules/Spam Control/Module.Default.json View File

@@ -1,25 +1,55 @@
{
"Name": "Spam Control",
"ClassName": "Spam_Control",
"Enabled": true,
"ChannelBlacklist": [],
"NickBlacklist": [],
"Commands": [],
"Options": [
{
"Name": "Max Messages",
"Description": "The maximum number of messages allowed per time alotted.",
"Value": 5
},
{
"Name": "Max Highlights",
"Description": "The maximum number of highlights allowed in a set period of time.",
"Value": 5
},
{
"Name": "Time Threshold",
"Description": "The minimum time allowed for a set of messages in milliseconds.",
"Value": 5000
}
]
"Name": "Spam Control",
"ClassName": "Spam_Control",
"Enabled": true,
"ChannelBlacklist": [ ],
"NickBlacklist": [ ],
"Commands": [ ],
"Options": [
{
"Name": "Max Messages",
"Description": "The maximum number of messages allowed per time alotted.",
"Value": 5
},
{
"Name": "Max Highlights",
"Description": "The maximum number of highlights allowed in a set period of time.",
"Value": 5
},
{
"Name": "Time Threshold",
"Description": "The minimum time allowed for a set of messages in milliseconds.",
"Value": 5000
},
{
"Name": "Voice Response",
"Description": "Whether the nick should be devoiced on spam.",
"Value": true
},
{
"Name": "Kick Response",
"Description": "Whether the nick should be kicked on spam.",
"Value": true
},
{
"Name": "Ban Response",
"Description": "Whether the nick should be banned on spam.",
"Value": true
},
{
"Name": "Unban Response",
"Description": "Whether the nick should be unbanned after being banned.",
"Value": true
},
{
"Name": "Devoice Time",
"Description": "How long to be devoiced due to spam.",
"Value": 60
},
{
"Name": "Unban Time",
"Description": "How long to be banned due to spam.",
"Value": 60
}
]
}

+ 235
- 56
Modules/Spam Control/Spam_Control.cs View File

@@ -13,9 +13,17 @@ namespace Combot.Modules.Plugins
private List<SpamHighlightInfo> SpamHighlightList;
private ReaderWriterLockSlim SpamMessageLock;
private ReaderWriterLockSlim SpamHighlightLock;
private List<System.Timers.Timer> unbanTimers;
private ReaderWriterLockSlim unbanLock;
private List<System.Timers.Timer> devoiceTimers;
private ReaderWriterLockSlim devoiceLock;

public override void Initialize()
{
unbanTimers = new List<System.Timers.Timer>();
unbanLock = new ReaderWriterLockSlim();
devoiceTimers = new List<System.Timers.Timer>();
devoiceLock = new ReaderWriterLockSlim();
SpamMessageList = new List<SpamMessageInfo>();
SpamHighlightList = new List<SpamHighlightInfo>();
SpamMessageLock = new ReaderWriterLockSlim();
@@ -27,92 +35,263 @@ namespace Combot.Modules.Plugins
{
if (Enabled && !ChannelBlacklist.Contains(message.Channel) && !NickBlacklist.Contains(message.Sender.Nickname))
{
int timeThreshold = Convert.ToInt32(GetOptionValue("Time Threshold"));
int maxMessages = Convert.ToInt32(GetOptionValue("Max Messages"));
int maxHighlights = Convert.ToInt32(GetOptionValue("Max Highlights"));
// Check for line spam
if (SpamMessageList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
CheckFlood(message);
CheckHighlight(message);
}
}

private void CheckFlood(ChannelMessage message)
{
int timeThreshold = Convert.ToInt32(GetOptionValue("Time Threshold"));
int maxMessages = Convert.ToInt32(GetOptionValue("Max Messages"));
int devoiceTime = Convert.ToInt32(GetOptionValue("Devoice Time"));
int unbanTime = Convert.ToInt32(GetOptionValue("Unban Time"));
bool voiceResponse = Convert.ToBoolean(GetOptionValue("Voice Response"));
bool kickResponse = Convert.ToBoolean(GetOptionValue("Kick Response"));
bool banResponse = Convert.ToBoolean(GetOptionValue("Ban Response"));
bool unbanResponse = Convert.ToBoolean(GetOptionValue("Unban Response"));

// Check for line spam
if (SpamMessageList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
{
SpamMessageLock.EnterReadLock();
SpamMessageInfo info = SpamMessageList.Find(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname);
SpamMessageLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstMessageTime);
if (difference.TotalMilliseconds < timeThreshold)
{
SpamMessageLock.EnterReadLock();
SpamMessageInfo info = SpamMessageList.Find(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname);
SpamMessageLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstMessageTime);
if (difference.TotalMilliseconds < timeThreshold)
info.Lines++;
if (info.Lines > maxMessages)
{
info.Lines++;
if (info.Lines > maxMessages)
if (voiceResponse)
{
TimedDeVoice(message, devoiceTime);
}
if (kickResponse)
{
Bot.IRC.Command.SendKick(info.Channel, info.Nick, string.Format("Please do not spam. You have messaged {0} times within {1}ms.", info.Lines, timeThreshold));
SpamMessageLock.EnterWriteLock();
SpamMessageList.Remove(info);
SpamMessageLock.ExitWriteLock();
}
}
else
{
if (banResponse)
{
if (unbanResponse)
{
TimedBan(message, unbanTime);
}
else
{
BanNick(true, message);
}
}
if (!kickResponse)
{
string spamMessage = string.Format("Please do not spam. You have messaged {0} times within {1}ms.", info.Lines, timeThreshold);
SendResponse(MessageType.Channel, message.Channel, message.Sender.Nickname, spamMessage);
}
SpamMessageLock.EnterWriteLock();
info.Lines = 1;
info.FirstMessageTime = message.TimeStamp;
SpamMessageList.Remove(info);
SpamMessageLock.ExitWriteLock();
}
}
else
{
SpamMessageInfo info = new SpamMessageInfo();
info.Channel = message.Channel;
info.Nick = message.Sender.Nickname;
SpamMessageLock.EnterWriteLock();
info.Lines = 1;
info.FirstMessageTime = message.TimeStamp;
SpamMessageLock.EnterWriteLock();
SpamMessageList.Add(info);
SpamMessageLock.ExitWriteLock();
}
}
else
{
SpamMessageInfo info = new SpamMessageInfo();
info.Channel = message.Channel;
info.Nick = message.Sender.Nickname;
info.Lines = 1;
info.FirstMessageTime = message.TimeStamp;
SpamMessageLock.EnterWriteLock();
SpamMessageList.Add(info);
SpamMessageLock.ExitWriteLock();
}
}

// Check for highlight spam
List<string> splitMessage = message.Message.Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries).ToList();
Channel channel = Bot.IRC.Channels.Find(chan => chan.Name == message.Channel);
if (channel != null)
private void CheckHighlight(ChannelMessage message)
{
int timeThreshold = Convert.ToInt32(GetOptionValue("Time Threshold"));
int maxHighlights = Convert.ToInt32(GetOptionValue("Max Highlights"));
int devoiceTime = Convert.ToInt32(GetOptionValue("Devoice Time"));
int unbanTime = Convert.ToInt32(GetOptionValue("Unban Time"));
bool voiceResponse = Convert.ToBoolean(GetOptionValue("Voice Response"));
bool kickResponse = Convert.ToBoolean(GetOptionValue("Kick Response"));
bool banResponse = Convert.ToBoolean(GetOptionValue("Ban Response"));
bool unbanResponse = Convert.ToBoolean(GetOptionValue("Unban Response"));

// Check for highlight spam
List<string> splitMessage = message.Message.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
Channel channel = Bot.IRC.Channels.Find(chan => chan.Name == message.Channel);
if (channel != null)
{
List<string> foundNicks = splitMessage.FindAll(msg => channel.Nicks.Exists(nick => msg.Contains(nick.Nickname)));
if (foundNicks.Any())
{
List<string> foundNicks = splitMessage.FindAll(msg => channel.Nicks.Exists(nick => msg.Contains(nick.Nickname)));
if (foundNicks.Any())
if (!SpamHighlightList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
{
if (!SpamHighlightList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
{
SpamHighlightInfo newInfo = new SpamHighlightInfo();
newInfo.Channel = message.Channel;
newInfo.Nick = message.Sender.Nickname;
newInfo.Highlights = 0;
newInfo.FirstHighlightTime = message.TimeStamp;
SpamHighlightInfo newInfo = new SpamHighlightInfo();
newInfo.Channel = message.Channel;
newInfo.Nick = message.Sender.Nickname;
newInfo.Highlights = 0;
newInfo.FirstHighlightTime = message.TimeStamp;

SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Add(newInfo);
SpamHighlightLock.ExitWriteLock();
}
SpamHighlightLock.EnterReadLock();
SpamHighlightInfo info = SpamHighlightList.Find(highlight => highlight.Channel == message.Channel && highlight.Nick == message.Sender.Nickname);
SpamHighlightLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstHighlightTime);
if (difference.TotalMilliseconds < timeThreshold)
SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Add(newInfo);
SpamHighlightLock.ExitWriteLock();
}
SpamHighlightLock.EnterReadLock();
SpamHighlightInfo info = SpamHighlightList.Find(highlight => highlight.Channel == message.Channel && highlight.Nick == message.Sender.Nickname);
SpamHighlightLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstHighlightTime);
if (difference.TotalMilliseconds < timeThreshold)
{
info.Highlights += foundNicks.Count;
if (info.Highlights > maxHighlights)
{
info.Highlights += foundNicks.Count;
if (info.Highlights > maxHighlights)
if (voiceResponse)
{
TimedDeVoice(message, devoiceTime);
}
if (kickResponse)
{
Bot.IRC.Command.SendKick(info.Channel, info.Nick, string.Format("Please do not highlight spam. You have highlighted {0} nicks within {1}ms.", info.Highlights, timeThreshold));
SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Remove(info);
SpamHighlightLock.ExitWriteLock();
}
if (banResponse)
{
if (unbanResponse)
{
TimedBan(message, unbanTime);
}
else
{
BanNick(true, message);
}
}
if (!kickResponse)
{
string spamMessage = string.Format("Please do not highlight spam. You have highlighted {0} nicks within {1}ms.", info.Highlights, timeThreshold);
SendResponse(MessageType.Channel, message.Channel, message.Sender.Nickname, spamMessage);
}
SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Remove(info);
SpamHighlightLock.ExitWriteLock();
}
}
else
{
SpamHighlightLock.EnterWriteLock();
info.Highlights = foundNicks.Count;
info.FirstHighlightTime = message.TimeStamp;
SpamHighlightLock.ExitWriteLock();
}
}
}
}

private void TimedDeVoice(ChannelMessage message, int timeout)
{
SetMode(false, message.Channel, ChannelMode.v, message.Sender.Nickname);
System.Timers.Timer devoiceTrigger = new System.Timers.Timer();
devoiceTrigger.Interval = (timeout * 1000.0);
devoiceTrigger.Enabled = true;
devoiceTrigger.AutoReset = false;
devoiceTrigger.Elapsed += (sender, e) => TimedVoice(sender, e, message);
devoiceLock.EnterWriteLock();
devoiceTimers.Add(devoiceTrigger);
devoiceLock.ExitWriteLock();
}

private void TimedVoice(object sender, EventArgs e, ChannelMessage message)
{
System.Timers.Timer devoiceTimer = (System.Timers.Timer)sender;
devoiceTimer.Enabled = false;
SetMode(true, message.Channel, ChannelMode.v, message.Sender.Nickname);
devoiceLock.EnterWriteLock();
devoiceTimers.Remove(devoiceTimer);
devoiceLock.ExitWriteLock();
}

private void TimedBan(ChannelMessage message, int timeout)
{
BanNick(true, message);
System.Timers.Timer unban_trigger = new System.Timers.Timer();
unban_trigger.Interval = (timeout * 1000.0);
unban_trigger.Enabled = true;
unban_trigger.AutoReset = false;
unban_trigger.Elapsed += (sender, e) => TimedUnBan(sender, e, message);
unbanLock.EnterWriteLock();
unbanTimers.Add(unban_trigger);
unbanLock.ExitWriteLock();
}

private void TimedUnBan(object sender, EventArgs e, ChannelMessage message)
{
System.Timers.Timer unbanTimer = (System.Timers.Timer)sender;
unbanTimer.Enabled = false;
BanNick(false, message);
unbanLock.EnterWriteLock();
unbanTimers.Remove(unbanTimer);
unbanLock.ExitWriteLock();
}

private void BanNick(bool set, ChannelMessage message)
{
string banMask = message.Sender.Nickname;
if (!banMask.Contains("@") || !banMask.Contains("!"))
{
string search = "SELECT `nickinfo`.`username`, `nickinfo`.`host`, `nicks`.`nickname` FROM `nickinfo` " +
"INNER JOIN `nicks` " +
"ON `nickinfo`.`nick_id` = `nicks`.`id` " +
"INNER JOIN `servers` " +
"ON `nicks`.`server_id` = `servers`.`id` " +
"WHERE `servers`.`name` = {0} AND `nicks`.`nickname` = {1}";
List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] {Bot.ServerConfig.Name, banMask});

if (results.Any())
{
foreach (Dictionary<string, object> result in results)
{
var nickname = result["nickname"].ToString();
var host = result["host"].ToString();
var username = result["username"].ToString();
if (!string.IsNullOrEmpty(host) && !string.IsNullOrEmpty(username))
{
banMask = string.Format("*!*{0}@{1}", username, host);
}
else if (!string.IsNullOrEmpty(host))
{
banMask = string.Format("*!*@{0}", host);
}
else if (!string.IsNullOrEmpty(username))
{
banMask = string.Format("{0}!*{1}@*", nickname, username);
}
else
{
SpamHighlightLock.EnterWriteLock();
info.Highlights = foundNicks.Count;
info.FirstHighlightTime = message.TimeStamp;
SpamHighlightLock.ExitWriteLock();
banMask = string.Format("{0}!*@*", nickname);
}
SetMode(set, message.Channel, ChannelMode.b, banMask);
}
}
else
{
SetMode(set, message.Channel, ChannelMode.b, string.Format("{0}!*@*", banMask));
}
}
}

private void SetMode(bool set, string channel, ChannelMode mode, string nickname)
{
ChannelModeInfo modeInfo = new ChannelModeInfo();
modeInfo.Mode = mode;
modeInfo.Parameter = nickname;
modeInfo.Set = set;
Bot.IRC.Command.SendMode(channel, modeInfo);
}
}
}

Loading…
Cancel
Save