diff --git a/bridget/cogs/antiraid.py b/bridget/cogs/antiraid.py index f0a5bf3..9d20206 100644 --- a/bridget/cogs/antiraid.py +++ b/bridget/cogs/antiraid.py @@ -11,11 +11,11 @@ from bridget.utils.enums import PermissionLevel from bridget.utils.pfpcalc import calculate_hash, hamming_distance -from model import Infraction +from model import Infraction, Guild from utils.services import guild_service, user_service from utils.config import cfg from utils.mod import prepare_ban_log -from utils.reports import report_raid, report_raid_phrase, report_spam +from utils.reports import report_raid, report_raid_phrase, report_spam, prepare_embed from utils import pfpcalc class RaidType: @@ -35,7 +35,7 @@ def __call__(self, msg): return self.get_key(msg) class AntiRaidMonitor(commands.Cog): # leaving this at commands.Cog - def __init__(self, bot): + def __init__(self, bot: commands.Bot): self.bot = bot # cooldown to monitor if too many users join in a short period of time (more than 10 within 8 seconds) @@ -79,6 +79,9 @@ def __init__(self, bot): self.last30pfps = [] self.last30messagecontents = {} + self.invite_filter = r'(?:https?://)?discord(?:(?:app)?\.com/invite|\.gg)\/{1,}[a-zA-Z0-9]+/?' + + @commands.Cog.listener() async def on_member_join(self, member: discord.Member) -> None: """Antiraid filter for when members join. @@ -220,6 +223,43 @@ async def on_message(self, message: discord.Message): await self.handle_raid_detection(message, RaidType.PingSpam) elif await self.detect_scam_link(message): await self.report_possible_raid_phrase(message) + elif await self.do_invite_filter(message, guild_service.get_guild()): + db_guild = guild_service.get_guild() + reports_channel = message.guild.get_channel(db_guild.channel_reports) + await reports_channel.send(f"<@&{db_guild.role_reportping}>", embed=await prepare_embed(message, title="Invite filter"), allowed_mentions=discord.AllowedMentions(roles=True)) + + + async def do_invite_filter(self, message: discord.Message, db_guild: Guild): + invites = re.findall(self.invite_filter, message.content, flags=re.S) + if not invites: + return + + whitelist = db_guild.filter_excluded_guilds + for invite in invites: + try: + invite = await self.bot.fetch_invite(invite) + + id = None + if isinstance(invite, discord.Invite): + if invite.guild is not None: + id = invite.guild.id + else: + id = 123 + elif isinstance(invite, discord.PartialInviteGuild) or isinstance(invite, discord.PartialInviteChannel): + id = invite.id + + if id not in whitelist: + await message.delete() + return True + + except discord.NotFound: + return False + # await self.delete(message) + # await self.ratelimit(message) + # await report_raid(user=message.author, msg=message) + # return True + + return False async def detect_scam_link(self, message: discord.Message): # check if message contains @everyone or @here diff --git a/bridget/cogs/native_actions_listeners.py b/bridget/cogs/native_actions_listeners.py index 003c56d..968c66d 100644 --- a/bridget/cogs/native_actions_listeners.py +++ b/bridget/cogs/native_actions_listeners.py @@ -154,6 +154,32 @@ async def automod_fancy_embed(bot: discord.BotIntegration, ctx: discord.AutoModA name="Warn points", value=user_service.get_user(ctx.user_id).warn_points, inline=True) + + account_age = (datetime.now() - datetime.fromtimestamp(discord.utils.snowflake_time(member.id))).days + + + if member.joined_at != None: + guild_age = (datetime.now() - member.joined_at).days + else: + guild_age = account_age + + risk_factor = user_service.get_user(ctx.user_id).warn_points * 0.5 + min(len(user_service.get_infractions(member.id)), 10) * 0.3 + min((guild_age / 30), 10) * 0.1 + min(account_age / 60, 10) * 0.1 + + embed.add_field(name="User risk factor (scale: 1-10)", + value=f"{risk_factor} (warn points * 0.5 + infraction count (max 10) * 0.3 + days since guild join / 30 (max 10) * 0.1 + days since account creation / 60 (max 10) * 0.1)" + ) + + reversed_roles = member.roles + reversed_roles.reverse() + + roles = "" + for role in reversed_roles[0:4]: + if role != member.guild.default_role: + roles += role.mention + " " + roles = roles.strip() + "..." + + embed.add_field( + name="Roles", value=roles if roles else "None", inline=False) # buttons view = AutoModReportView(member, bot) diff --git a/bridget/migrate/__main__.py b/bridget/migrate/__main__.py index 2ca3855..1ce5c9b 100644 --- a/bridget/migrate/__main__.py +++ b/bridget/migrate/__main__.py @@ -9,8 +9,9 @@ from bridget import model from utils import services +from typing import * -girfilter = [] +girfilter: List[girmodel.FilterWord] = [] girraid = [] class MigrateClient(discord.Client): @@ -19,21 +20,30 @@ async def on_ready(self): rules = await self.get_guild(services.guild_id).fetch_automod_rules() for filter in girfilter: - rule = self.get_guild(services.guild_id).getrole(filter.bypass) - rule = [ x for x in rules if rule.name in x.name ] - if len(rule) == 0: - return - rule = rule[0] - - # extract the trigger to modify it - trig = rule.trigger - - - phrase = filter.word - trig.keyword_filter.append(phrase) - - # edit the rule trigger - await rule.edit(trigger=trig, reason="Filtered word/regex/whitelist has been added (Migration)") + try: + guild: model.Guild = self.get_guild(int(services.guild_id)) + if guild == None: + continue + rule = self.get_guild(int(services.guild_id)).get_role(filter.bypass) + if filter.notify: + rule = [ x for x in rules if rule.name in x.name and rule.name.endswith('🚨') ] + else: + rule = [ x for x in rules if rule.name in x.name and not rule.name.endswith('🚨')] + if len(rule) == 0: + return + rule = rule[0] + + # extract the trigger to modify it + trig = rule.trigger + + + phrase = filter.word + trig.keyword_filter.append(phrase) + + # edit the rule trigger + await rule.edit(trigger=trig, reason="Filtered word/regex/whitelist has been added (Migration)") + except: + continue print("Migrating AntiRaid!") diff --git a/bridget/utils/reports.py b/bridget/utils/reports.py index 262998d..35ecb31 100644 --- a/bridget/utils/reports.py +++ b/bridget/utils/reports.py @@ -174,8 +174,7 @@ def prepare_ping_string(db_guild, message): ping_string += f"{member.mention} " return ping_string""" - return "<@&1068359860728643704> " - + return f"<@&{guild_service.get_guild().role_reportping}> " def prepare_embed(target: Union[discord.Message, discord.Member], word: str = None, title="Word filter"): """Prepares embed @@ -228,6 +227,18 @@ def prepare_embed(target: Union[discord.Message, discord.Member], word: str = No embed.add_field(name="Warn points", value=user_info.warn_points, inline=True) + account_age = (datetime.now() - datetime.fromtimestamp(discord.utils.snowflake_time(member.id))).days + + if member.joined_at != None: + guild_age = (datetime.now() - member.joined_at).days + else: + guild_age = account_age + + risk_factor = user_service.get_user(member.id).warn_points * 0.5 + min(len(user_service.get_infractions(member.id)), 10) * 0.3 + min((guild_age / 30), 10) * 0.1 + min(account_age / 60, 10) * 0.1 + + embed.add_field(name="User risk factor (scale: 1-10)", + value=f"{risk_factor} (warn points * 0.5 + infraction count (max 10) * 0.3 + days since guild join / 30 (max 10) * 0.1 + days since account creation / 60 (max 10) * 0.1)" + ) reversed_roles = member.roles reversed_roles.reverse() @@ -242,14 +253,13 @@ def prepare_embed(target: Union[discord.Message, discord.Member], word: str = No name="Roles", value=roles if roles else "None", inline=False) if len(rd) > 0: - embed.add_field(name=f"{len(rd)} most recent infractions", + embed.add_field(name=f"{len(rd)} most recent cases", value=rd_text, inline=True) else: - embed.add_field(name=f"Recent infractions", - value="This user has no infractions.", inline=True) + embed.add_field(name=f"Recent cases", + value="This user has no cases.", inline=True) return embed - class ReportActions(ui.View): def __init__(self, target_member: discord.Member): super().__init__(timeout=None)