Add phishing validation and Phishlist

This commit is contained in:
Zeva Rose 2022-10-04 12:44:39 -06:00
parent b7e0381b8a
commit 1a73d6bbf3
2 changed files with 109 additions and 53 deletions

View file

@ -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)

View file

@ -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:
@ -83,6 +84,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(
@ -96,49 +101,12 @@ class MessageEventMixin:
).commit()
tracker = warnings_tracker.labels(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(
@ -168,9 +136,9 @@ class MessageEventMixin:
).commit()
tracker = warnings_tracker.labels(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")
@ -232,9 +200,11 @@ class MessageEventMixin:
).commit()
tracker = warnings_tracker.labels(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")
@ -242,6 +212,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}"
)
@ -257,9 +230,9 @@ class MessageEventMixin:
).commit()
tracker = warnings_tracker.labels(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:
@ -268,12 +241,41 @@ class MessageEventMixin:
self.logger.warn("Failed to delete malicious message")
tracker = malicious_tracker.labels(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",
@ -303,9 +305,9 @@ class MessageEventMixin:
tracker = warnings_tracker.labels(guild_id=message.guild.id, guild_name=message.guild.name)
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:
@ -314,6 +316,31 @@ class MessageEventMixin:
self.logger.warn("Failed to delete malicious message")
tracker = malicious_tracker.labels(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
@ -362,7 +389,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:
@ -418,7 +444,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: