public BaseClient() { var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "settings.json"); if (File.Exists(path)) { var data = File.ReadAllText(path); try { Settings = JsonConvert.DeserializeObject <Settings>(data, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error }); if (!IrcValidation.IsNickname(Settings.Nickname)) { throw new JsonException("Nickname is not valid."); } if (!IrcValidation.IsChannelName(Settings.RedirectChannel)) { throw new JsonException("Redirect channel is not valid."); } foreach (var channel in Settings.Channels) { if (!IrcValidation.IsChannelName(channel)) { throw new JsonException($"Channel '{channel}' is not valid."); } } } catch (JsonException e) { Log.WriteError("IRC", "Failed to parse settings.json file: {0}", e.Message); Environment.Exit(1); } } else { Log.WriteWarn("IRC", "File config/settings.json doesn't exist"); Environment.Exit(1); } Client = new IrcClient { ClientVersion = "Wendy# -- https://github.com/xPaw/WendySharp" }; Client.Connected += OnConnected; Client.Closed += OnDisconnected; Permissions = new Permissions(); Commands = new Commands(Client); LinkExpander = new LinkExpander(Client); ChannelList = new Channels(Client); Whois = new Whois(Client); }
private void ProcessQuit(IrcIdentity ident, string channelName, SpamConfig channel) { var nickname = ident.Nickname; Whois.NormalizeIdentity(ident); var quits = channel.AddUserPart(ident.ToString(), channel.QuitsThresholdSeconds); if (quits < channel.QuitsThreshold) { return; } channel.ResetUserPart(ident.ToString()); Log.WriteInfo("Spam", "'{1}' ({0}) is spamming joins/quits in {2}. Redirecting for {3} minutes.", nickname, ident, channelName, channel.QuitsBanMinutes); Bootstrap.Client.Client.Mode(channelName, "+b", ident + "$" + Bootstrap.Client.Settings.RedirectChannel); // In case they manage to come back before ban takes place Bootstrap.Client.Client.Kick(nickname, channelName, string.Format("Fix your connection. Banned for {0} minutes", channel.QuitsBanMinutes)); Bootstrap.Client.Client.Notice(nickname, string.Format("You have been banned from {0} for {1} minutes for rapidly rejoining the channel.", channelName, channel.QuitsBanMinutes)); Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = channelName, Recipient = ident.ToString(), Mode = "-b", Time = DateTime.UtcNow.AddMinutes(channel.QuitsBanMinutes), Reason = "Quit/leave flood" } ); }
public override void OnCommand(CommandArguments command) { var nick = command.Arguments.Groups["nick"].Value; if (!IrcIdentity.TryParse(nick, out var ident)) { command.Reply("Invalid identity."); return; } var channel = Bootstrap.Client.ChannelList.GetChannel(command.Event.Recipient); if (!channel.WeAreOpped) { if (channel.HasChanServ) { Bootstrap.Client.Client.Message("ChanServ", string.Format("op {0}", channel.Name)); } else { command.Reply("I'm not opped, send help."); return; } } var isQuiet = command.MatchedCommand != "unban"; Bootstrap.Client.Whois.Query(ident, whoisData => { if (whoisData.Identity.Nickname != null) { ident = whoisData.Identity; Whois.NormalizeIdentity(ident); } else { if (ident.Username == null) { ident.Username = "******"; } if (ident.Hostname == null) { ident.Hostname = "*"; } } Log.WriteInfo("Unban", "'{0}' unbanned '{1}' in {2}", command.Event.Sender, ident, command.Event.Recipient); Bootstrap.Client.Client.Mode(command.Event.Recipient, isQuiet ? "-q" : "-b", ident); command.ReplyAsNotice("{0} {1}", isQuiet ? "Unmuted" : "Unbanned", ident); } ); }
private void ProcessQuit(IrcIdentity ident, string channelName, SpamConfig channel) { var nickname = ident.Nickname; ident = Whois.NormalizeIdentity(ident); var quits = channel.AddUserPart(ident.ToString(), channel.QuitsThresholdSeconds); if (quits < channel.QuitsThreshold) { return; } var banMinutes = channel.AddUserBan(ident.ToString()) * channel.QuitsBanMinutes; Log.WriteInfo("Spam", "'{1}' ({0}) is spamming joins/quits in {2}. Redirecting for {3} minutes.", nickname, ident, channelName, banMinutes); Bootstrap.Client.Client.Mode(channelName, "+b", ident + "$" + Bootstrap.Client.Settings.RedirectChannel); // In case they manage to come back before ban takes place Bootstrap.Client.Client.Kick(nickname, channelName, $"Fix your connection. Banned for {banMinutes} minutes"); Bootstrap.Client.Client.Notice(nickname, $"Please fix your connection. You have been banned from {channelName} for {banMinutes} minutes for rapidly rejoining the channel."); if (Bootstrap.Client.ModeList.Find(channelName, ident.ToString(), "-b") != null) { Log.WriteInfo("Spam", "There's already a latemode set for '{0}' in {1}", ident, channelName); return; } Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = channelName, Recipient = ident.ToString(), Mode = "-b", Time = DateTime.UtcNow.AddMinutes(banMinutes), Reason = "Quit/leave flood" } ); }
public override void OnCommand(CommandArguments command) { var nick = command.Arguments.Groups["nick"].Value; if (!IrcIdentity.TryParse(nick, out var ident)) { command.Reply("Invalid identity."); return; } var channel = Bootstrap.Client.ChannelList.GetChannel(command.Event.Recipient); if (!channel.WeAreOpped) { if (channel.HasChanServ) { Bootstrap.Client.Client.Message("ChanServ", string.Format("op {0}", channel.Name)); } else { command.Reply("I'm not opped, send help."); return; } } Bootstrap.Client.Whois.Query(ident, whoisData => { if (whoisData.Identity.Nickname != null) { ident = whoisData.Identity; } var nickname = ident.Nickname; if (nickname.ToString().ToLowerInvariant() == Bootstrap.Client.TrueNickname.ToLowerInvariant()) { command.Reply("Don't you even dare."); return; } if (whoisData.Identity.Nickname != null) { Whois.NormalizeIdentity(ident); } else { if (ident.Username == null) { ident.Username = "******"; } if (ident.Hostname == null) { ident.Hostname = "*"; } } var targetChannel = command.Arguments.Groups["channel"].Value.Trim(); if (targetChannel.Length == 0) { targetChannel = Bootstrap.Client.Settings.RedirectChannel; } else if (!IrcValidation.IsChannelName(targetChannel)) { command.Reply("Invalid target channel."); return; } if (Bootstrap.Client.ModeList.Find(command.Event.Recipient, ident.ToString(), "-b") != null) { command.Reply("{0} is already banned in this channel.", ident); return; } Log.WriteInfo("Redirect", "'{0}' redirected '{1}' from {2} to {3}", command.Event.Sender, ident, command.Event.Recipient, targetChannel); var reason = string.Format("Redirected to {0} by {1} for 2 hours", targetChannel, command.Event.Sender.Nickname); Bootstrap.Client.Client.Mode(command.Event.Recipient, "+b", ident + "$" + targetChannel); if (channel.HasUser(nickname)) { Bootstrap.Client.Client.Kick(nickname, command.Event.Recipient, reason); } command.ReplyAsNotice("Redirected {0} to {1} for 2 hours", ident, targetChannel); Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = command.Event.Recipient, Recipient = ident.ToString(), Sender = command.Event.Sender.ToString(), Mode = "-b", Time = DateTime.UtcNow.AddHours(2), Reason = reason } ); } ); }
public void OnMessage(ChatMessageEventArgs e, string message, User user) { if (e.Sender == null || !Channels.ContainsKey(e.Recipient) || (user?.HasPermission(e.Recipient, "spam.whitelist") == true)) { return; } var sender = e.Sender; var channel = Channels[e.Recipient]; channel.AddAction(sender, message); var actualChannel = Bootstrap.Client.ChannelList.GetChannel(e.Recipient); var mentions = message.Split(' ').Count(word => word.Length > 2 && actualChannel.HasUser(word)); if (mentions >= channel.UserMentionsInOneMessage) { Bootstrap.Client.Client.Notice(sender.Nickname, "Don't mention too many users at once."); } else { var saidLines = 0; var repeatLines = 0; foreach (var action in channel.LastActions) { if (action.Identity != sender) { continue; } if (action.Time.AddSeconds(channel.LinesThresholdSeconds) >= DateTime.UtcNow) { saidLines++; } if (action.Time.AddSeconds(channel.RepeatThresholdSeconds) >= DateTime.UtcNow && action.Message == message) { repeatLines++; } } if (saidLines < channel.LinesThreshold && repeatLines < channel.RepeatThreshold) { return; } channel.LastActions.Clear(); // TODO: FIX Bootstrap.Client.Client.Notice(sender.Nickname, channel.Message); } Log.WriteInfo("Spam", "A line by '{0}' in {1} was detected as spam. Quieting for {2} seconds.", sender, e.Recipient, channel.Duration); sender = Whois.NormalizeIdentity(sender); Bootstrap.Client.Client.Mode(e.Recipient, "+q", sender); if (Bootstrap.Client.ModeList.Find(e.Recipient, sender.ToString(), "-q") != null) { Log.WriteInfo("Spam", "There's already a latemode set for '{0}' in {1}", sender, e.Recipient); return; } Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = e.Recipient, Recipient = sender.ToString(), Mode = "-q", Time = DateTime.UtcNow.AddSeconds(channel.Duration), Reason = "Spam" } ); }
public override void OnCommand(CommandArguments command) { var nick = command.Arguments.Groups["nick"].Value; if (!IrcIdentity.TryParse(nick, out var ident)) { command.Reply("Invalid identity."); return; } var duration = command.Arguments.Groups["duration"].Value; var durationTime = default(DateTime); if (duration.Length > 0) { try { durationTime = DateTimeParser.Parse(duration, command.Arguments.Groups["durationUnit"].Value); } catch (ArgumentException e) { command.Reply("{0}", e.Message); return; } } var channel = Bootstrap.Client.ChannelList.GetChannel(command.Event.Recipient); if (!channel.WeAreOpped) { if (channel.HasChanServ) { Bootstrap.Client.Client.IrcCommand("CHANSERV", "op", channel.Name); } else { command.Reply("I'm not opped, send help."); return; } } var isQuiet = command.MatchedCommand == "quiet" || command.MatchedCommand == "mute"; Bootstrap.Client.Whois.Query(ident, whoisData => { if (whoisData.Identity.Nickname == null) { command.Reply("There is no user by that nick on the network. Try {0}!*@* to {1} anyone with that nick, or specify a full hostmask.", ident.Nickname, isQuiet ? "quiet" : "ban"); return; } ident = whoisData.Identity; var nickname = ident.Nickname; if (string.Equals(nickname.ToString(), Bootstrap.Client.TrueNickname, StringComparison.InvariantCultureIgnoreCase)) { command.Reply("Don't you even dare."); return; } ident = Whois.NormalizeIdentity(ident); if (Bootstrap.Client.ModeList.Find(command.Event.Recipient, ident.ToString(), isQuiet ? "-q" : "-b") != null) { command.Reply("{0} is already {1} in this channel.", ident, isQuiet ? "muted" : "banned"); return; } Log.WriteInfo("Ban", "'{0}' {1} '{2}' from {3}", command.Event.Sender, isQuiet ? "quieted" : "banned", ident, command.Event.Recipient); var reason = command.Arguments.Groups["reason"].Value.Trim(); if (reason.Length == 0) { reason = $"Banned by {command.Event.Sender.Nickname}"; } Bootstrap.Client.Client.Mode(command.Event.Recipient, isQuiet ? "+q" : "+b", ident); if (!isQuiet && channel.HasUser(nickname)) { Bootstrap.Client.Client.Kick(nickname, command.Event.Recipient, reason); } if (duration.Length > 0) { command.ReplyAsNotice("Will {0} {1} {2}", isQuiet ? "unmute" : "unban", ident, durationTime.ToRelativeString()); Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = command.Event.Recipient, Recipient = ident.ToString(), Sender = command.Event.Sender.ToString(), Mode = isQuiet ? "-q" : "-b", Time = durationTime, Reason = reason } ); } else { command.ReplyAsNotice("{0} {1}", isQuiet ? "Muted" : "Banned", ident); } } ); }
private void OnMessage(object obj, ChatMessageEventArgs e) { if (e.Sender == null || !Channels.ContainsKey(e.Recipient) || IsWhitelisted(e.Sender, e.Recipient)) { return; } var sender = e.Sender; var channel = Channels[e.Recipient]; channel.AddAction(sender, e.Message); var actualChannel = Bootstrap.Client.ChannelList.GetChannel(e.Recipient); var mentions = e.Message.Split((byte)' ').Count(word => word.Length > 2 && actualChannel.HasUser(word)); if (mentions >= channel.UserMentionsInOneMessage) { Bootstrap.Client.Client.Notice(sender.Nickname, "Don't mention too many users at once."); } else if (mentions > 0 && e.Message.ToString().Contains('▄')) { // Stupid tactic to deal with spambots } else { var saidLines = 0; var repeatLines = 0; foreach (var message in channel.LastActions) { if (message.Identity != sender) { continue; } if (message.Time.AddSeconds(channel.LinesThresholdSeconds) >= DateTime.UtcNow) { saidLines++; } if (message.Time.AddSeconds(channel.RepeatThresholdSeconds) >= DateTime.UtcNow && message.Message == e.Message) { repeatLines++; } } if (saidLines < channel.LinesThreshold && repeatLines < channel.RepeatThreshold) { return; } channel.LastActions.Clear(); // TODO: FIX Bootstrap.Client.Client.Notice(sender.Nickname, channel.Message); } Log.WriteInfo("Spam", "A line by '{0}' in {1} was detected as spam. Quieting for {2} seconds.", sender, e.Recipient, channel.Duration); Whois.NormalizeIdentity(sender); Bootstrap.Client.Client.Mode(e.Recipient, "+q", sender); Bootstrap.Client.ModeList.AddLateModeRequest( new LateModeRequest { Channel = e.Recipient, Recipient = sender.ToString(), Mode = "-q", Time = DateTime.UtcNow.AddSeconds(channel.Duration), Reason = "Spam" } ); }