How To Limit Access To A Telegram Bot
Asked Answered
M

7

30

When I send a message to my Telegram Bot, it responses with no problems.

I wanna limit the access such that me and only me can send message to it.

How can I do that?

Marlomarlon answered 12/2, 2016 at 17:18 Comment(0)
T
30

As this question is related to python-telegram-bot, information below is related to it:

When you add handlers to your bot's dispatcher, you can specify various pre-built filters (read more at docs, github) or you can create custom ones in order to filter incoming updates.

To limit access to a specific user, you need to add Filters.user(username="@telegramusername") when initializing handler, e.g.:

dispatcher.add_handler(CommandHandler("start", text_callback, Filters.user(username="@username")))

This handler will accept /start command only from user with username @username.

You can also specify user-id instead of username, which I would highly recommend, as latter is non-constant and can be changed over time.

Thrave answered 22/3, 2018 at 14:6 Comment(0)
V
13

Filter messages by field update.message.from.id

Venge answered 13/2, 2016 at 1:54 Comment(0)
R
11

Based on the python-telegram-bot code snippets, one can build a simple wrapper around the handler:

def restricted(func):
    """Restrict usage of func to allowed users only and replies if necessary"""
    @wraps(func)
    def wrapped(bot, update, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in conf['restricted_ids']:
            print("WARNING: Unauthorized access denied for {}.".format(user_id))
            update.message.reply_text('User disallowed.')
            return  # quit function
        return func(bot, update, *args, **kwargs)
    return wrapped

where conf['restricted_ids'] might be an id list, e.g. [11111111, 22222222].

So the usage would look like this:

@restricted
def bot_start(bot, update):
    """Send a message when the command /start is issued"""
    update.message.reply_text('Hi! This is {} speaking.'.format(bot.username))

Update | for functions and methods (DRY, python-telegram-bot version 12 and above)

The solution above cannot be used on methods inside classes (positional arguments change). For a while, I had just created an additional decorator for methods. However one would always need to keep in mind which decorator to use when.

Building on top of this solution, the following decorator class can be built:

class restricted(object):
    """
    Decorator class used to restrict usage of commands.
    Sends a "disallowed" reply if necessary. Works on functions and methods.
    """
    def __init__(self, func):
        self._func = func
        self._obj = None
        self._wrapped = None

    def __call__(self, *args, **kwargs):
        if not self._wrapped:
            if self._obj:
                self._wrapped = self._wrap_method(self._func)
                self._wrapped = partial(self._wrapped, self._obj)
            else:
                self._wrapped = self._wrap_function(self._func)
        return self._wrapped(*args, **kwargs)

    def __get__(self, obj, type_=None):
        self._obj = obj
        return self

    def _wrap_method(self, method): # Wrapper called in case of a method
        @wraps(method)
        def inner(self, *args, **kwargs): # `self` is the *inner* class' `self` here
            user_id = args[0].effective_user.id # args[0]: update
            if user_id not in cfg.RESTRICTED_IDS:
                print(f'Unauthorized access denied on {method.__name__} ' \
                    f'for {user_id} : {args[0].message.chat.username}.')
                args[0].message.reply_text('User disallowed.')
                return None # quit handling command
            return method(self, *args, **kwargs)
        return inner

    def _wrap_function(self, function): # Wrapper called in case of a function
        @wraps(function)
        def inner(*args, **kwargs): # `self` would be the *restricted* class' `self` here
            user_id = args[0].effective_user.id # args[0]: update
            if user_id not in cfg.RESTRICTED_IDS:
                print(f'Unauthorized access denied on {function.__name__} ' \
                    f'for {user_id} : {args[0].message.chat.username}.')
                args[0].message.reply_text('User disallowed.')
                return None # quit handling command
            return function(*args, **kwargs)
        return inner

This works then, as expected, on functions and methods. It's not entirely DRY (cf. comments), but at least self-contained.

Rozanna answered 24/2, 2019 at 17:40 Comment(1)
Best not to forget the imports you have used: from functools import partial, wrapsDockery
E
5

Start a conversation with your bot, and send it a message. This will queue up an updates for the bot containing the message and the chat ID for your conversation.

To view recent updates, you call the getUpdates method. This is done by making a HTTP GET request to the URL https://api.telegram.org/bot$TOKEN/getUpdates Where $TOKEN is the token provided by the BotFather. Something like:

"chat":{
        "id":12345,
        "first_name":"Bob",
        "last_name":"Jones",
        "username":"bjones",
        "type":"private"},
      "date":1452933785,
      "text":"Hi there, bot!"}}]}

Once you determined your chat id you can write a piece of code in your bot like:

id_a = [111111,2222222,3333333,4444444,5555555]

    def handle(msg):
        chat_id = msg['chat']['id']
        command = msg['text']
        sender = msg['from']['id']
     if sender in id_a:
    [...]
     else:
           bot.sendMessage(chat_id, 'Forbidden access!')
           bot.sendMessage(chat_id, sender)
Echevarria answered 16/12, 2016 at 13:20 Comment(0)
A
3

I ran into this question myself so I thought I might say how I did it with Python's python-telegram-bot. So, with the new release (Version 20) [some classes/functions have changed] you could do something such as:

async def restrict(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await context.bot.send_message(
        chat_id=update.effective_chat.id,
        text="There is no bot in Ba Sing Se."
    )

# Creating the Application
application = ApplicationBuilder().token(TOKEN).build()

# Restrict bot to the specified user_id
restrict_handler = MessageHandler(~ filters.User(USER_ID), restrict)
application.add_handler(restrict_handler)

See the github tutorial for the rest of the scaffolding, but this puts the restricted handlder first using a filter to effectively cut off access to any user who doesn't match the USER_ID you feed to it, and because it's first, all other handlers don't hit.

The other answers work well if you want to specifically restrict certain actions, but this is good for a blanket restriction. You could also just use a filter inside each action you want restricted.

Anemone answered 15/8, 2022 at 18:59 Comment(0)
I
2

in my case this idea helped, actually logic is pretty easy,maybe you will find it useful. I used a telebot module:

# list with an id's, type int
prmssn=[
    12345678,87654321
]

@bot.message_handler(content_types=['text'])
def handle_text(message):
    # get the user's id of a last message 
    u_id=message.chat.id
    # you can use print to find out an id's of those who're trying to write to your bot
    print(u_id)
    # we use a permission list to compare id, if id is in the perm. list bot is going to answer, otherwise it keeps silence
    if u_id in prmssn:
        # get user's message
        u_query=message.text.strip()
        # echo it back
        bot.send_message(message.chat.id, u_query)
Inoue answered 25/3, 2022 at 9:45 Comment(0)
I
1

Filtering by update.message.chat_id works for me. In order to find your chat id, send a message to your bot and browse to

https://api.telegram.org/bot$TOKEN/getUpdates

where $TOKEN is the bot token as provided by BotFather, as mentioned in the answer by fdicarlo, where you can find the chat id in the json structure.

Isreal answered 8/1, 2019 at 9:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.