An easy to use an (hopefully useful) captcha solution for pyTelegramBotAPI

Overview

pyTelegramBotCAPTCHA

An easy to use and (hopefully useful) image CAPTCHA soltion for pyTelegramBotAPI.

PyPi Package Version Supported Python versions


Installation:

pip install pyTelegramBotCAPTCHA

Do not forget to update the package from time to time by calling
pip install pyTelegramBotCAPTCHA --upgrade


Description:

Do you have problems with userbots that spam your groups or add your group members to other chats? Then this package can help you to protect your groups and members! It's very easy to integrate into your existing bot and also easy to customize the CAPTCHA image with your own fonts.
You can also choose between digits and hexdigits for your CAPTCHA generation.
Note: You should have basic knowledge about the pyTelegramBotAPI
Example1 Example2


Writing a CAPTCHA bot:

Import TeleBot and the CapchaManager:

from telebot import TeleBot
from pyTelegramBotCAPTCHA import CaptchaManager

Initialize the bot and the captcha_manager:

CaptchaManager requires the user_id of your TeleBot instance! You get it with bot.get_me().id
You can add the following optional parameters:

  • default_language (str) the default language to use if not set in captcha_manager.send_random_captcha(...). Default is "en". Currently supported "en", "ru" and "de"
  • default_timeout (float) the default timeout to use if not set in captcha_manager.send_random_captcha(...). Default is None but we will use a default_timeout of 90 seconds for our CAPTCHAs.
  • fonts (list) the fonts to use instead of the builtin ones (must be a list of .ttf file paths). You can choose as many fonts as you like, but keep in mind that all the fonts are loaded into your memory, so use a lot but not to many.
bot = TeleBot("TOKEN")
captcha_manager = CaptchaManager(bot.get_me().id, default_timeout=90)

Note: Make sure to actually replace TOKEN with your own API token


Add a message handler for new chat members:

We need a message handler to restrict the new member and sending a CAPTCHA to solve when a new user joins the group.
captcha_manager.restrict_chat_member() requires your TeleBot instance, the chat_id and the user_id. It disables all permissions of a chat member.
captcha_manager.send_random_captcha() requires your TeleBot instance, the Chat object and the User object. It sends a new CAPTCHA in the chat.
You can add the following optional parameters:

  • language (str) the language to use for this CAPTCHA
  • add_noise (bool) add noise to the CAPTCHA image
  • only_digits (bool) only use ditgits instead of hexdigits for the CAPTCHA code
  • timeout (float) to set a timeout for the CAPTCHA in seconds.
# Message handler for new chat members
@bot.message_handler(content_types=["new_chat_members"])
def new_member(message):
  # get the new chat members
  for user in message.new_chat_members:

    # Restrict the new chat member
    captcha_manager.restrict_chat_member(bot, message.chat.id, user.id)

    # send random CAPTCHA
    captcha_manager.send_random_captcha(bot, message.chat, user)

Note: Service messages about non-bot users joining the chat will be soon removed from large groups. We recommend using the “chat_member” update as a replacement.


Add a callback query handler:

We need a callback query handler, to handle the users input when he presses a CAPTCHA button.
captcha_manager.update_captcha() requires your TeleBot instance and the CallbackQuery object as parameters.
It automatically returns if callback was not from a CAPTCHA or from the wrong user.
If the wrong user pressed a button he gets an callback query answer denying his input.
If the submit button is pressed the CAPTCHA is automatically checked and your corresponding CAPTCHA handler function is called. The timeout is also canceled if submit is pressed.

# Callback query handler
@bot.callback_query_handler(func=lambda callback:True)
def on_callback(callback):
  # update the CAPTCHA
  captcha_manager.update_captcha(bot, callback)

Add CAPTCHA handler functions:

