Merge pull request #2537 from BEDOLAGA-DEV/fix/blacklist-middleware
fix: enforce blacklist via middleware
This commit is contained in:
@@ -61,6 +61,7 @@ from app.handlers.admin import (
|
||||
)
|
||||
from app.handlers.stars_payments import register_stars_handlers
|
||||
from app.middlewares.auth import AuthMiddleware
|
||||
from app.middlewares.blacklist import BlacklistMiddleware
|
||||
from app.middlewares.button_stats import ButtonStatsMiddleware
|
||||
from app.middlewares.display_name_restriction import DisplayNameRestrictionMiddleware
|
||||
from app.middlewares.global_error import GlobalErrorMiddleware
|
||||
@@ -119,6 +120,10 @@ async def setup_bot() -> tuple[Bot, Dispatcher]:
|
||||
dp.callback_query.middleware(LoggingMiddleware())
|
||||
dp.message.middleware(MaintenanceMiddleware())
|
||||
dp.callback_query.middleware(MaintenanceMiddleware())
|
||||
blacklist_middleware = BlacklistMiddleware()
|
||||
dp.message.middleware(blacklist_middleware)
|
||||
dp.callback_query.middleware(blacklist_middleware)
|
||||
dp.pre_checkout_query.middleware(blacklist_middleware)
|
||||
display_name_middleware = DisplayNameRestrictionMiddleware()
|
||||
dp.message.middleware(display_name_middleware)
|
||||
dp.callback_query.middleware(display_name_middleware)
|
||||
|
||||
@@ -12,6 +12,7 @@ from app.config import settings
|
||||
from app.database.crud.user import get_user_by_id
|
||||
from app.database.database import AsyncSessionLocal
|
||||
from app.database.models import User
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.maintenance_service import maintenance_service
|
||||
|
||||
from .auth.jwt_handler import get_token_payload
|
||||
@@ -104,6 +105,18 @@ async def get_current_cabinet_user(
|
||||
detail='User account is not active',
|
||||
)
|
||||
|
||||
# Check blacklist
|
||||
if user.telegram_id is not None:
|
||||
is_blacklisted, reason = await blacklist_service.is_user_blacklisted(user.telegram_id, user.username)
|
||||
if is_blacklisted:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail={
|
||||
'code': 'blacklisted',
|
||||
'message': reason or 'Доступ запрещен',
|
||||
},
|
||||
)
|
||||
|
||||
# Check maintenance mode (allow admins to pass)
|
||||
if maintenance_service.is_maintenance_active():
|
||||
# Проверяем админа по telegram_id ИЛИ email
|
||||
|
||||
@@ -8,7 +8,6 @@ from app.config import settings
|
||||
from app.database.models import User
|
||||
from app.keyboards.inline import get_back_keyboard
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.payment_service import PaymentService
|
||||
from app.states import BalanceStates
|
||||
from app.utils.decorators import error_handler
|
||||
@@ -126,23 +125,6 @@ async def process_cryptobot_payment_amount(
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Оплата невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
if not settings.is_cryptobot_enabled():
|
||||
|
||||
@@ -8,7 +8,6 @@ from app.database.models import User
|
||||
from app.external.telegram_stars import TelegramStarsService
|
||||
from app.keyboards.inline import get_back_keyboard
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.payment_service import PaymentService
|
||||
from app.states import BalanceStates
|
||||
from app.utils.decorators import error_handler
|
||||
@@ -94,23 +93,6 @@ async def process_stars_payment_amount(message: types.Message, db_user: User, am
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Оплата невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
if not settings.TELEGRAM_STARS_ENABLED:
|
||||
|
||||
@@ -10,7 +10,6 @@ from app.config import settings
|
||||
from app.database.models import User
|
||||
from app.keyboards.inline import get_back_keyboard
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.payment_service import PaymentService
|
||||
from app.states import BalanceStates
|
||||
from app.utils.decorators import error_handler
|
||||
@@ -171,23 +170,6 @@ async def process_yookassa_payment_amount(
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Оплата невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
if not settings.is_yookassa_enabled():
|
||||
@@ -338,23 +320,6 @@ async def process_yookassa_sbp_payment_amount(
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Оплата невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
if not settings.is_yookassa_enabled() or not settings.YOOKASSA_SBP_ENABLED:
|
||||
|
||||
@@ -9,7 +9,6 @@ from app.database.models import User
|
||||
from app.keyboards.inline import get_back_keyboard
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.admin_notification_service import AdminNotificationService
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.promocode_service import PromoCodeService
|
||||
from app.states import PromoCodeStates
|
||||
from app.utils.decorators import error_handler
|
||||
@@ -71,23 +70,6 @@ async def activate_promocode_for_registration(db: AsyncSession, user_id: int, co
|
||||
|
||||
@error_handler
|
||||
async def process_promocode(message: types.Message, db_user: User, state: FSMContext, db: AsyncSession):
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Активация промокода невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
code = message.text.strip()
|
||||
|
||||
@@ -35,7 +35,6 @@ from app.middlewares.channel_checker import (
|
||||
get_pending_payload_from_redis,
|
||||
)
|
||||
from app.services.admin_notification_service import AdminNotificationService
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.campaign_service import AdvertisingCampaignService
|
||||
from app.services.main_menu_button_service import MainMenuButtonService
|
||||
from app.services.pinned_message_service import (
|
||||
@@ -993,25 +992,6 @@ async def process_referral_code_skip(callback: types.CallbackQuery, state: FSMCo
|
||||
async def complete_registration_from_callback(callback: types.CallbackQuery, state: FSMContext, db: AsyncSession):
|
||||
logger.info(f'🎯 COMPLETE: Завершение регистрации для пользователя {callback.from_user.id}')
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
callback.from_user.id, callback.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {callback.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await callback.message.answer(
|
||||
f'🚫 Регистрация невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
existing_user = await get_user_by_telegram_id(db, callback.from_user.id)
|
||||
|
||||
if existing_user and existing_user.status == UserStatus.ACTIVE.value:
|
||||
@@ -1262,25 +1242,6 @@ async def complete_registration_from_callback(callback: types.CallbackQuery, sta
|
||||
async def complete_registration(message: types.Message, state: FSMContext, db: AsyncSession):
|
||||
logger.info(f'🎯 COMPLETE: Завершение регистрации для пользователя {message.from_user.id}')
|
||||
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
message.from_user.id, message.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await message.answer(
|
||||
f'🚫 Регистрация невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
existing_user = await get_user_by_telegram_id(db, message.from_user.id)
|
||||
|
||||
if existing_user and existing_user.status == UserStatus.ACTIVE.value:
|
||||
|
||||
@@ -39,7 +39,6 @@ from app.keyboards.inline import (
|
||||
)
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.admin_notification_service import AdminNotificationService
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
from app.services.remnawave_service import RemnaWaveConfigurationError
|
||||
from app.services.subscription_checkout_service import (
|
||||
clear_subscription_checkout_draft,
|
||||
@@ -1724,24 +1723,6 @@ async def handle_extend_subscription(callback: types.CallbackQuery, db_user: Use
|
||||
|
||||
|
||||
async def confirm_extend_subscription(callback: types.CallbackQuery, db_user: User, db: AsyncSession):
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
callback.from_user.id, callback.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {callback.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await callback.answer(
|
||||
f'🚫 Продление подписки невозможно\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.',
|
||||
show_alert=True,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
days = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
@@ -2228,24 +2209,6 @@ async def devices_continue(callback: types.CallbackQuery, state: FSMContext, db_
|
||||
|
||||
|
||||
async def confirm_purchase(callback: types.CallbackQuery, state: FSMContext, db_user: User, db: AsyncSession):
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
callback.from_user.id, callback.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {callback.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await callback.answer(
|
||||
f'🚫 Покупка подписки невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.',
|
||||
show_alert=True,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
# Проверка ограничения на покупку/продление подписки
|
||||
if getattr(db_user, 'restriction_subscription', False):
|
||||
reason = getattr(db_user, 'restriction_reason', None) or 'Действие ограничено администратором'
|
||||
@@ -4134,24 +4097,6 @@ async def handle_simple_subscription_purchase(
|
||||
db: AsyncSession,
|
||||
):
|
||||
"""Обрабатывает простую покупку подписки."""
|
||||
# Проверяем, находится ли пользователь в черном списке
|
||||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||||
callback.from_user.id, callback.from_user.username
|
||||
)
|
||||
|
||||
if is_blacklisted:
|
||||
logger.warning(f'🚫 Пользователь {callback.from_user.id} находится в черном списке: {blacklist_reason}')
|
||||
try:
|
||||
await callback.answer(
|
||||
f'🚫 Простая покупка подписки невозможна\n\n'
|
||||
f'Причина: {blacklist_reason}\n\n'
|
||||
f'Если вы считаете, что это ошибка, обратитесь в поддержку.',
|
||||
show_alert=True,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка при отправке сообщения о блокировке: {e}')
|
||||
return
|
||||
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
if not settings.SIMPLE_SUBSCRIPTION_ENABLED:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import logging
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Any
|
||||
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram.types import CallbackQuery, Message, PreCheckoutQuery, TelegramObject, User as TgUser
|
||||
|
||||
from app.services.blacklist_service import blacklist_service
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BlacklistMiddleware(BaseMiddleware):
|
||||
async def __call__(
|
||||
self,
|
||||
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
||||
event: TelegramObject,
|
||||
data: dict[str, Any],
|
||||
) -> Any:
|
||||
user: TgUser | None = None
|
||||
if isinstance(event, (Message, CallbackQuery, PreCheckoutQuery)):
|
||||
user = event.from_user
|
||||
|
||||
if not user or user.is_bot:
|
||||
return await handler(event, data)
|
||||
|
||||
is_blacklisted, reason = await blacklist_service.is_user_blacklisted(user.id, user.username)
|
||||
|
||||
if not is_blacklisted:
|
||||
return await handler(event, data)
|
||||
|
||||
logger.warning(f'🚫 Пользователь {user.id} (@{user.username}) из черного списка: {reason}')
|
||||
|
||||
block_text = (
|
||||
f'🚫 Доступ запрещен\n\nПричина: {reason}\n\nЕсли вы считаете, что это ошибка, обратитесь в поддержку.'
|
||||
)
|
||||
|
||||
try:
|
||||
if isinstance(event, Message):
|
||||
await event.answer(block_text)
|
||||
elif isinstance(event, CallbackQuery):
|
||||
await event.answer(block_text, show_alert=True)
|
||||
elif isinstance(event, PreCheckoutQuery):
|
||||
await event.answer(ok=False, error_message='Доступ запрещен')
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка отправки сообщения о блокировке пользователю {user.id}: {e}')
|
||||
|
||||
return None
|
||||
@@ -160,8 +160,9 @@ class BlacklistService:
|
||||
|
||||
# Проверяем по username, если он передан
|
||||
if username:
|
||||
username_lower = username.lower().lstrip('@')
|
||||
for bl_id, bl_username, bl_reason in self.blacklist_data:
|
||||
if bl_username and (bl_username == username or bl_username == f'@{username}'):
|
||||
if bl_username and bl_username.lower().lstrip('@') == username_lower:
|
||||
logger.info(
|
||||
f'Пользователь {username} ({telegram_id}) найден в черном списке по username: {bl_reason}'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user