aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/converters.py15
-rw-r--r--bot/exts/filters/antispam.py22
-rw-r--r--bot/exts/info/doc/_cog.py9
-rw-r--r--bot/exts/info/doc/_inventory_parser.py22
4 files changed, 48 insertions, 20 deletions
diff --git a/bot/converters.py b/bot/converters.py
index 8b0890830..c96e2c984 100644
--- a/bot/converters.py
+++ b/bot/converters.py
@@ -235,11 +235,16 @@ class Inventory(Converter):
async def convert(ctx: Context, url: str) -> t.Tuple[str, _inventory_parser.InventoryDict]:
"""Convert url to Intersphinx inventory URL."""
await ctx.trigger_typing()
- if (inventory := await _inventory_parser.fetch_inventory(url)) is None:
- raise BadArgument(
- f"Failed to fetch inventory file after {_inventory_parser.FAILED_REQUEST_ATTEMPTS} attempts."
- )
- return url, inventory
+ try:
+ inventory = await _inventory_parser.fetch_inventory(url)
+ except _inventory_parser.InvalidHeaderError:
+ raise BadArgument("Unable to parse inventory because of invalid header, check if URL is correct.")
+ else:
+ if inventory is None:
+ raise BadArgument(
+ f"Failed to fetch inventory file after {_inventory_parser.FAILED_REQUEST_ATTEMPTS} attempts."
+ )
+ return url, inventory
class Snowflake(IDConverter):
diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py
index 70c1168bf..8bae159d2 100644
--- a/bot/exts/filters/antispam.py
+++ b/bot/exts/filters/antispam.py
@@ -82,28 +82,34 @@ class DeletionContext:
f"**Rules:** {', '.join(rule for rule in self.rules)}\n"
)
- # For multiple messages or those with excessive newlines, use the logs API
- if len(self.messages) > 1 or 'newlines' in self.rules:
+ messages_as_list = list(self.messages.values())
+ first_message = messages_as_list[0]
+ # For multiple messages and those with attachments or excessive newlines, use the logs API
+ if any((
+ len(messages_as_list) > 1,
+ len(first_message.attachments) > 0,
+ first_message.content.count('\n') > 15
+ )):
url = await modlog.upload_log(self.messages.values(), actor_id, self.attachments)
mod_alert_message += f"A complete log of the offending messages can be found [here]({url})"
else:
mod_alert_message += "Message:\n"
- [message] = self.messages.values()
- content = message.clean_content
+ content = first_message.clean_content
remaining_chars = 4080 - len(mod_alert_message)
if len(content) > remaining_chars:
- content = content[:remaining_chars] + "..."
+ url = await modlog.upload_log([first_message], actor_id, self.attachments)
+ log_site_msg = f"The full message can be found [here]({url})"
+ content = content[:remaining_chars - (3 + len(log_site_msg))] + "..."
- mod_alert_message += f"{content}"
+ mod_alert_message += content
- *_, last_message = self.messages.values()
await modlog.send_log_message(
icon_url=Icons.filtering,
colour=Colour(Colours.soft_red),
title="Spam detected!",
text=mod_alert_message,
- thumbnail=last_message.author.avatar_url_as(static_format="png"),
+ thumbnail=first_message.author.avatar_url_as(static_format="png"),
channel_id=Channels.mod_alerts,
ping_everyone=AntiSpamConfig.ping_everyone
)
diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py
index 1624c50f6..e7710db24 100644
--- a/bot/exts/info/doc/_cog.py
+++ b/bot/exts/info/doc/_cog.py
@@ -22,7 +22,7 @@ from bot.utils.lock import SharedEvent, lock
from bot.utils.messages import send_denial, wait_for_deletion
from bot.utils.scheduling import Scheduler
from . import NAMESPACE, PRIORITY_PACKAGES, _batch_parser, doc_cache
-from ._inventory_parser import InventoryDict, fetch_inventory
+from ._inventory_parser import InvalidHeaderError, InventoryDict, fetch_inventory
log = logging.getLogger(__name__)
@@ -137,7 +137,12 @@ class DocCog(commands.Cog):
The first attempt is rescheduled to execute in `FETCH_RESCHEDULE_DELAY.first` minutes, the subsequent attempts
in `FETCH_RESCHEDULE_DELAY.repeated` minutes.
"""
- package = await fetch_inventory(inventory_url)
+ try:
+ package = await fetch_inventory(inventory_url)
+ except InvalidHeaderError as e:
+ # Do not reschedule if the header is invalid, as the request went through but the contents are invalid.
+ log.warning(f"Invalid inventory header at {inventory_url}. Reason: {e}")
+ return
if not package:
if api_package_name in self.inventory_scheduler:
diff --git a/bot/exts/info/doc/_inventory_parser.py b/bot/exts/info/doc/_inventory_parser.py
index 80d5841a0..61924d070 100644
--- a/bot/exts/info/doc/_inventory_parser.py
+++ b/bot/exts/info/doc/_inventory_parser.py
@@ -16,6 +16,10 @@ _V2_LINE_RE = re.compile(r'(?x)(.+?)\s+(\S*:\S*)\s+(-?\d+)\s+?(\S*)\s+(.*)')
InventoryDict = DefaultDict[str, List[Tuple[str, str]]]
+class InvalidHeaderError(Exception):
+ """Raised when an inventory file has an invalid header."""
+
+
class ZlibStreamReader:
"""Class used for decoding zlib data of a stream line by line."""
@@ -80,19 +84,25 @@ async def _fetch_inventory(url: str) -> InventoryDict:
stream = response.content
inventory_header = (await stream.readline()).decode().rstrip()
- inventory_version = int(inventory_header[-1:])
- await stream.readline() # skip project name
- await stream.readline() # skip project version
+ try:
+ inventory_version = int(inventory_header[-1:])
+ except ValueError:
+ raise InvalidHeaderError("Unable to convert inventory version header.")
+
+ has_project_header = (await stream.readline()).startswith(b"# Project")
+ has_version_header = (await stream.readline()).startswith(b"# Version")
+ if not (has_project_header and has_version_header):
+ raise InvalidHeaderError("Inventory missing project or version header.")
if inventory_version == 1:
return await _load_v1(stream)
elif inventory_version == 2:
if b"zlib" not in await stream.readline():
- raise ValueError(f"Invalid inventory file at url {url}.")
+ raise InvalidHeaderError("'zlib' not found in header of compressed inventory.")
return await _load_v2(stream)
- raise ValueError(f"Invalid inventory file at url {url}.")
+ raise InvalidHeaderError("Incompatible inventory version.")
async def fetch_inventory(url: str) -> Optional[InventoryDict]:
@@ -115,6 +125,8 @@ async def fetch_inventory(url: str) -> Optional[InventoryDict]:
f"Failed to get inventory from {url}; "
f"trying again ({attempt}/{FAILED_REQUEST_ATTEMPTS})."
)
+ except InvalidHeaderError:
+ raise
except Exception:
log.exception(
f"An unexpected error has occurred during fetching of {url}; "