This works just like you know it from message handlers from the pyTelegramBotAPI.
A Captcha object will be passed to your functions.
The Captcha object has the following attributes:

  • message_id (int) the message id of the CAPTCHA message
  • user (User) the user that must solve the CAPTCHA
  • chat (Chat) the chat
  • users_code (str) the code entered by the user
  • correct_code (str) the correct code to solve the CAPTCHA
  • language (str) the language of the CAPTCHA text
  • created_at (float) the timestemp when the CAPTCHA was created
  • previous_tries (int) the number of tries the user made
  • incorrect_digits (int) the number of digits that dont match
  • solved (bool) has the user solved the CAPTCHA? it does not matter if he solved it correct

Lets add our first CAPTCHA handler that handles correct solved CAPTCHAs. captcha_manager.unrestrict_chat_member() requires your TeleBot instance, the chat_id and the user_id. It removes all restictions of a chat member.
captcha_manager.delete_captcha() requires your TeleBot instance and the Captcha object. It removes the CAPTCHA from the chat and your memory

# Handler for correct solved CAPTCHAs
@captcha_manager.on_captcha_correct
def on_correct(captcha):
  bot.send_message(captcha.chat.id, "Congrats! You solved the CAPTCHA!")
  # We unrestrict the chat member because he solved the CAPTCHA correct.
  captcha_manager.unrestrict_chat_member(bot, captcha.chat.id, captcha.user.id)
  # Delete the CAPTCHA
  captcha_manager.delete_captcha(bot, captcha)

Lets add a handler that handles wrong solved CAPTCHAs.
We use the Captcha attributes incorrect_digits and previous_tries to give the user a second try if only one digit was incorrect.
captcha_manager.refresh_captcha() requires your TeleBot instance and the Captcha object. It generates a new code image.
You can add the following optional parameters:

  • add_noise (bool) add noise to the CAPTCHA image
  • only_digits (bool) only use ditgits instead of hexdigits for the CAPTCHA code
  • timeout (float) set new timeout because the previous is canceled. If not set it will captcha_manager.default_timeout (if set).
# Handler for wrong solved CAPTCHAs
@captcha_manager.on_captcha_not_correct
def on_not_correct(captcha):
  # Check if only one dicit was incorrect and the user only did one try
  if (captcha.incorrect_digits == 1 and captcha.previous_tries < 2):
    # Refresh the CAPTCHA
    captcha_manager.refresh_captcha(bot, captcha)
  else:
    # We ban the chat member because he failed solving the CAPTCHA.
    bot.kick_chat_member(captcha.chat.id, captcha.user.id)
    bot.send_message(captcha.chat.id, f"{captcha.user.first_name} failed solving the CAPTCHA and was banned!")
    # Delete the CAPTCHA
    captcha_manager.delete_captcha(bot, captcha)

Now lets add a handler that handles timed out CAPTCHAs

# Handler for timed out CAPTCHAS
@captcha_manager.on_captcha_timeout
def on_timeout(captcha):
  # We ban the chat member because he did not solve the CAPTCHA.
  bot.kick_chat_member(captcha.chat.id, captcha.user.id)
  bot.send_message(captcha.chat.id, f"{captcha.user.first_name} did not solve the CAPTCHA and was banned!")
  # Delete the CAPTCHA
  captcha_manager.delete_captcha(bot, captcha)

The finished CAPTCHA bot

Now we only have to add the line bot.polling()at the end of our script and we have a finished CAPTCHA bot that looks like this:

from telebot import TeleBot
from pyTelegramBotCAPTCHA import CaptchaManager
                                                                    
bot = TeleBot("TOKEN")
captcha_manager = CaptchaManager(bot.get_me().id)

# Message handler for new chat members
@bot.message_handler(content_types=["new_chat_members"])
def new_member(message):
  new_user_id = message.json.get("new_chat_member").get("id")
  new_user = bot.get_chat_member(message.chat.id, new_user_id).user
  captcha_manager.restrict_chat_member(bot, message.chat.id, new_user.id)
  captcha_manager.send_random_captcha(bot, message.chat, new_user)
                                                                    
