Files
Solo_bot/middlewares/direct_start_blocker.py
T
2025-12-07 00:32:43 +03:00

85 lines
3.0 KiB
Python

import time
from collections.abc import Awaitable, Callable
from typing import Any
from aiogram import BaseMiddleware
from aiogram.types import Message, Update
from config import DISABLE_DIRECT_START
from core.bootstrap import MODES_CONFIG
from database import async_session_maker, check_user_exists
from logger import logger
_TTL = 20
_cache_user_exists: dict[int, tuple[float, bool]] = {}
class DirectStartBlockerMiddleware(BaseMiddleware):
def __init__(self) -> None:
self.allowed_prefixes = ("gift_", "referral_", "coupons_", "utm", "partner_")
async def __call__(
self,
handler: Callable[[Update, dict[str, Any]], Awaitable[Any]],
event: Update,
data: dict[str, Any],
) -> Any:
direct_start_disabled = bool(MODES_CONFIG.get("DIRECT_START_DISABLED", DISABLE_DIRECT_START))
if not direct_start_disabled:
return await handler(event, data)
message: Message | None = getattr(event, "message", None)
if not message or not message.text:
return await handler(event, data)
fsm = data.get("state")
if fsm:
current_state = await fsm.get_state()
if current_state:
return await handler(event, data)
tg_id = message.from_user.id
text = message.text.strip()
now = time.time()
async def user_exists_cached() -> bool:
cached = _cache_user_exists.get(tg_id)
if cached and cached[0] > now:
return cached[1]
async with async_session_maker() as session:
exists = await check_user_exists(session, tg_id)
_cache_user_exists[tg_id] = (now + _TTL, exists)
return exists
if not text.startswith("/"):
if await user_exists_cached():
return await handler(event, data)
return
parts = text.split(maxsplit=1)
if parts[0] != "/start":
if await user_exists_cached():
return await handler(event, data)
logger.info(
f"[DirectStartBlocker] Команда '{text}' отклонена для незарегистрированного пользователя {tg_id}"
)
return
if len(parts) == 1:
if await user_exists_cached():
return await handler(event, data)
logger.info(f"[DirectStartBlocker] Прямой старт запрещён для нового пользователя {tg_id}")
return
start_param = parts[1].strip()
if not start_param or not start_param.startswith(self.allowed_prefixes):
if await user_exists_cached():
return await handler(event, data)
logger.info(f"[DirectStartBlocker] Отклонена неизвестная ссылка от {tg_id}: {start_param!r}")
return
logger.info(f"[DirectStartBlocker] Разрешённая ссылка от {tg_id}: {start_param!r}")
return await handler(event, data)