from __future__ import annotations import logging from datetime import datetime, timedelta, timezone import discord from discord import app_commands from discord.ext import commands from features import shared logger = logging.getLogger("vision") _raids: dict[int, list[tuple[datetime, str]]] = {} class Security(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot @commands.Cog.listener() async def on_member_join(self, member: discord.Member): cfg = shared.section(member.guild.id, "security") if not cfg.get("antiraid"): return now = datetime.now(timezone.utc) raids = _raids.setdefault(member.guild.id, []) raids.append((now, str(member.id))) cutoff = now - timedelta(seconds=cfg.get("antiraid_window", 10)) _raids[member.guild.id] = [(t, uid) for t, uid in raids if t > cutoff] threshold = cfg.get("antiraid_threshold", 5) if len(_raids[member.guild.id]) >= threshold: try: await member.guild.edit(verification_level=discord.VerificationLevel.highest) embed = discord.Embed( title="🛡️ Alerte Antiraid", description=f"**{len(_raids[member.guild.id])}** membres en {cfg.get('antiraid_window', 10)}s.\n" f"**Verification_level** augmenté automatiquement.", color=discord.Color.red(), ) if cfg.get("log_channel_id"): ch = member.guild.get_channel(cfg["log_channel_id"]) if ch: await ch.send(embed=embed) except discord.HTTPException: pass _raids[member.guild.id] = [] @commands.Cog.listener() async def on_member_ban(self, guild: discord.Guild, user: discord.User | discord.Member): cfg = shared.section(guild.id, "security") if not cfg.get("ban_protection"): return embed = discord.Embed( title="🔨 Protection Ban", description=f"**{user}** a été banni de **{guild.name}**", color=discord.Color.orange(), ) if cfg.get("log_channel_id"): ch = guild.get_channel(cfg["log_channel_id"]) if ch: await ch.send(embed=embed) @commands.Cog.listener() async def on_member_remove(self, member: discord.Member): cfg = shared.section(member.guild.id, "security") if not cfg.get("join_leave_log"): return embed = discord.Embed( title="📥 Départ", description=f"**{member}** a quitté **{member.guild.name}**", color=discord.Color.grey(), timestamp=datetime.now(timezone.utc), ) if cfg.get("log_channel_id"): ch = member.guild.get_channel(cfg["log_channel_id"]) if ch: await ch.send(embed=embed) @app_commands.command(name="security_setup", description="Configurer la sécurité") @app_commands.describe(log_channel="Canal de logs", antiraid_threshold="Seuil antiraid (membres/10s)") @app_commands.checks.has_permissions(manage_guild=True) async def security_setup( self, interaction: discord.Interaction, log_channel: discord.TextChannel, antiraid_threshold: int = 5 ): cfg = shared.get(interaction.guild_id, "security") cfg["enabled"] = True cfg["log_channel_id"] = log_channel.id cfg["antiraid"] = True cfg["antiraid_threshold"] = antiraid_threshold cfg["antiraid_window"] = 10 cfg["ban_protection"] = True cfg["join_leave_log"] = True shared.set(interaction.guild_id, "security", cfg) await interaction.response.send_message( f"Sécurité activée. Logs dans {log_channel.mention}. Seuil antiraid : {antiraid_threshold} membres / 10s.", ephemeral=True, ) async def setup(bot: commands.Bot): await bot.add_cog(Security(bot))