# Callback query handler
@bot.callback_query_handler(func=lambda callback:True)
def on_callback(callback):
  captcha_manager.update_captcha(bot, callback)
                                                                    
# Handler for correct solved CAPTCHAs
@captcha_manager.on_captcha_correct
def on_correct(captcha):
  bot.send_message(captcha.chat.id, "Congrats! You solved the CAPTCHA!")
  captcha_manager.unrestrict_chat_member(bot, captcha.chat.id, captcha.user.id)
  captcha_manager.delete_captcha(bot, captcha)

# Handler for wrong solved CAPTCHAs
@captcha_manager.on_captcha_not_correct
def on_not_correct(captcha):
  if (captcha.incorrect_digits == 1 and captcha.previous_tries < 2):
    captcha_manager.refresh_captcha(bot, captcha)
  else:
    bot.kick_chat_member(captcha.chat.id, captcha.user.id)
    bot.send_message(captcha.chat.id, f"{captcha.user.first_name} failed solving the CAPTCHA and was banned!")
    captcha_manager.delete_captcha(bot, captcha)
  
# Handler for timed out CAPTCHAS
@captcha_manager.on_captcha_timeout
def on_timeout(captcha):
  bot.kick_chat_member(captcha.chat.id, captcha.user.id)
  bot.send_message(captcha.chat.id, f"{captcha.user.first_name} did not solve the CAPTCHA and was banned!")
  captcha_manager.delete_captcha(bot, captcha)
  
