Heroku/hikka/modules/api_protection.py

754 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# ©️ Dan Gazizullin, 2021-2023
# This file is a part of Hikka Userbot
# 🌐 https://github.com/hikariatama/Hikka
# You can redistribute it and/or modify it under the terms of the GNU AGPLv3
# 🔑 https://www.gnu.org/licenses/agpl-3.0.html
import asyncio
import io
import json
import logging
import random
import time
from hikkatl.tl import functions
from hikkatl.tl.tlobject import TLRequest
from hikkatl.tl.types import Message
from hikkatl.utils import is_list_like
from .. import loader, utils
from ..inline.types import InlineCall
from ..web.debugger import WebDebugger
logger = logging.getLogger(__name__)
GROUPS = [
"auth",
"account",
"users",
"contacts",
"messages",
"updates",
"photos",
"upload",
"help",
"channels",
"bots",
"payments",
"stickers",
"phone",
"langpack",
"folders",
"stats",
]
CONSTRUCTORS = {
(lambda x: x[0].lower() + x[1:])(
method.__class__.__name__.rsplit("Request", 1)[0]
): method.CONSTRUCTOR_ID
for method in utils.array_sum(
[
[
method
for method in dir(getattr(functions, group))
if isinstance(method, TLRequest)
]
for group in GROUPS
]
)
}
@loader.tds
class APIRatelimiterMod(loader.Module):
"""Helps userbot avoid spamming Telegram API"""
strings = {
"name": "APILimiter",
"warning": (
"⚠️ <b>WARNING!</b>\n\nYour account exceeded the limit of requests,"
" specified in config. In order to prevent Telegram API Flood, userbot has"
" been <b>fully frozen</b> for {} seconds. Further info is provided in"
" attached file. \n\nIt is recommended to get help in"
" <code>{prefix}support</code> group!\n\nIf you think, that it is an"
" intended behavior, then wait until userbot gets unlocked and next time,"
" when you will be going to perform such an operation, use"
" <code>{prefix}suspend_api_protect</code> &lt;time in seconds&gt;"
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Invalid arguments</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>API Flood Protection"
" is disabled for {} seconds</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protection enabled</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protection"
" disabled</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Are you sure?</b>"
),
"_cfg_time_sample": "Time sample through which the bot will count requests",
"_cfg_threshold": "Threshold of requests to trigger protection",
"_cfg_local_floodwait": (
"Freeze userbot for this amount of time, if request limit exceeds"
),
"_cfg_forbidden_methods": (
"Forbid specified methods from being executed throughout external modules"
),
"btn_no": "🚫 No",
"btn_yes": "✅ Yes",
"web_pin": (
"🔓 <b>Click the button below to show Werkzeug debug PIN. Do not give it to"
" anyone.</b>"
),
"web_pin_btn": "🐞 Show Werkzeug PIN",
"proxied_url": "🌐 Proxied URL",
"local_url": "🏠 Local URL",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web debugger is"
" disabled, url is not available</b>"
),
}
strings_ru = {
"warning": (
"⚠️ <b>ВНИМАНИЕ!</b>\n\nАккаунт вышел за лимиты запросов, указанные в"
" конфиге. С целью предотвращения флуда Telegram API, юзербот был"
" <b>полностью заморожен</b> на {} секунд. Дополнительная информация"
" прикреплена в файле ниже. \n\nРекомендуется обратиться за помощью в"
" <code>{prefix}support</code> группу!\n\nЕсли ты считаешь, что это"
" запланированное поведение юзербота, просто подожди, пока закончится"
" таймер и в следующий раз, когда запланируешь выполнять такую"
" ресурсозатратную операцию, используй"
" <code>{prefix}suspend_api_protect</code> &lt;время в секундах&gt;"
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Неверные аргументы</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Защита API отключена"
" на {} секунд</b>"
),
"on": "<emoji document_id=5458450833857322148>👌</emoji> <b>Защита включена</b>",
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Защита отключена</b>"
),
"u_sure": "<emoji document_id=5312383351217201533>⚠️</emoji> <b>Ты уверен?</b>",
"_cfg_time_sample": (
"Временной промежуток, по которому будет считаться количество запросов"
),
"_cfg_threshold": "Порог запросов, при котором будет срабатывать защита",
"_cfg_local_floodwait": (
"Заморозить юзербота на это количество секунд, если лимит запросов превышен"
),
"_cfg_forbidden_methods": (
"Запретить выполнение указанных методов во всех внешних модулях"
),
"btn_no": "🚫 Нет",
"btn_yes": "✅ Да",
"web_pin": (
"🔓 <b>Нажми на кнопку ниже, чтобы показать Werkzeug debug PIN. Не давай его"
" никому.</b>"
),
"web_pin_btn": "🐞 Показать Werkzeug PIN",
"proxied_url": "🌐 Проксированная ссылка",
"local_url": "🏠 Локальная ссылка",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Веб-отладчик отключен,"
" ссылка недоступна</b>"
),
}
strings_fr = {
"warning": (
"⚠️ <b>ATTENTION!</b>\n\nLe compte a dépassé les limites de requêtes"
" spécifiées dans la configuration. En vue de prévenir le flood de"
" l'API Telegram, le userbot a été <b>complètement gelé</b> pendant {}"
" secondes. Des informations supplémentaires sont ajoutées dans le"
" fichier ci-dessous.\n\nIl est recommandé de contacter le groupe"
" <code>{prefix}support</code> pour obtenir de l'aide!\n\nSi vous"
" pensez que le comportement du userbot a été planifié, attendez"
" simplement que le minuteur se termine et, la prochaine fois que"
" vous prévoyez d'exécuter une opération aussi coûteuse en ressources,"
" utilisez <code>{prefix}suspend_api_protect</code> &lt;temps en"
" secondes&gt;"
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Arguments"
" invalides</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protection API"
" désactivée pendant {} secondes</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protection activée</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protection"
" désactivée</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Êtes-vous sûr?</b>"
),
"_cfg_time_sample": (
"Intervalle de temps sur lequel le nombre de demandes sera compté"
),
"_cfg_threshold": "Seuil de demandes auquel la protection sera déclenchée",
"_cfg_local_floodwait": (
"Geler le userbot pendant cette durée de secondes si la limite de"
" requêtes est dépassée"
),
"_cfg_forbidden_methods": (
"Interdire l'exécution des méthodes spécifiées dans tous les modules"
" externes"
),
"btn_no": "🚫 Non",
"btn_yes": "✅ Oui",
"web_pin": (
"🔓 <b>Cliquez sur le bouton ci-dessous pour afficher le code PIN de"
" débogage de Werkzeug. Ne le donnez pas à personne.</b>"
),
"web_pin_btn": "🐞 Afficher le code PIN de Werkzeug",
"proxied_url": "🌐 Lien de proxification",
"local_url": "🏠 Lien local",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Le débogueur Web est"
" désactivé, le lien n'est pas disponible</b>"
),
}
strings_it = {
"warning": (
"⚠️ <b>ATTENZIONE!</b>\n\nIl"
" tuo account è uscito dai limiti di richieste impostati nel file config."
" Per evitare flood di richieste, il bot è stato <b>completamente"
" sospeso</b> per {} secondi. Ulteriori informazioni sono disponibili nel"
" file allegato. \n\nTi consigliamo di unirti al gruppo"
" <code>{prefix}support</code> per ulteriore assistenza!\n\nSe ritieni che"
" questo sia un comportamento programmato del bot, puoi semplicemente"
" aspettare che il timer finisca e, in seguito, quando pianifichi di"
" eseguire operazioni così pesanti, usa"
" <code>{prefix}suspend_api_protect</code> &lt;tempo in secondi&gt;"
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Argomenti non"
" validi</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protezione API"
" disattivata per {} secondi</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protezione"
" attivata</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protezione"
" disattivata</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Sei sicuro?</b>"
),
"_cfg_time_sample": (
"Intervallo di tempo per il quale verranno conteggiate le richieste"
),
"_cfg_threshold": (
"Limite delle richieste, al di sopra del quale verrà attivato"
" il sistema di protezione"
),
"_cfg_local_floodwait": (
"Il bot verrà sospeso per questo numero di secondi se il limite delle"
" richieste viene superato"
),
"_cfg_forbidden_methods": (
"Vieta l'esecuzione di questi metodi in tutti i moduli esterni"
),
"btn_no": "🚫 No",
"btn_yes": "✅ Sì",
"web_pin": (
"🔓 <b>Premi il pulsante qui sotto per mostrare il PIN di debug di Werkzeug."
" Non darglielo a nessuno.</b>"
),
"web_pin_btn": "🐞 Mostra PIN di Werkzeug",
"proxied_url": "🌐 URL del proxy",
"local_url": "🏠 URL locale",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Il debugger web è"
" disabilitato, l'URL non è disponibile</b>"
),
}
strings_de = {
"warning": (
"⚠️ <b>Achtung!</b>\n\nDas Konto hat die in der Konfiguration angegebenen"
" Grenzwerte für Anfragen überschritten. Um Telegram API-Flooding zu"
" verhindern, wurde der <b>ganze Userbot</b> für {} Sekunden"
" eingefroren. Weitere Informationen finden Sie im unten angefügten"
" Datei.\n\nWir empfehlen Ihnen, sich mit Hilfe der <code>{prefix}"
"support</code> Gruppe zu helfen!\n\nWenn du denkst, dass dies"
" geplantes Verhalten des Userbots ist, dann warte einfach, bis der"
" Timer abläuft und versuche beim nächsten Mal, eine so ressourcen"
" intensive Operation wie <code>{prefix}suspend_api_protect</code>"
" &lt;Zeit in Sekunden&gt; zu planen."
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Ungültige"
" Argumente</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>API Flood"
" Protection ist für {} Sekunden deaktiviert</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Schutz aktiviert</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Schutz deaktiviert</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Bist du sicher?</b>"
),
"_cfg_time_sample": "Zeitintervall, in dem die Anfragen gezählt werden",
"_cfg_threshold": (
"Schwellenwert für Anfragen, ab dem der Schutz aktiviert wird"
),
"_cfg_local_floodwait": (
"Einfrieren des Userbots für diese Anzahl von Sekunden, wenn der Grenzwert"
" überschritten wird"
),
"_cfg_forbidden_methods": "Verbotene Methoden in allen externen Modulen",
"btn_no": "🚫 Nein",
"btn_yes": "✅ Ja",
"web_pin": (
"🔓 <b>Drücke auf die Schaltfläche unten, um den Werkzeug debug PIN"
" anzuzeigen. Gib ihn niemandem.</b>"
),
"web_pin_btn": "🐞 Werkzeug PIN anzeigen",
"proxied_url": "🌐 Proxied URL",
"local_url": "🏠 Lokale URL",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web-Debugger"
" deaktiviert, Link nicht verfügbar</b>"
),
}
strings_tr = {
"warning": (
"⚠️ <b>Dikkat!</b>\n\nHesap"
" yapılandırmasında belirtilen sınır değerlerini aştı. Telegram API"
" sızmalarını önlemek için <b>tüm Userbot</b> {} sanie donduruldu. Daha"
" fazla bilgi için aşağıya eklenen dosyaya bakın.\n\nLütfen"
" <code>{prefix}support</code> grubu ile yardım almak için destek"
" olun!\n\nEğer bu, Userbot'un planlanmış davranışı olduğunu"
" düşünüyorsanız, zamanlayıcı bittiğinde ve"
" <code>{prefix}suspend_api_protect</code> &lt;saniye cinsinden süre&gt;"
" gibi kaynak tüketen bir işlemi planladığınızda yeniden deneyin."
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Geçersiz"
" argümanlar</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>API Flood koruması {}"
" saniyeliğine durduruldu.</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Koruma"
" aktifleştirildi.</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Koruma"
" de-aktifleştirildi</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Emin misin?</b>"
),
"_cfg_time_sample": "Saniyede sayılan isteklerin zaman aralığı",
"_cfg_threshold": "Korumanın etkinleşeceği sınır değeri",
"_cfg_local_floodwait": (
"Telegram API sınır değeri aşıldığında kullanıcı botu bir süre durdurulur"
),
"_cfg_forbidden_methods": (
"Belirtili metodların harici modüller tarafından çalıştırılmasını yasakla"
),
"btn_no": "🚫 Hayır",
"btn_yes": "✅ Evet",
"web_pin": (
"🔓 <b>Werkzeug hata ayıklama PIN'ini göstermek için aşağıdaki düğmeyi"
" tıklayın. Onu kimseye vermeyin.</b>"
),
"web_pin_btn": "🐞 Werkzeug PIN'ini göster",
"proxied_url": "🌐 Proxied URL",
"local_url": "🏠 Lokal URL",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web-Debugger devre"
" dışı, bağlantı kullanılamaz</b>"
),
}
strings_uz = {
"warning": (
"⚠️ <b>Ogohlantirish!</b>\n\nBu hisob uchun konfiguratsiyada ko'rsatilgan"
" chegaralar chegarani o'zgartirgan.\n\nTelegram API Flood"
" to'xtatish uchun, bu <b>hammasi userbot</b> uchun {} sekundni"
" blokirovka qilindi. Batafsil ma'lumot uchun pastdagi faylni o'qing.\n\n"
"Yordam uchun <code>{prefix}support</code> guruhidan foydalaning!\n\nAgar"
" siz hisobni botning yordamchisi bo'lishi kerak bo'lgan amalni bajarishga"
" imkoniyat berishga o'xshaysiz, unda faqat blokirovkani to'xtatish uchun"
" <code>{prefix}suspend_api_protect</code> &lt;sekund&gt; dan foydalaning."
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Noto'g'ri argument</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>API Flood"
" himoya {} sekund uchun to'xtatildi</b>"
),
"on": "<emoji document_id=5458450833857322148>👌</emoji> <b>Himoya yoqildi</b>",
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Himoya o'chirildi</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Siz ishonchingiz"
" komilmi?</b>"
),
"_cfg_time_sample": "Sekundda qabul qilinadigan so'rovlar soni chegarasi",
"_cfg_threshold": "Himoya yoqish uchun qiymatni chegaralash",
"_cfg_local_floodwait": (
"Foydalanuvchi botni ushbu soniya davomida blokirovka qiladi, agar"
" chegaralar qiymati oshsa"
),
"_cfg_forbidden_methods": "Barcha tashqi modullarda taqiqlangan usullar",
"btn_no": "🚫 Yo'q",
"btn_yes": "✅ Ha",
"web_pin": (
"🔓 <b>Werkzeug Debug PIN kodini ko'rsatish uchun quyidagi tugmani bosing."
" Uni hech kimga bermang.</b>"
),
"web_pin_btn": "🐞 Werkzeug PIN-ni ko'rsatish",
"proxied_url": "🌐 Proxied URL",
"local_url": "🏠 Lokal URL",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web-Debugger"
" o'chirilgan, ulanish mavjud emas</b>"
),
}
strings_es = {
"warning": (
"⚠️ <b>¡Advertencia!</b>\n\nDe acuerdo con la configuración de esta cuenta,"
" las siguientes limitaciones serán aplicadas.\n\nSe bloqueará <b>a todos"
" los bots de los usuarios</b> por {} segundos para evitar el exceso de las"
" limitaciones de Telegram API. Para más información, consulta el archivo"
" siguiente.\n\nPara obtener ayuda, use el grupo"
" <code>{prefix}support</code>!\n\nPara permitir que la cuenta funcione,"
" use <code>{prefix}suspend_api_protect</code> para desbloquear."
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Argumentos"
" inválidos</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji>"
" <b>Se ha desactivado la protección de API por {} segundos</b>"
),
"on": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protección"
" activada</b>"
),
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Protección"
" desactivada</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>¿Estás seguro?</b>"
),
"_cfg_time_sample": (
"El tiempo en segundos durante el cual se exceden las limitaciones"
),
"_cfg_threshold": "El valor por encima del cual se exceden las limitaciones",
"_cfg_local_floodwait": (
"El tiempo en segundos durante el cual se bloquea al usuario para el bot"
),
"_cfg_forbidden_methods": (
"Los comandos prohibidos por todas las extensiones externas"
),
"btn_no": "🚫 No",
"btn_yes": "✅ Sí",
"web_pin": (
"🔓 <b>Haga clic en el botón de abajo para mostrar el PIN de depuración de"
" Werkzeug. No se lo des a nadie.</b>"
),
"web_pin_btn": "🐞 Mostrar el PIN de Werkzeug",
"proxied_url": "🌐 URL de proxy",
"local_url": "🏠 URL local",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web-Debugger"
" desactivado, conexión no disponible</b>"
),
}
strings_kk = {
"warning": (
"⚠️ <b>Ескерту!</b>\n\nБұл есептің конфигурациясына сәйкес, келесі"
" шектелген шарттар қолданылады.\n\nTelegram API үлеслерінен қорғалмасы"
" үшін, <b>барлық пайдаланушылардың боттары</b> {} секунд құлыпталады."
" Көбірек ақпарат үшін келесі файлды қараңыз.\n\nАнықтама үшін"
" <code>{prefix}support</code> топын пайдаланыңыз!\n\nЕгер сізге"
" бұл есептің боттың көмекшісі болуы керек болса, құлыпталуын өшіру үшін"
" <code>{prefix}suspend_api_protect</code> &lt;секунд&gt; пайдаланыңыз."
),
"args_invalid": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Жарамсыз"
" аргументтер</b>"
),
"suspended_for": (
"<emoji document_id=5458450833857322148>👌</emoji>"
" <b>API үлеслерін қорғалуы {} секунд үшін өшірілді</b>"
),
"on": "<emoji document_id=5458450833857322148>👌</emoji> <b>Қорғалу қосылды</b>",
"off": (
"<emoji document_id=5458450833857322148>👌</emoji> <b>Қорғалу өшірілді</b>"
),
"u_sure": (
"<emoji document_id=5312383351217201533>⚠️</emoji> <b>Сіз әлімдісіз бе?</b>"
),
"_cfg_time_sample": "API үлеслерінен қорғалуы үшін көрсетілген уақыт (секунд)",
"_cfg_threshold": "API үлеслерінен қорғалуы үшін көрсетілген қаншалық",
"_cfg_local_floodwait": "Бот үшін пайдаланушыны құлыпталу уақыты (секунд)",
"_cfg_forbidden_methods": (
"Барлық сыртқы қосымшалардың қолданылуының тыйым салынған командалары"
),
"btn_no": "🚫 Жоқ",
"btn_yes": "✅ Иә",
"web_pin": (
"🔓 <b>Werkzeug дебаг PIN кодын көрсету үшін төмендегі түймешікті"
" басыңыз. Оны кімсіне де бермеңіз.</b>"
),
"web_pin_btn": "🐞 Werkzeug PIN кодын көрсету",
"proxied_url": "🌐 Прокси URL",
"local_url": "🏠 Жергілікті URL",
"debugger_disabled": (
"<emoji document_id=5312526098750252863>🚫</emoji> <b>Web-Debugger"
" өшірілген, байланыс жоқ</b>"
),
}
_ratelimiter = []
_suspend_until = 0
_lock = False
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"time_sample",
15,
lambda: self.strings("_cfg_time_sample"),
validator=loader.validators.Integer(minimum=1),
),
loader.ConfigValue(
"threshold",
100,
lambda: self.strings("_cfg_threshold"),
validator=loader.validators.Integer(minimum=10),
),
loader.ConfigValue(
"local_floodwait",
30,
lambda: self.strings("_cfg_local_floodwait"),
validator=loader.validators.Integer(minimum=10, maximum=3600),
),
loader.ConfigValue(
"forbidden_methods",
["joinChannel", "importChatInvite"],
lambda: self.strings("_cfg_forbidden_methods"),
validator=loader.validators.MultiChoice(
[
"sendReaction",
"joinChannel",
"importChatInvite",
]
),
on_change=lambda: self._client.forbid_constructors(
map(
lambda x: CONSTRUCTORS[x], self.config["forbidden_constructors"]
)
),
),
)
async def client_ready(self):
asyncio.ensure_future(self._install_protection())
async def _install_protection(self):
await asyncio.sleep(30) # Restart lock
if hasattr(self._client._call, "_old_call_rewritten"):
raise loader.SelfUnload("Already installed")
old_call = self._client._call
async def new_call(
sender: "MTProtoSender", # type: ignore # noqa: F821
request: TLRequest,
ordered: bool = False,
flood_sleep_threshold: int = None,
):
await asyncio.sleep(random.randint(1, 5) / 100)
req = (request,) if not is_list_like(request) else request
for r in req:
if (
time.perf_counter() > self._suspend_until
and not self.get(
"disable_protection",
True,
)
and (
r.__module__.rsplit(".", maxsplit=1)[1]
in {"messages", "account", "channels"}
)
):
request_name = type(r).__name__
self._ratelimiter += [[request_name, time.perf_counter()]]
self._ratelimiter = list(
filter(
lambda x: time.perf_counter() - x[1]
< int(self.config["time_sample"]),
self._ratelimiter,
)
)
if (
len(self._ratelimiter) > int(self.config["threshold"])
and not self._lock
):
self._lock = True
report = io.BytesIO(
json.dumps(
self._ratelimiter,
indent=4,
).encode("utf-8")
)
report.name = "local_fw_report.json"
await self.inline.bot.send_document(
self.tg_id,
report,
caption=self.inline.sanitise_text(
self.strings("warning").format(
self.config["local_floodwait"],
prefix=self.get_prefix(),
)
),
)
# It is intented to use time.sleep instead of asyncio.sleep
time.sleep(int(self.config["local_floodwait"]))
self._lock = False
return await old_call(sender, request, ordered, flood_sleep_threshold)
self._client._call = new_call
self._client._old_call_rewritten = old_call
self._client._call._hikka_overwritten = True
logger.debug("Successfully installed ratelimiter")
async def on_unload(self):
if hasattr(self._client, "_old_call_rewritten"):
self._client._call = self._client._old_call_rewritten
delattr(self._client, "_old_call_rewritten")
logger.debug("Successfully uninstalled ratelimiter")
@loader.command(
ru_doc="<время в секундах> - Заморозить защиту API на N секунд",
fr_doc="<secondes> - Congeler la protection de l'API pendant N secondes",
it_doc="<tempo in secondi> - Congela la protezione API per N secondi",
de_doc="<Sekunden> - API-Schutz für N Sekunden einfrieren",
tr_doc="<saniye> - API korumasını N saniye dondur",
uz_doc="<soniya> - API himoyasini N soniya o'zgartirish",
es_doc="<segundos> - Congela la protección de la API durante N segundos",
kk_doc="<секунд> - API қорғауын N секундтік уақытта құлыптау",
)
async def suspend_api_protect(self, message: Message):
"""<time in seconds> - Suspend API Ratelimiter for n seconds"""
args = utils.get_args_raw(message)
if not args or not args.isdigit():
await utils.answer(message, self.strings("args_invalid"))
return
self._suspend_until = time.perf_counter() + int(args)
await utils.answer(message, self.strings("suspended_for").format(args))
@loader.command(
ru_doc="Включить/выключить защиту API",
fr_doc="Activer / désactiver la protection de l'API",
it_doc="Attiva/disattiva la protezione API",
de_doc="API-Schutz einschalten / ausschalten",
tr_doc="API korumasını aç / kapat",
uz_doc="API himoyasini yoqish / o'chirish",
es_doc="Activar / desactivar la protección de API",
kk_doc="API қорғауын қосу / жою",
)
async def api_fw_protection(self, message: Message):
"""Toggle API Ratelimiter"""
await self.inline.form(
message=message,
text=self.strings("u_sure"),
reply_markup=[
{"text": self.strings("btn_no"), "action": "close"},
{"text": self.strings("btn_yes"), "callback": self._finish},
],
)
@property
def _debugger(self) -> WebDebugger:
return logging.getLogger().handlers[0].web_debugger
async def _show_pin(self, call: InlineCall):
await call.answer(f"Werkzeug PIN: {self._debugger.pin}", show_alert=True)
@loader.command(
ru_doc="Показать PIN Werkzeug",
fr_doc="Afficher le PIN Werkzeug",
it_doc="Mostra il PIN Werkzeug",
de_doc="PIN-Werkzeug anzeigen",
tr_doc="PIN aracını göster",
uz_doc="PIN vositasi ko'rsatish",
es_doc="Mostrar herramienta PIN",
kk_doc="PIN құралын көрсету",
)
async def debugger(self, message: Message):
"""Show the Werkzeug PIN"""
await self.inline.form(
message=message,
text=self.strings("web_pin"),
reply_markup=[
[
{
"text": self.strings("web_pin_btn"),
"callback": self._show_pin,
}
],
[
{"text": self.strings("proxied_url"), "url": self._debugger.url},
{
"text": self.strings("local_url"),
"url": f"http://127.0.0.1:{self._debugger.port}",
},
],
],
)
async def _finish(self, call: InlineCall):
state = self.get("disable_protection", True)
self.set("disable_protection", not state)
await call.edit(self.strings("on" if state else "off"))