From e1ec7937fedc263982d4f2ba7ce93ffa58640e34 Mon Sep 17 00:00:00 2001 From: Andriy <30056636+West14@users.noreply.github.com> Date: Thu, 7 Jul 2022 17:02:47 +0300 Subject: [PATCH 1/2] [code-watcher] skip messages with lineCount < 2 --- modules/CodeWatcher/Handler.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/CodeWatcher/Handler.cs b/modules/CodeWatcher/Handler.cs index 81ba20c..7dc5f1f 100644 --- a/modules/CodeWatcher/Handler.cs +++ b/modules/CodeWatcher/Handler.cs @@ -34,6 +34,11 @@ public class Handler : BotEventHandler .SplitToLines() .ToList(); + if (entityLines.Count < 2) + { + continue; + } + if (entityLines.Count >= 20 || entityLines.Any(line => line.Length > 160)) { await DeleteAndNotifyAsync(message); From a4f05bacab27d36b544196a708ae6729ea62f119 Mon Sep 17 00:00:00 2001 From: Andriy <30056636+West14@users.noreply.github.com> Date: Thu, 7 Jul 2022 17:15:40 +0300 Subject: [PATCH 2/2] [code-watcher] handle message edit & message delayed delete service Message delayed deleter service deals with issue when you need to delete some message with delay without blocking the execution. This is replacement for dumb Task.Delay call. Use of it could be used before as exploit, to stop responding for a long time. --- modules/CodeWatcher/CodeWatcher.cs | 10 ++++- modules/CodeWatcher/DeleteRequest.cs | 10 +++++ modules/CodeWatcher/DeleteService.cs | 59 ++++++++++++++++++++++++++++ modules/CodeWatcher/Handler.cs | 29 ++++++++++---- 4 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 modules/CodeWatcher/DeleteRequest.cs create mode 100644 modules/CodeWatcher/DeleteService.cs diff --git a/modules/CodeWatcher/CodeWatcher.cs b/modules/CodeWatcher/CodeWatcher.cs index 0dfe046..d759347 100644 --- a/modules/CodeWatcher/CodeWatcher.cs +++ b/modules/CodeWatcher/CodeWatcher.cs @@ -1,9 +1,17 @@ -using Kruzya.TelegramBot.Core; +using System.Collections.Concurrent; +using Kruzya.TelegramBot.Core; +using Microsoft.Extensions.DependencyInjection; namespace West.TelegramBot.CodeWatcher { public class CodeWatcher : Module { public CodeWatcher(Core core) : base(core) {} + + public override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton>(); + services.AddHostedService(); + } } } \ No newline at end of file diff --git a/modules/CodeWatcher/DeleteRequest.cs b/modules/CodeWatcher/DeleteRequest.cs new file mode 100644 index 0000000..6f6c82b --- /dev/null +++ b/modules/CodeWatcher/DeleteRequest.cs @@ -0,0 +1,10 @@ +using Telegram.Bot.Types; + +namespace West.TelegramBot.CodeWatcher; + +public class DeleteRequest +{ + public ChatId ChatId { get; set; } + public int MessageId { get; set; } + public DateTime DeleteAt { get; set; } +} \ No newline at end of file diff --git a/modules/CodeWatcher/DeleteService.cs b/modules/CodeWatcher/DeleteService.cs new file mode 100644 index 0000000..42a0a4c --- /dev/null +++ b/modules/CodeWatcher/DeleteService.cs @@ -0,0 +1,59 @@ +using System.Collections.Concurrent; +using BotFramework.Abstractions; +using Kruzya.TelegramBot.Core.Service; +using Microsoft.Extensions.Logging; +using Telegram.Bot; +using Telegram.Bot.Exceptions; + +namespace West.TelegramBot.CodeWatcher; + +public class DeleteService : AbstractTimedHostedService +{ + private readonly ConcurrentBag _deleteRequests; + protected override TimeSpan TimerPeriod => TimeSpan.FromSeconds(10); + + public DeleteService(ILogger logger, IBotInstance bot, ConcurrentBag deleteRequests) : base(logger, + bot) + { + _deleteRequests = deleteRequests; + } + + protected override async Task OnRun() + { + var now = DateTime.Now; + var skippedRequestList = new List(); + + _logger.LogDebug("Spinning up the delete requests loop. Request count: {RequestCount}", _deleteRequests.Count); + for (var i = 0; i < _deleteRequests.Count; i++) + { + if (!_deleteRequests.TryTake(out var request)) + { + _logger.LogDebug("Nothing to take, breaking..."); + break; + } + + if (request.DeleteAt < now) + { + try + { + await _bot.BotClient.DeleteMessageAsync(request.ChatId, request.MessageId); + } + catch (ApiRequestException e) + { + _logger.LogError("Error deleting message, code - {ErrorCode}, msg - {ErrorMessage}", e.ErrorCode, + e.Message); + } + } + else + { + _logger.LogDebug("Skipping {MessageId}", request.MessageId); + skippedRequestList.Add(request); + } + } + + foreach (var request in skippedRequestList) + { + _deleteRequests.Add(request); + } + } +} \ No newline at end of file diff --git a/modules/CodeWatcher/Handler.cs b/modules/CodeWatcher/Handler.cs index 7dc5f1f..3abeaa8 100644 --- a/modules/CodeWatcher/Handler.cs +++ b/modules/CodeWatcher/Handler.cs @@ -1,4 +1,5 @@ -using BotFramework; +using System.Collections.Concurrent; +using BotFramework; using BotFramework.Attributes; using BotFramework.Enums; using Kruzya.TelegramBot.Core.Extensions; @@ -10,12 +11,19 @@ namespace West.TelegramBot.CodeWatcher; public class Handler : BotEventHandler { - [Message(InChat.Public, MessageFlag.HasText)] + private readonly ConcurrentBag _requests; + + public Handler(ConcurrentBag requests) + { + _requests = requests; + } + + [Update(InChat.Public, UpdateFlag.Message | UpdateFlag.EditedMessage)] public async Task HandleMessage() { - var message = RawUpdate.Message!; + var message = RawUpdate.Message ?? RawUpdate.EditedMessage; - if (message.Entities == null) + if (message?.Entities == null) { return; } @@ -51,12 +59,17 @@ public class Handler : BotEventHandler public async Task DeleteAndNotifyAsync(Message message) { await Bot.DeleteMessageAsync(Chat.Id, message.MessageId); - var notifyMsg = await Bot.SendTextMessageAsync(Chat.Id, + var notifyMsg = await Bot.SendTextMessageAsync(Chat.Id, (message.From?.ToHtml() ?? "") + ", не стоит публиковать столь большой код прямо в чат. " + "Вместо этого загрузите его на https://pastebin.com и отправьте в виде ссылки.", ParseMode.Html); - - await Task.Delay(TimeSpan.FromMinutes(1)); - await Bot.DeleteMessageAsync(Chat.Id, notifyMsg.MessageId); + + // TODO: maybe write a wrapper-service around collection to avoid direct interactions with the collection, West, 07.07.2022, 16:53 + _requests.Add(new DeleteRequest + { + ChatId = notifyMsg.Chat.Id, + MessageId = notifyMsg.MessageId, + DeleteAt = DateTime.Now.AddSeconds(30) + }); } } \ No newline at end of file