bot.polling()
Comments
  • Issues with CustomLanguage parameters 'your_code' and 'try_again'

    Issues with CustomLanguage parameters 'your_code' and 'try_again'

    Let's take the following setup:

    languages = CustomLanguage() languages.text = "text" languages.try_again = "again" languages.wrong_user = "wrong" languages.too_short = "short" languages.your_code = "code"

    'try_again' is actually not shown when it should. You keep seeing 'text' on both a wrong attempt and a manual user refresh.

    'your_code' is also not shown when it should. You always see the default "Your Code:", and 'your_code' does show up but only on a wrong attempt or a manual user refresh (it is not visible on the initial captcha). However, "Your Code:" is still visible up to this point, so you actually see two lines, one time the default one, and one time the new custom one.

    bug 
    opened by tinderboxmedia 5
  • Inconsistency: A captcha reload on an incorrect submit has default values

    Inconsistency: A captcha reload on an incorrect submit has default values

    If an individual fails to solve the captcha and if another attempt is allowed, the captcha will refresh but it will override variables such as timeout, digits_only and add_noice. This feels like an inconsistency in the logic as a refresh should give a new captcha but with all the user declared variables and values. If the function is declared to not add_noice or to be digits_only, a refresh should not change this behaviour, unless declared otherwise.

    To fix this inconsistency the captcha refresh should either follow the user declared variables and values, or one should be able to allow this override to happen or not.

    enhancement 
    opened by tinderboxmedia 5
  • No timeout anymore when user has made a wrong attempt

    No timeout anymore when user has made a wrong attempt

    There seems to be an error where there is no timeout event anymore when a user made a wrong attempt, it also seems to not work anymore when a user manually refreshed the CAPTCHA. It still happens though when a user is still on the initial CAPTCHA. I tried this with the default timeout of 90, and a custom timeout. Note that max_incorrect_to_auto_reload has been set to 1, so a timeout should still happen.

    bug 
    opened by tinderboxmedia 4
  • Suggestion: Be able to declare the digits and hex-digits used in the captcha outside of the module

    Suggestion: Be able to declare the digits and hex-digits used in the captcha outside of the module

    Currently the only way to change the digits and hex-digits used in the captcha is to change variables inside of the module. The suggestion would be to be able to declare which digits or letters can be used, but still in a set of 10 (the 2 by 5 input markup grid), or a set of 16 (the 4x4 input markup grid).

    The main reason for this suggestion is that some fonts do have characters that could potentially look to similar. For example: 8 and B, or 1 and 7. Be able to declare a custom set of 10 or 16 characters, the captchas could become more user friendly but still bot proof.

    opened by tinderboxmedia 4
  • Suggestion: Be able to declare the length of the captcha

    Suggestion: Be able to declare the length of the captcha

    Currently the length of the captcha showed is defaulted and hardcoded to be 8 characters long. The suggestion would be to be able to declare the length of the captcha, so that it can display less or even more characters that need to be solved.

    enhancement 
    opened by tinderboxmedia 4
  • KeyZenD returns a 404. Fallback to 'Default' might be needed.

    KeyZenD returns a 404. Fallback to 'Default' might be needed.

    Seems like the KeyZenD CAPTCHA can't be found anymore: https://tyt.xyeta.ml/captcha.png

    This page returns an 404, and the CAPTCHA can't be found. Maybe it would be smart to add some sort of fallback that turns the option back to 'default' as currently this would break the entire thing?

    opened by tinderboxmedia 3
  • Issue: Adding 1+ users to the channel will only trigger 1 captcha

    Issue: Adding 1+ users to the channel will only trigger 1 captcha

    After some more stress testing it seems to be the case that if someone invites or adds more than 1 user (the option to mass invite your contacts to a channel for example) to the channel where the bot is active, it will only create 1 captcha. Only one user has to complete the captcha, the other users are already 'in' (so to speak).

    opened by tinderboxmedia 3
  • ERROR: TypeError: 'float' object cannot be interpreted as an integer

    ERROR: TypeError: 'float' object cannot be interpreted as an integer

    I try init a new bot with

    from telebot import TeleBot
    from pyTelegramBotCAPTCHA import CaptchaManager
                                                                        
    bot = TeleBot("MY_TOKEN")
    captcha_manager = CaptchaManager(bot.get_me().id)
    
    # Message handler for new chat members
    @bot.message_handler(content_types=["new_chat_members"])
    def new_member(message):
      for new_user in message.new_chat_members:
        captcha_manager.restrict_chat_member(bot, message.chat.id, new_user.id)
        captcha_manager.send_new_captcha(bot, message.chat, new_user)
                                                                        
    # Callback query handler
    @bot.callback_query_handler(func=lambda callback:True)
    def on_callback(callback):
      captcha_manager.update_captcha(bot, callback)
                                                                        
    # Handler for correct solved CAPTCHAs
    @captcha_manager.on_captcha_correct
    def on_correct(captcha):
      bot.send_message(captcha.chat.id, "Congrats! You solved the CAPTCHA!")
      captcha_manager.unrestrict_chat_member(bot, captcha.chat.id, captcha.user.id)
      captcha_manager.delete_captcha(bot, captcha)
    
    # Handler for wrong solved CAPTCHAs
    @captcha_manager.on_captcha_not_correct
    def on_not_correct(captcha):
      if (captcha.incorrect_digits == 1 and captcha.previous_tries < 2):
        captcha_manager.refresh_captcha(bot, captcha)
      else:
        bot.kick_chat_member(captcha.chat.id, captcha.user.id)
        bot.send_message(captcha.chat.id, f"{captcha.user.first_name} failed solving the CAPTCHA and was banned!")
        captcha_manager.delete_captcha(bot, captcha)
    
    # Handler for timed out CAPTCHAS
    @captcha_manager.on_captcha_timeout
    def on_timeout(captcha):
      bot.kick_chat_member(captcha.chat.id, captcha.user.id)
      bot.send_message(captcha.chat.id, f"{captcha.user.first_name} did not solve the CAPTCHA and was banned!")
      captcha_manager.delete_captcha(bot, captcha)
      
    bot.polling()
    

    And i take a error:

    Traceback (most recent call last):
      File "/Users/olivmath/repo/lunes/bot-telegram-cruzeiro/olivmath.py", line 43, in <module>
        bot.polling()
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/telebot/__init__.py", line 660, in polling
        self.__threaded_polling(non_stop, interval, timeout, long_polling_timeout, allowed_updates)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/telebot/__init__.py", line 722, in __threaded_polling
        raise e
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/telebot/__init__.py", line 682, in __threaded_polling
        self.worker_pool.raise_exceptions()
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/telebot/util.py", line 135, in raise_exceptions
        raise self.exception_info
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/telebot/util.py", line 87, in run
        task(*args, **kwargs)
      File "/Users/olivmath/repo/lunes/bot-telegram-cruzeiro/olivmath.py", line 12, in new_member
        captcha_manager.send_new_captcha(bot, message.chat, new_user)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/pyTelegramBotCAPTCHA/telebot_captcha.py", line 553, in send_new_captcha
        captcha = Captcha(bot, chat, user, options)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/pyTelegramBotCAPTCHA/telebot_captcha.py", line 345, in __init__
        self.correct_code, self.image = _random_codeimage(self.options)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/pyTelegramBotCAPTCHA/telebot_captcha.py", line 865, in _random_codeimage
        image = image.generate_image(code)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/captcha/image.py", line 228, in generate_image
        im = self.create_captcha_image(chars, color, background)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/captcha/image.py", line 212, in create_captcha_image
        mask = im.convert('L').point(table)
      File "/Users/olivmath/Library/Caches/pypoetry/virtualenvs/bot-telegram-cruzeiro-rcJnbm2r-py3.10/lib/python3.10/site-packages/PIL/Image.py", line 1680, in point
        return self._new(self.im.point(lut, mode))
    TypeError: 'float' object cannot be interpreted as an integer
    
    opened by olivmath 2
  • Refresh button

    Refresh button

    Hi there,

    Great work - loving your captcha bot! I had one idea that would be great to implement. A Refresh button in case the captcha is really hard / barley readable.

    Keep it up!

    enhancement good first issue 
    opened by fabston 2
  • Issue: Adding the code_length argument to send_random_captcha will throw a TypeError.

    Issue: Adding the code_length argument to send_random_captcha will throw a TypeError.

    For example, trying initialize the captcha using captcha_manager.send_random_captcha(bot, message.chat, new_user, timeout=60, code_length=4, language="en") will result in TypeError: send_random_captcha() got an unexpected keyword argument 'code_length'

    However, following the documentation this should be possible.

    opened by tinderboxmedia 2
  • Issue: If a captcha is not properly removed after kicking a user, it will throw a KeyError when trying to interact with it again

    Issue: If a captcha is not properly removed after kicking a user, it will throw a KeyError when trying to interact with it again

    While interacting with a captcha button (update_captcha), it should first be checked if that captcha session is still 'available' or not. It not being 'available' can be due to that the captcha message was not deleted properly after kicking a user and that user did not solve it, or that the file that holds that captcha session is somehow removed.

    Right now it will throw a KeyError if the session can't be found, but if we can check if that captcha session is not available anymore, we could just remove the captcha instead (whoever presses it) and clean up.

    opened by tinderboxmedia 2
