Add phishing validation and Phishlist
This commit is contained in:
parent
854689f5ce
commit
232fcabbf7
2 changed files with 109 additions and 53 deletions
|
@ -1,6 +1,6 @@
|
|||
"""JARVIS component event mixin."""
|
||||
from jarvis_core.db import q
|
||||
from jarvis_core.db.models import Action, Modlog, Note, Reminder, Star
|
||||
from jarvis_core.db.models import Action, Modlog, Note, Phishlist, Reminder, Star
|
||||
from naff import listen
|
||||
from naff.api.events.internal import Button
|
||||
from naff.models.discord.embed import EmbedField
|
||||
|
@ -136,9 +136,40 @@ class ComponentEventMixin:
|
|||
|
||||
await context.send("Reminder copied!", ephemeral=True)
|
||||
|
||||
async def _handle_phishlist_button(self, event: Button) -> None:
|
||||
context = event.context
|
||||
if not context.custom_id.startswith("pl|"):
|
||||
return
|
||||
|
||||
if not context.deferred and not context.responded:
|
||||
await context.defer(ephemeral=True)
|
||||
|
||||
_, valid, id_ = context.custom_id.split("|")
|
||||
valid = valid == "valid"
|
||||
pl = await Phishlist.find_one(q(_id=id_))
|
||||
if not pl:
|
||||
self.logger.warn(f"Phishlist {id_} does not exist!")
|
||||
return
|
||||
|
||||
pl.valid = valid
|
||||
pl.confirmed = True
|
||||
|
||||
await pl.commit()
|
||||
|
||||
for row in context.message.components:
|
||||
for component in row.components:
|
||||
component.disabled = True
|
||||
|
||||
embed = context.message.embeds[0]
|
||||
embed.add_field(name="Valid", value="Yes" if valid else "No")
|
||||
|
||||
await context.message.edit(components=context.message.components, embeds=embed)
|
||||
await context.send("Confirmed! Thank you for confirming this URL.")
|
||||
|
||||
@listen()
|
||||
async def on_button(self, event: Button) -> None:
|
||||
"""Process button events."""
|
||||
await self._handle_modcase_button(event)
|
||||
await self._handle_delete_button(event)
|
||||
await self._handle_copy_button(event)
|
||||
await self._handle_phishlist_button(event)
|
||||
|
|
|
@ -7,8 +7,8 @@ from jarvis_core.db import q
|
|||
from jarvis_core.db.models import (
|
||||
Autopurge,
|
||||
Autoreact,
|
||||
Filter,
|
||||
Mute,
|
||||
Phishlist,
|
||||
Roleping,
|
||||
Setting,
|
||||
Warning,
|
||||
|
@ -18,15 +18,16 @@ from naff import listen
|
|||
from naff.api.events.discord import MessageCreate, MessageDelete, MessageUpdate
|
||||
from naff.client.utils.misc_utils import find_all
|
||||
from naff.models.discord.channel import DMChannel, GuildText
|
||||
from naff.models.discord.components import ActionRow, Button
|
||||
from naff.models.discord.embed import EmbedField
|
||||
from naff.models.discord.enums import Permissions
|
||||
from naff.models.discord.enums import ButtonStyles, Permissions
|
||||
from naff.models.discord.message import Message
|
||||
from naff.models.discord.user import Member
|
||||
|
||||
from jarvis.branding import get_command_color
|
||||
from jarvis.embeds.admin import warning_embed
|
||||
from jarvis.tracking import malicious_tracker, warnings_tracker
|
||||
from jarvis.utils import build_embed
|
||||
from jarvis.utils.embeds import warning_embed
|
||||
|
||||
|
||||
class MessageEventMixin:
|
||||
|
@ -87,6 +88,10 @@ class MessageEventMixin:
|
|||
]
|
||||
if (m := match.group(1)) not in allowed and setting.value:
|
||||
self.logger.debug(f"Removing non-allowed invite `{m}` from {message.guild.id}")
|
||||
try:
|
||||
await message.delete()
|
||||
except Exception:
|
||||
self.logger.debug("Message deleted before action taken")
|
||||
|
||||
expires_at = datetime.now(tz=timezone.utc) + timedelta(hours=24)
|
||||
await Warning(
|
||||
|
@ -102,49 +107,12 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
embed = warning_embed(message.author, "Sent an invite link")
|
||||
embed = warning_embed(message.author, "Sent an invite link", self.user)
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
await message.channel.send(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
|
||||
try:
|
||||
await message.delete()
|
||||
except Exception:
|
||||
self.logger.debug("Message deleted before action taken")
|
||||
|
||||
async def filters(self, message: Message) -> None:
|
||||
"""Handle filter evennts."""
|
||||
filters = await Filter.find(q(guild=message.guild.id)).to_list(None)
|
||||
for item in filters:
|
||||
for f in item.filters:
|
||||
if re.search(f, message.content, re.IGNORECASE):
|
||||
expires_at = datetime.now(tz=timezone.utc) + timedelta(hours=24)
|
||||
await Warning(
|
||||
active=True,
|
||||
admin=self.user.id,
|
||||
duration=24,
|
||||
expires_at=expires_at,
|
||||
guild=message.guild.id,
|
||||
reason="Sent a message with a filtered word",
|
||||
user=message.author.id,
|
||||
).commit()
|
||||
tracker = warnings_tracker.labels(
|
||||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
embed = warning_embed(message.author, "Sent a message with a filtered word")
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
|
||||
try:
|
||||
await message.delete()
|
||||
except Exception:
|
||||
self.logger.debug("Message deleted before action taken")
|
||||
return
|
||||
|
||||
async def massmention(self, message: Message) -> None:
|
||||
"""Handle massmention events."""
|
||||
massmention = await Setting.find_one(
|
||||
|
@ -178,9 +146,9 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
embed = warning_embed(message.author, "Mass Mention")
|
||||
embed = warning_embed(message.author, "Mass Mention", self.user)
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
await message.channel.send(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
|
||||
|
@ -246,9 +214,11 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
embed = warning_embed(message.author, "Pinged a blocked role/user with a blocked role")
|
||||
embed = warning_embed(
|
||||
message.author, "Pinged a blocked role/user with a blocked role", self.user
|
||||
)
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
await message.channel.send(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
|
||||
|
@ -256,6 +226,9 @@ class MessageEventMixin:
|
|||
"""Check if the message contains any known phishing domains."""
|
||||
for match in url.finditer(message.content):
|
||||
if (m := match.group("domain")) in self.phishing_domains:
|
||||
pl = await Phishlist.find_one(q(url=m))
|
||||
if pl and pl.confirmed and not pl.valid:
|
||||
return False
|
||||
self.logger.debug(
|
||||
f"Phishing url `{m}` detected in {message.guild.id}/{message.channel.id}/{message.id}"
|
||||
)
|
||||
|
@ -273,9 +246,9 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
embed = warning_embed(message.author, "Phishing URL")
|
||||
embed = warning_embed(message.author, "Phishing URL", self.user)
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
await message.channel.send(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
try:
|
||||
|
@ -286,12 +259,41 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
|
||||
if not pl or not pl.confirmed:
|
||||
if not pl:
|
||||
pl = Phishlist(url=m)
|
||||
await pl.commit()
|
||||
|
||||
embed = build_embed(
|
||||
title="Phishing URL detected",
|
||||
description="Please confirm that this is valid",
|
||||
fields=[EmbedField(name="URL", value=m)],
|
||||
)
|
||||
|
||||
valid_button = Button(
|
||||
style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}"
|
||||
)
|
||||
invalid_button = Button(
|
||||
style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}"
|
||||
)
|
||||
|
||||
channel = await self.fetch_channel(1026918337554423868)
|
||||
|
||||
components = [ActionRow(invalid_button, valid_button)]
|
||||
|
||||
await channel.send(embeds=embed, components=components)
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
async def malicious_url(self, message: Message) -> None:
|
||||
"""Check if the message contains any known phishing domains."""
|
||||
for match in url.finditer(message.content):
|
||||
m = match.group("domain")
|
||||
pl = await Phishlist.find_one(q(url=m))
|
||||
if pl and pl.confirmed and not pl.valid:
|
||||
return False
|
||||
async with ClientSession() as session:
|
||||
resp = await session.post(
|
||||
"https://anti-fish.bitflow.dev/check",
|
||||
|
@ -323,9 +325,9 @@ class MessageEventMixin:
|
|||
)
|
||||
tracker.inc()
|
||||
reasons = ", ".join(f"{m['source']}: {m['type']}" for m in data["matches"])
|
||||
embed = warning_embed(message.author, reasons)
|
||||
embed = warning_embed(message.author, reasons, self.user)
|
||||
try:
|
||||
await message.reply(embeds=embed)
|
||||
await message.channel.send(embeds=embed)
|
||||
except Exception:
|
||||
self.logger.warn("Failed to send warning embed")
|
||||
try:
|
||||
|
@ -336,6 +338,31 @@ class MessageEventMixin:
|
|||
guild_id=message.guild.id, guild_name=message.guild.name
|
||||
)
|
||||
tracker.inc()
|
||||
|
||||
if not pl or not pl.confirmed:
|
||||
if not pl:
|
||||
pl = Phishlist(url=m)
|
||||
await pl.commit()
|
||||
|
||||
embed = build_embed(
|
||||
title="Malicious URL detected",
|
||||
description="Please confirm that this is valid",
|
||||
fields=[EmbedField(name="URL", value=m)],
|
||||
)
|
||||
|
||||
valid_button = Button(
|
||||
style=ButtonStyles.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}"
|
||||
)
|
||||
invalid_button = Button(
|
||||
style=ButtonStyles.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}"
|
||||
)
|
||||
|
||||
channel = await self.fetch_channel(1026918337554423868)
|
||||
|
||||
components = [ActionRow(invalid_button, valid_button)]
|
||||
|
||||
await channel.send(embeds=embed, components=components)
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -384,7 +411,6 @@ class MessageEventMixin:
|
|||
malicious = await self.malicious_url(message)
|
||||
if phish or malicious:
|
||||
await self.timeout_user(message.author, message.channel)
|
||||
await self.filters(message)
|
||||
|
||||
@listen()
|
||||
async def on_message_edit(self, event: MessageUpdate) -> None:
|
||||
|
@ -442,7 +468,6 @@ class MessageEventMixin:
|
|||
malicious = await self.malicious_url(after)
|
||||
if phish or malicious:
|
||||
await self.timeout_user(after.author, after.channel)
|
||||
await self.filters(after)
|
||||
|
||||
@listen()
|
||||
async def on_message_delete(self, event: MessageDelete) -> None:
|
||||
|
|
Loading…
Add table
Reference in a new issue