From a9e111bd4f873ed897db63a2f1dff48daeea9fc9 Mon Sep 17 00:00:00 2001 From: Zakhar Izmaylov Date: Mon, 20 Jan 2025 22:27:39 +0300 Subject: [PATCH] Add captcha functionality to start command handler - Included captcha router in main handlers. - Integrated captcha generation in the start command, conditional on CAPTCHA_ENABLE setting. --- handlers/__init__.py | 2 ++ handlers/captcha.py | 76 ++++++++++++++++++++++++++++++++++++++++++++ handlers/start.py | 8 +++++ 3 files changed, 86 insertions(+) create mode 100644 handlers/captcha.py diff --git a/handlers/__init__.py b/handlers/__init__.py index 85ac4866..92c8292a 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -13,11 +13,13 @@ from .payments import router as payments_router from .profile import router as profile_router from .start import router as start_router from .user import router as user_router +from .captcha import router as captcha_router router = Router(name="handlers_main_router") router.include_routers( start_router, + captcha_router, profile_router, pay_router, donate_router, diff --git a/handlers/captcha.py b/handlers/captcha.py new file mode 100644 index 00000000..9f36cf63 --- /dev/null +++ b/handlers/captcha.py @@ -0,0 +1,76 @@ +import random +from typing import Any + +from aiogram import F, Router +from aiogram.fsm.context import FSMContext +from aiogram.types import CallbackQuery +from aiogram.utils.keyboard import InlineKeyboardBuilder + +from config import CAPTCHA_EMOJIS +from handlers.start import start_command +from logger import logger + +router = Router() + + +async def generate_captcha(state: FSMContext): + """Генерирует новую капчу и сохраняет правильный ответ в состоянии + + Пример словаря CAPTCHA_EMOJIS: + { + "🐶": "собаку", # Собака + "🐱": "кошку", # Кошка + "🐭": "мышь", # Мышь + "🐹": "хомяка", # Хомяк + "🐰": "кролика", # Кролик + ... + } + """ + # Выбираем случайный эмодзи и его описание из конфига + correct_emoji, correct_text = random.choice(list(CAPTCHA_EMOJIS.items())) + + # Получаем 3 случайных неправильных эмодзи + wrong_emojis = random.sample( + [e for e in CAPTCHA_EMOJIS.keys() if e != correct_emoji], 3 + ) + + # Создаем список всех эмодзи и перемешиваем их + all_emojis = [correct_emoji] + wrong_emojis + random.shuffle(all_emojis) + + # Сохраняем правильный ответ в состоянии + await state.update_data(correct_emoji=correct_emoji) + + # Создаем клавиатуру + builder = InlineKeyboardBuilder() + for emoji in all_emojis: + builder.button(text=emoji, callback_data=f"captcha_{emoji}") + builder.adjust(2, 2) + + return { + "text": f"🔒 Для подтверждения что вы не робот,\nвыберите кнопку с {correct_text}", + "markup": builder.as_markup() + } + + +@router.callback_query(F.data.startswith("captcha_")) +async def check_captcha( + callback: CallbackQuery, state: FSMContext, session: Any, admin: bool +): + """Проверяет ответ пользователя на капчу""" + selected_emoji = callback.data.split("captcha_")[1] + state_data = await state.get_data() + correct_emoji = state_data.get("correct_emoji") + + if selected_emoji == correct_emoji: + logger.info(f"Пользователь {callback.message.chat.id} успешно прошел капчу") + await callback.message.delete() + await start_command(callback.message, state, session, admin) + else: + logger.warning( + f"Пользователь {callback.message.chat.id} неверно ответил на капчу" + ) + captcha = await generate_captcha(state) + await callback.message.edit_text( + text=captcha["text"], reply_markup=captcha["markup"] + ) diff --git a/handlers/start.py b/handlers/start.py index d9c9ead5..070f57fa 100644 --- a/handlers/start.py +++ b/handlers/start.py @@ -21,6 +21,7 @@ from config import ( DOWNLOAD_ANDROID, DOWNLOAD_IOS, SUPPORT_CHAT_URL, + CAPTCHA_ENABLE, ) from database import ( add_connection, @@ -41,6 +42,7 @@ from handlers.keys.key_management import create_key from handlers.keys.trial_key import create_trial_key from handlers.texts import INSTRUCTIONS_TRIAL, WELCOME_TEXT, get_about_vpn from logger import logger +from handlers.captcha import generate_captcha router = Router() @@ -59,6 +61,12 @@ async def start_command(message: Message, state: FSMContext, session: Any, admin await state.clear() + # Проверка капчи, если включена + if CAPTCHA_ENABLE: + captcha = await generate_captcha(state) + await message.answer(text=captcha["text"], reply_markup=captcha["markup"]) + return + if message.text: try: connection_exists = await check_connection_exists(message.chat.id)