Releases(1.1.4)
A python script based on opencv and paddleocr, which can automatically pick up tasks, make cookies, and receive rewards in the Destiny 2 Dawning Oven

A python script based on opencv and paddleocr, which can automatically pick up tasks, make cookies, and receive rewards in the Destiny 2 Dawning Oven

1 Dec 22, 2021
Fatigue Driving Detection Based on Dlib

Fatigue Driving Detection Based on Dlib

5 Dec 14, 2022
OCR software for recognition of handwritten text

Handwriting OCR The project tries to create software for recognition of a handwritten text from photos (also for Czech language). It uses computer vis

Břetislav Hájek 562 Jan 03, 2023
Repository collecting all the submodules for the new PyTorch-based OCR System.

OCRopus3 is being replaced by OCRopus4, which is a rewrite using PyTorch 1.7; release should be soonish. Please check github.com/tmbdev/ocropus for up

NVIDIA Research Projects 138 Dec 09, 2022
A post-processing tool for scanned sheets of paper.

unpaper Originally written by Jens Gulden — see AUTHORS for more information. Licensed under GNU GPL v2 — see COPYING for more information. Overview u

27 Dec 07, 2022
A semi-automatic open-source tool for Layout Analysis and Region EXtraction on early printed books.

LAREX LAREX is a semi-automatic open-source tool for layout analysis on early printed books. It uses a rule based connected components approach which

