From 8f8898e9011ca713e73fca2dc3e9af4c0e189a1a Mon Sep 17 00:00:00 2001 From: Sergey Gut Date: Tue, 3 Mar 2020 14:11:51 +0400 Subject: [PATCH] :construction: Anti-spam system based on entities --- Core/Core.cs | 4 +- Core/Extensions/StartupExtension.cs | 4 ++ Core/Extensions/UserExtension.cs | 2 +- Kruzya.TelegramBot.sln | 7 +++ modules/UrlLimitations/Data/ChatMember.cs | 19 +++++++ modules/UrlLimitations/MessageHandler.cs | 58 ++++++++++++++++++++ modules/UrlLimitations/UrlLimitations.cs | 19 +++++++ modules/UrlLimitations/UrlLimitations.csproj | 13 +++++ modules/UrlLimitations/UserJoinHandler.cs | 25 +++++++++ 9 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 modules/UrlLimitations/Data/ChatMember.cs create mode 100644 modules/UrlLimitations/MessageHandler.cs create mode 100644 modules/UrlLimitations/UrlLimitations.cs create mode 100644 modules/UrlLimitations/UrlLimitations.csproj create mode 100644 modules/UrlLimitations/UserJoinHandler.cs diff --git a/Core/Core.cs b/Core/Core.cs index 64e77ac..c6a981e 100644 --- a/Core/Core.cs +++ b/Core/Core.cs @@ -161,11 +161,11 @@ namespace Kruzya.TelegramBot.Core private void HookAppDomain() { var appDomain = AppDomain.CurrentDomain; - + appDomain.AssemblyResolve += delegate(object? sender, ResolveEventArgs args) { var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string assemblyPath = Path.Combine(basePath, new AssemblyName(args.Name).Name + ".dll"); + var assemblyPath = Path.Combine(basePath, new AssemblyName(args.Name).Name + ".dll"); if (!File.Exists(assemblyPath)) { return null; diff --git a/Core/Extensions/StartupExtension.cs b/Core/Extensions/StartupExtension.cs index cbbbfbd..1cd4c46 100644 --- a/Core/Extensions/StartupExtension.cs +++ b/Core/Extensions/StartupExtension.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using Kruzya.TelegramBot.Core.Cache; using Microsoft.Extensions.DependencyInjection; namespace Kruzya.TelegramBot.Core.Extensions @@ -7,5 +8,8 @@ namespace Kruzya.TelegramBot.Core.Extensions { public static IServiceCollection AddQueue(this IServiceCollection collection) => collection.AddSingleton>(); + + public static IServiceCollection AddMemoryCache(this IServiceCollection collection) + => collection.AddSingleton>(); } } \ No newline at end of file diff --git a/Core/Extensions/UserExtension.cs b/Core/Extensions/UserExtension.cs index ad34cc9..11f578c 100644 --- a/Core/Extensions/UserExtension.cs +++ b/Core/Extensions/UserExtension.cs @@ -8,7 +8,7 @@ namespace Kruzya.TelegramBot.Core.Extensions public static string ToHtml(this User user) { var text = new StringBuilder(); - text.Append(""); + text.Append($""); if (!string.IsNullOrWhiteSpace(user.Username)) text.Append(user.Username); else diff --git a/Kruzya.TelegramBot.sln b/Kruzya.TelegramBot.sln index 05b2821..48d8613 100644 --- a/Kruzya.TelegramBot.sln +++ b/Kruzya.TelegramBot.sln @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RichSiteSummary", "modules\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests.csproj", "{5C62CA70-F270-4029-953E-458623C31A3B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UrlLimitations", "modules\UrlLimitations\UrlLimitations.csproj", "{B82E3339-3B34-4600-8C59-C5A3640B1982}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,9 +34,14 @@ Global {5C62CA70-F270-4029-953E-458623C31A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU {5C62CA70-F270-4029-953E-458623C31A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C62CA70-F270-4029-953E-458623C31A3B}.Release|Any CPU.Build.0 = Release|Any CPU + {B82E3339-3B34-4600-8C59-C5A3640B1982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B82E3339-3B34-4600-8C59-C5A3640B1982}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B82E3339-3B34-4600-8C59-C5A3640B1982}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B82E3339-3B34-4600-8C59-C5A3640B1982}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {F1E1FBB7-ABA4-4304-9A42-D4975822B002} = {C7821F15-DEDD-474F-A575-A296D4B58F10} {C50D64C3-204B-4B58-927B-C8D759787252} = {C7821F15-DEDD-474F-A575-A296D4B58F10} + {B82E3339-3B34-4600-8C59-C5A3640B1982} = {C7821F15-DEDD-474F-A575-A296D4B58F10} EndGlobalSection EndGlobal diff --git a/modules/UrlLimitations/Data/ChatMember.cs b/modules/UrlLimitations/Data/ChatMember.cs new file mode 100644 index 0000000..cc8d906 --- /dev/null +++ b/modules/UrlLimitations/Data/ChatMember.cs @@ -0,0 +1,19 @@ +using Telegram.Bot.Types; + +namespace Kruzya.TelegramBot.UrlLimitations +{ + public struct ChatMember + { + public long Chat; + public long User; + + public static ChatMember From(long chatId, long userId) + { + return new ChatMember() + { + Chat = chatId, + User = userId + }; + } + } +} \ No newline at end of file diff --git a/modules/UrlLimitations/MessageHandler.cs b/modules/UrlLimitations/MessageHandler.cs new file mode 100644 index 0000000..55e99d3 --- /dev/null +++ b/modules/UrlLimitations/MessageHandler.cs @@ -0,0 +1,58 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using BotFramework; +using BotFramework.Attributes; +using BotFramework.Setup; +using Kruzya.TelegramBot.Core.Cache; +using Kruzya.TelegramBot.Core.Extensions; +using Microsoft.Extensions.Logging; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; + +namespace Kruzya.TelegramBot.UrlLimitations +{ + public class MessageHandler : BotEventHandler + { + protected ILogger Logger; + protected MemoryCache ChatMembersCache; + + public MessageHandler(ILogger logger, MemoryCache chatMembersCache) + { + Logger = logger; + ChatMembersCache = chatMembersCache; + } + + [TextMessage(InChat.Public)] + public async Task OnMessageReceived() + { + Logger.LogDebug($"Message received from {From.Id} in {Chat.Id}"); + + UInt16 messageCount; + var chatMember = ChatMember.From(Chat.Id, From.Id); + if (!ChatMembersCache.TryGetValue(chatMember, out messageCount)) + { + return; + } + + if (messageCount > 10) + { + ChatMembersCache.SetValue(chatMember, 0, 0); + return; + } + + messageCount++; + ChatMembersCache.SetValue(chatMember, messageCount); + var message = RawUpdate.Message; + if (message.Entities.Count(e => e.Type == MessageEntityType.Url || e.Type == MessageEntityType.TextLink) > + 0) + { + var targetChat = new ChatId(Chat.Id); + await Bot.KickChatMemberAsync(new ChatId(Chat.Id), From.Id, DateTime.Now.AddDays(1)); + await Bot.DeleteMessageAsync(targetChat, message.MessageId); + await Bot.SendTextMessageAsync(targetChat, + $"Member {From.ToHtml()} has been banned.\nReason:
Spam suspicion
", ParseMode.Html); + } + } + } +} \ No newline at end of file diff --git a/modules/UrlLimitations/UrlLimitations.cs b/modules/UrlLimitations/UrlLimitations.cs new file mode 100644 index 0000000..e0158da --- /dev/null +++ b/modules/UrlLimitations/UrlLimitations.cs @@ -0,0 +1,19 @@ +using System; +using Kruzya.TelegramBot.Core; +using Kruzya.TelegramBot.Core.Extensions; +using Microsoft.Extensions.DependencyInjection; + +namespace Kruzya.TelegramBot.UrlLimitations +{ + public class UrlLimitations : Module + { + public UrlLimitations(Core.Core core) : base(core) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddMemoryCache(); + } + } +} \ No newline at end of file diff --git a/modules/UrlLimitations/UrlLimitations.csproj b/modules/UrlLimitations/UrlLimitations.csproj new file mode 100644 index 0000000..41c572b --- /dev/null +++ b/modules/UrlLimitations/UrlLimitations.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + TelegramBot.UrlLimitations + Kruzya.TelegramBot.UrlLimitations + + + + + + + diff --git a/modules/UrlLimitations/UserJoinHandler.cs b/modules/UrlLimitations/UserJoinHandler.cs new file mode 100644 index 0000000..98bd0ff --- /dev/null +++ b/modules/UrlLimitations/UserJoinHandler.cs @@ -0,0 +1,25 @@ +using System; +using BotFramework; +using BotFramework.Attributes; +using BotFramework.Setup; +using Kruzya.TelegramBot.Core.Cache; +using Telegram.Bot.Types.Enums; + +namespace Kruzya.TelegramBot.UrlLimitations +{ + public class UserJoinHandler : BotEventHandler + { + protected MemoryCache ChatMembersCache; + + public UserJoinHandler(MemoryCache chatMembersCache) + { + ChatMembersCache = chatMembersCache; + } + + [Message(MessageType.ChatMembersAdded, InChat.Public)] + public void OnChatMembersAdded() + { + ChatMembersCache.SetValue(ChatMember.From(Chat.Id, From.Id), 0); + } + } +} \ No newline at end of file