Бот для борьбы со спамом в Telegram на Golang

Posted by Pavel on Friday, April 23, 2021

Вступление

This article in English

Перед тем как начать писать своего бота я пытался использовать уже существующих, но все они обладали своими недостатками. Так как я был админом русскоязычного гео-чата в Telegram мне нужно было решение которое бы справлялась с большим количеством ботов не загрязняя ленту сообщений другими сообщения о том что один пользователь заблокирован или удален

Минусы существующих ботов:

  • Большие информационные сообщения по типу: “Сообщение удалено так как …", что плохо работает там, где есть много спам ботов

  • Проверка на капчу не решает проблемы англоязычных ботов-торговцев, которые решают простую капчу и затем вставляют свое спам сообщение. Мне нужно было решение, которое оставит только русскоязычных пользователей

Решение

Решением стало написание свое бота, который задавал вопросы по типу:

@username Добро пожаловать в чат @chatname! Напишите числом сколько будет: два умножить на три, чтобы проверить, что вы не бот

example

Пользователю нужно ответить правильно, другие сообщения будут удаляться

Как добавить бота в чат?

Сначала вам нужно пригласить бота в чат по его никнейму: @spam_fighter_bot

Ссылка на бота: https://t.me/spam_fighter_bot

  1. Добавляете бота в чат:

add-bot-to-chat

  1. После этого добавляете бота как админа в настройках чата:

add-bot-as-admin

  1. Даете боту права доступа на удаление сообщений и бан пользователей:

add-bot-as-admin

Готово!

Код

Для работы с сообщениями в телеграм я решил использовать библиотеку 🔗tucnak/telebot с которой я уже работал раньше и которая кажется мне весьма удобной

Для начала надо настроить и запустить нового бота:

В импорты нужно добавить:

import (
	tb "gopkg.in/tucnak/telebot.v2"
)

И таким образом запускается наш бот

	// initialize bot
	b, err := tb.NewBot(tb.Settings{
		Token:  "YOUR_TOKEN",
		Poller: &tb.LongPoller{Timeout: 10 * time.Second},
	})
	if err != nil {
		fmt.Printf("error while initializing bot, %v", err)
	}

Для того чтобы отследить когда новый пользователь зайдет в чат, нужно добавить отлавливание этих событий:

    b.Handle(tb.OnUserJoined, UserJoined(l, b, memoryStorage))

А вот так выглядит сама функция UserJoined:

func UserJoined(l *zap.SugaredLogger, b *tb.Bot, s data.Storage) func(m *tb.Message) {
	return func(m *tb.Message) {
		r := rand.New(rand.NewSource(time.Now().UnixNano()))

		// generating two random small number
		firstNumber := r.Intn(4) + 1
		secondNumber := r.Intn(4) + 1
		fistNumberInWords := ntw.IntegerToRuRu(firstNumber)
		secondNumberInWords := ntw.IntegerToRuRu(secondNumber)

		username := getUsername(m.Sender)
		welcomeMessageText := getWelcomeMessageText(username, m.Chat.Title, fistNumberInWords, secondNumberInWords)
		welcomeMessage, err := b.Send(m.Chat, welcomeMessageText)
		if err != nil {
			l.Error("error while sending welcome message", err)
			return
		}
		s.Add(m.Chat, m.Sender, data.Info{WelcomeMessage: welcomeMessage, RightAnswer: firstNumber * secondNumber})

		// Goroutine to delete message after 2 minutes
		// and block user if he or she still in the list
		go checkAndBanUser(l, b, welcomeMessage, s, m, username)
	}
}

Она генерирут два случайных числа и конвертирует их в текст. Правильный ответ записывается в память. Затем в горутине ожидается 2 минуты от отправки сообщения, если пользователь так и не решил правильно ответ, то он блокируется и удаляется из чата

Вот так выглядит код для проверки ответа пользователя:

func Text(l *zap.SugaredLogger, b *tb.Bot, s data.Storage) func(m *tb.Message) {
	return func(m *tb.Message) {
		info, ok := s.Exist(m.Chat, m.Sender)
		if !ok {
			return
		}
		if m.Text != strconv.Itoa(info.RightAnswer) {
			err := b.Delete(m)
			if err != nil {
				l.Errorf("error while deleting (spam) user message: %v", err)
			}
			return
		}
		// in case of correct answer:
		s.Remove(m.Chat, m.Sender)

		// Correct! Tell us about yourself
		approveMessage, err := b.Send(m.Chat, "Верно! Расскажите нам о себе 🙂")
		if err != nil {
			l.Errorf("error while sending: %v", err)
		}
		go deleteWelcomeMessages(l, b, m, approveMessage, info.WelcomeMessage)
	}
}

Итог работы бота

По итогу бот очень успешно банит других ботов, не давая им написать сообщение с рекламой. Никто не переводит сообщения на английский язык и поэтому не знает что именно нужно делать. Таким образом пока получается блокировать всех ботов, хотя раньше с другими анти-спам ботами 50% просто решали капчу и писали спам

feedback

Исходный код

Исходный код, который деплоится затем на сервер вы можете найти тут:

🔗GitHub

Вы можете предложить свои изменения и улучшения, код открытый

После мержа код автоматически деплоится в продакшен (если билд пройдет успешно)


comments powered by Disqus