162 Jan 05, 2023
Code for the paper: Fusformer: A Transformer-based Fusion Approach for Hyperspectral Image Super-resolution

Fusformer Code for the paper: "Fusformer: A Transformer-based Fusion Approach for Hyperspectral Image Super-resolution" Plateform Python 3.8.5 + Pytor

Jin-Fan Hu (胡锦帆) 11 Dec 12, 2022
Ackermann Line Follower Robot Simulation.

Ackermann Line Follower Robot This is a simulation of a line follower robot that works with steering control based on Stanley: The Robot That Won the

Lucas Mazzetto 2 Apr 16, 2022
Code for the AAAI 2018 publication "SEE: Towards Semi-Supervised End-to-End Scene Text Recognition"

SEE: Towards Semi-Supervised End-to-End Scene Text Recognition Code for the AAAI 2018 publication "SEE: Towards Semi-Supervised End-to-End Scene Text

Christian Bartz 572 Jan 05, 2023
Primary QPDF source code and documentation

QPDF QPDF is a command-line tool and C++ library that performs content-preserving transformations on PDF files. It supports linearization, encryption,

QPDF 2.2k Jan 04, 2023
Scan the MRZ code of a passport and extract the firstname, lastname, passport number, nationality, date of birth, expiration date and personal numer.

PassportScanner Works with 2 and 3 line identity documents. What is this With PassportScanner you can use your camera to scan the MRZ code of a passpo

Edwin Vermeer 441 Dec 24, 2022
Captcha Recognition

The objective of this project is to recognize the target numbers in the captcha images correctly which would tell us how good or bad a captcha system has been built.

Mohit Kaushik 5 Feb 20, 2022
a deep learning model for page layout analysis / segmentation.

OCR Segmentation a deep learning model for page layout analysis / segmentation. dependencies tensorflow1.8 python3 dataset: uw3-framed-lines-degraded-

99 Dec 12, 2022
Awesome anomaly detection in medical images

A curated list of awesome anomaly detection works in medical imaging, inspired by the other awesome-* initiatives.

Kang Zhou 57 Dec 19, 2022
A pure pytorch implemented ocr project including text detection and recognition

ocr.pytorch A pure pytorch implemented ocr project. Text detection is based CTPN and text recognition is based CRNN. More detection and recognition me

coura 444 Dec 30, 2022
scene-linear test images

Scene-Referred Image Collection A collection of OpenEXR Scene-Referred images, encoded as max 2048px width, DWAA 80 compression. All exrs are encoded

Gralk Klorggson 7 Aug 25, 2022
A community-supported supercharged version of paperless: scan, index and archive all your physical documents

Paperless-ngx Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep,

5.2k Jan 04, 2023
Code for CVPR 2022 paper "SoftGroup for Instance Segmentation on 3D Point Clouds"

SoftGroup We provide code for reproducing results of the paper SoftGroup for 3D Instance Segmentation on Point Clouds (CVPR 2022) Author: Thang Vu, Ko

Thang Vu 231 Dec 27, 2022
Code for the paper "Controllable Video Captioning with an Exemplar Sentence"

SMCG Code for the paper "Controllable Video Captioning with an Exemplar Sentence" Introduction We investigate a novel and challenging task, namely con

10 Dec 04, 2022
Textboxes implementation with Tensorflow (python)

tb_tensorflow A python implementation of TextBoxes Dependencies TensorFlow r1.0 OpenCV2 Code from Chaoyue Wang 03/09/2017 Update: 1.Debugging optimize

Jayne Shin (신재인) 20 May 31, 2019