155 lines
6.1 KiB
Python
155 lines
6.1 KiB
Python
|
|
import discord
|
||
|
|
from discord.ext import commands
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import asyncio
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
SETTINGS_FILE = "data/security_settings.json"
|
||
|
|
WHITELIST_FILE = "data/whitelist.json"
|
||
|
|
|
||
|
|
class AntiSpam(commands.Cog):
|
||
|
|
def __init__(self, bot):
|
||
|
|
self.bot = bot
|
||
|
|
# Compteurs pour le Spam
|
||
|
|
self.message_counts = {}
|
||
|
|
self.spam_warnings = {}
|
||
|
|
|
||
|
|
# Compteurs pour les Liens
|
||
|
|
self.link_warnings = {}
|
||
|
|
|
||
|
|
def is_whitelisted(self, guild_id, user_id):
|
||
|
|
"""Vérifie si l'utilisateur est protégé (Whitelist ou Owner)"""
|
||
|
|
# 1. Le propriétaire est toujours whitelist
|
||
|
|
guild = self.bot.get_guild(guild_id)
|
||
|
|
if guild and user_id == guild.owner_id:
|
||
|
|
return True
|
||
|
|
|
||
|
|
# 2. Vérification fichier Whitelist
|
||
|
|
if not os.path.exists(WHITELIST_FILE): return False
|
||
|
|
try:
|
||
|
|
with open(WHITELIST_FILE, "r", encoding='utf-8') as f:
|
||
|
|
data = json.load(f)
|
||
|
|
return user_id in data.get(str(guild_id), [])
|
||
|
|
except: return False
|
||
|
|
|
||
|
|
@commands.Cog.listener()
|
||
|
|
async def on_message(self, message):
|
||
|
|
if message.author.bot or not message.guild: return
|
||
|
|
|
||
|
|
# --- 1. IMMUNITÉ TOTALE ---
|
||
|
|
# Si Whitelisté, on ignore tout (Spam et Liens)
|
||
|
|
if self.is_whitelisted(message.guild.id, message.author.id):
|
||
|
|
return
|
||
|
|
|
||
|
|
# --- 2. CHARGEMENT CONFIG ---
|
||
|
|
if not os.path.exists(SETTINGS_FILE): return
|
||
|
|
with open(SETTINGS_FILE, "r", encoding='utf-8') as f:
|
||
|
|
settings = json.load(f).get(str(message.guild.id), {})
|
||
|
|
|
||
|
|
# =================================================================
|
||
|
|
# MODULE ANTI-LINK (3 Avertissements -> Mute)
|
||
|
|
# =================================================================
|
||
|
|
if settings.get("anti_link"):
|
||
|
|
# Liste des déclencheurs interdits
|
||
|
|
forbidden = ["discord.gg/", "http://", "https://", "www."]
|
||
|
|
|
||
|
|
# On vérifie si le message contient un lien interdit
|
||
|
|
if any(trigger in message.content.lower() for trigger in forbidden):
|
||
|
|
# Si l'auteur a la permission de gérer les messages, on laisse passer (optionnel, sinon retirer cette ligne)
|
||
|
|
if not message.author.guild_permissions.manage_messages:
|
||
|
|
await self.handle_link_violation(message)
|
||
|
|
return # On arrête là, pas besoin de vérifier le spam si le message est supprimé
|
||
|
|
|
||
|
|
# =================================================================
|
||
|
|
# MODULE ANTI-SPAM (3 Avertissements -> Mute)
|
||
|
|
# =================================================================
|
||
|
|
if settings.get("anti_spam"):
|
||
|
|
user_id = message.author.id
|
||
|
|
now = datetime.now().timestamp()
|
||
|
|
|
||
|
|
if user_id not in self.message_counts:
|
||
|
|
self.message_counts[user_id] = []
|
||
|
|
|
||
|
|
self.message_counts[user_id].append(now)
|
||
|
|
# Fenêtre de temps : 5 secondes
|
||
|
|
self.message_counts[user_id] = [t for t in self.message_counts[user_id] if now - t < 5]
|
||
|
|
|
||
|
|
# Seuil dynamique (défaut: 5)
|
||
|
|
limit = settings.get("spam_threshold", 5)
|
||
|
|
|
||
|
|
if len(self.message_counts[user_id]) > limit:
|
||
|
|
await self.handle_spam_violation(message)
|
||
|
|
|
||
|
|
|
||
|
|
# --- GESTION DES VIOLATIONS LIENS ---
|
||
|
|
async def handle_link_violation(self, message):
|
||
|
|
try:
|
||
|
|
await message.delete()
|
||
|
|
except:
|
||
|
|
pass # Message déjà supprimé ou manque de perms
|
||
|
|
|
||
|
|
user_id = message.author.id
|
||
|
|
warnings = self.link_warnings.get(user_id, 0) + 1
|
||
|
|
self.link_warnings[user_id] = warnings
|
||
|
|
|
||
|
|
if warnings <= 3:
|
||
|
|
embed = discord.Embed(
|
||
|
|
title="🔗 Liens Interdits",
|
||
|
|
description=f"{message.author.mention}, les liens ne sont pas autorisés.\n**Avertissement : {warnings}/3**",
|
||
|
|
color=0xFFA500
|
||
|
|
)
|
||
|
|
await message.channel.send(embed=embed, delete_after=5)
|
||
|
|
else:
|
||
|
|
await self.sanction_user(message, "Publication de liens interdits")
|
||
|
|
self.link_warnings[user_id] = 0 # Reset après sanction
|
||
|
|
|
||
|
|
# --- GESTION DES VIOLATIONS SPAM ---
|
||
|
|
async def handle_spam_violation(self, message):
|
||
|
|
user_id = message.author.id
|
||
|
|
|
||
|
|
# Nettoyage visuel du spam
|
||
|
|
try:
|
||
|
|
await message.channel.purge(limit=5, check=lambda m: m.author == message.author)
|
||
|
|
except: pass
|
||
|
|
|
||
|
|
warnings = self.spam_warnings.get(user_id, 0) + 1
|
||
|
|
self.spam_warnings[user_id] = warnings
|
||
|
|
|
||
|
|
# Reset le compteur de messages pour éviter le spam d'avertissements
|
||
|
|
self.message_counts[user_id] = []
|
||
|
|
|
||
|
|
if warnings <= 3:
|
||
|
|
embed = discord.Embed(
|
||
|
|
title="🛡️ Anti-Spam",
|
||
|
|
description=f"{message.author.mention}, veuillez cesser de spammer.\n**Avertissement : {warnings}/3**",
|
||
|
|
color=0xFFA500
|
||
|
|
)
|
||
|
|
await message.channel.send(embed=embed, delete_after=5)
|
||
|
|
else:
|
||
|
|
await self.sanction_user(message, "Spam excessif")
|
||
|
|
self.spam_warnings[user_id] = 0 # Reset après sanction
|
||
|
|
|
||
|
|
# --- SANCTION COMMUNE (TIMEOUT 5 MIN) ---
|
||
|
|
async def sanction_user(self, message, reason):
|
||
|
|
try:
|
||
|
|
# Durée : 5 minutes
|
||
|
|
duration = discord.utils.utcnow() + asyncio.timedelta(minutes=5)
|
||
|
|
|
||
|
|
# Application du Timeout (Exclusion temporaire)
|
||
|
|
await message.author.timeout(duration, reason=f"Kuby Security: {reason} (3 Warns)")
|
||
|
|
|
||
|
|
embed = discord.Embed(
|
||
|
|
title="⛔ Exclusion Temporaire",
|
||
|
|
description=f"**Utilisateur :** {message.author.mention}\n**Durée :** 5 minutes\n**Raison :** {reason} (Limite atteinte).",
|
||
|
|
color=0xFF0000
|
||
|
|
)
|
||
|
|
await message.channel.send(embed=embed)
|
||
|
|
|
||
|
|
except discord.Forbidden:
|
||
|
|
await message.channel.send("⚠️ Je n'ai pas la permission d'exclure ce membre (Vérifiez ma hiérarchie).")
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Erreur Sanction: {e}")
|
||
|
|
|
||
|
|
async def setup(bot):
|
||
|
|
await bot.add_cog(AntiSpam(bot))
|