import hashlib from fastapi import HTTPException, status from redis.exceptions import RedisError from app.config.settings import settings from app.utils.redis_client import get_redis_client def _hash_text(text: str) -> str: return hashlib.sha256(text.encode("utf-8")).hexdigest() async def enforce_message_spam_policy(*, user_id: int, chat_id: int, text: str | None) -> None: redis = get_redis_client() rate_key = f"spam:msg_rate:{user_id}:{chat_id}" try: count = await redis.incr(rate_key) if count == 1: await redis.expire(rate_key, 60) if count > settings.message_rate_limit_per_minute: raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="Message rate limit exceeded for this chat.", ) normalized = (text or "").strip() if normalized: dup_key = f"spam:dup:{user_id}:{chat_id}:{_hash_text(normalized)}" if await redis.exists(dup_key): raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="Duplicate message cooldown is active.", ) await redis.set(dup_key, "1", ex=settings.duplicate_message_cooldown_seconds) except RedisError: return