Prevent OverflowError from very large timedeltas in Mutes (#6353)

This commit is contained in:
TrustyJAID 2024-04-20 19:01:28 -06:00 committed by GitHub
parent 47d4675f52
commit 0c9c210dbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 58 additions and 36 deletions

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import logging import logging
import re import re
from typing import Optional, TypedDict from typing import Optional, TypedDict
from datetime import timedelta from datetime import timedelta, datetime, timezone
from typing_extensions import Annotated from typing_extensions import Annotated
from discord.ext.commands.converter import Converter from discord.ext.commands.converter import Converter
@ -29,6 +29,7 @@ def _edgematch(pattern: re.Pattern[str], argument: str) -> Optional[re.Match[str
class _MuteTime(TypedDict, total=False): class _MuteTime(TypedDict, total=False):
duration: timedelta duration: timedelta
reason: str reason: str
until: datetime
class _MuteTimeConverter(Converter): class _MuteTimeConverter(Converter):
@ -57,6 +58,8 @@ class _MuteTimeConverter(Converter):
) )
try: try:
result["duration"] = duration = timedelta(**time_data) result["duration"] = duration = timedelta(**time_data)
result["until"] = ctx.message.created_at + duration
# Catch if using the timedelta with the current date will also result in an Overflow error
except OverflowError: except OverflowError:
raise commands.BadArgument( raise commands.BadArgument(
_("The time provided is too long; use a more reasonable time.") _("The time provided is too long; use a more reasonable time.")

View File

@ -1005,13 +1005,20 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
await self.config.guild(ctx.guild).default_time.clear() await self.config.guild(ctx.guild).default_time.clear()
await ctx.send(_("Default mute time removed.")) await ctx.send(_("Default mute time removed."))
else: else:
data = time.get("duration", {}) duration = time.get("duration", None)
if not data: if not duration:
return await ctx.send(_("Please provide a valid time format.")) return await ctx.send(_("Please provide a valid time format."))
await self.config.guild(ctx.guild).default_time.set(data.total_seconds()) if duration >= timedelta(days=365000):
# prevent setting a default time now that might eventually cause an overflow
# later as the date goes up. 1000 years gives us approximately 8000 more years
# of wiggle room.
return await ctx.send(
_("The time provided is too long; use a more reasonable time.")
)
await self.config.guild(ctx.guild).default_time.set(duration.total_seconds())
await ctx.send( await ctx.send(
_("Default mute time set to {time}.").format( _("Default mute time set to {time}.").format(
time=humanize_timedelta(timedelta=data) time=humanize_timedelta(timedelta=duration)
) )
) )
@ -1142,15 +1149,15 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
return await ctx.send(_("You cannot mute me.")) return await ctx.send(_("You cannot mute me."))
if ctx.author in users: if ctx.author in users:
return await ctx.send(_("You cannot mute yourself.")) return await ctx.send(_("You cannot mute yourself."))
duration = time_and_reason.get("duration", None) until = time_and_reason.get("until", None)
reason = time_and_reason.get("reason", None)
time = ""
duration = None
if until:
duration = time_and_reason.get("duration")
if duration and duration > timedelta(days=28): if duration and duration > timedelta(days=28):
await ctx.send(_(MUTE_UNMUTE_ISSUES["mute_is_too_long"])) await ctx.send(_(MUTE_UNMUTE_ISSUES["mute_is_too_long"]))
return return
reason = time_and_reason.get("reason", None)
time = ""
until = None
if duration:
until = datetime.now(timezone.utc) + duration
length = humanize_timedelta(timedelta=duration) length = humanize_timedelta(timedelta=duration)
time = _(" for {length} until {duration}").format( time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until) length=length, duration=discord.utils.format_dt(until)
@ -1159,7 +1166,8 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
else: else:
default_duration = await self.config.guild(ctx.guild).default_time() default_duration = await self.config.guild(ctx.guild).default_time()
if default_duration: if default_duration:
until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) duration = timedelta(seconds=default_duration)
until = ctx.message.created_at + duration
length = humanize_timedelta(seconds=default_duration) length = humanize_timedelta(seconds=default_duration)
time = _(" for {length} until {duration}").format( time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until) length=length, duration=discord.utils.format_dt(until)
@ -1227,12 +1235,12 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
if not await self._check_for_mute_role(ctx): if not await self._check_for_mute_role(ctx):
return return
async with ctx.typing(): async with ctx.typing():
duration = time_and_reason.get("duration", None) until = time_and_reason.get("until", None)
reason = time_and_reason.get("reason", None) reason = time_and_reason.get("reason", None)
time = "" time = ""
until = None duration = None
if duration: if until:
until = datetime.now(timezone.utc) + duration duration = time_and_reason.get("duration")
length = humanize_timedelta(timedelta=duration) length = humanize_timedelta(timedelta=duration)
time = _(" for {length} until {duration}").format( time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until) length=length, duration=discord.utils.format_dt(until)
@ -1241,7 +1249,8 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
else: else:
default_duration = await self.config.guild(ctx.guild).default_time() default_duration = await self.config.guild(ctx.guild).default_time()
if default_duration: if default_duration:
until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) duration = timedelta(seconds=default_duration)
until = ctx.message.created_at + duration
length = humanize_timedelta(seconds=default_duration) length = humanize_timedelta(seconds=default_duration)
time = _(" for {length} until {duration}").format( time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until) length=length, duration=discord.utils.format_dt(until)
@ -1377,18 +1386,26 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
if ctx.author in users: if ctx.author in users:
return await ctx.send(_("You cannot mute yourself.")) return await ctx.send(_("You cannot mute yourself."))
async with ctx.typing(): async with ctx.typing():
duration = time_and_reason.get("duration", None) until = time_and_reason.get("until", None)
reason = time_and_reason.get("reason", None) reason = time_and_reason.get("reason", None)
time = "" time = ""
until = None duration = None
if duration: if until:
until = datetime.now(timezone.utc) + duration duration = time_and_reason.get("duration")
time = _(" until {duration}").format(duration=discord.utils.format_dt(until)) length = humanize_timedelta(timedelta=duration)
time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until)
)
else: else:
default_duration = await self.config.guild(ctx.guild).default_time() default_duration = await self.config.guild(ctx.guild).default_time()
if default_duration: if default_duration:
until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) duration = timedelta(seconds=default_duration)
time = _(" until {duration}").format(duration=discord.utils.format_dt(until)) until = ctx.message.created_at + duration
length = humanize_timedelta(seconds=default_duration)
time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until)
)
author = ctx.message.author author = ctx.message.author
channel = ctx.message.channel channel = ctx.message.channel
if isinstance(channel, discord.Thread): if isinstance(channel, discord.Thread):

View File

@ -99,23 +99,25 @@ class VoiceMutes(MixinMeta):
if not can_move: if not can_move:
issue_list.append((user, perm_reason)) issue_list.append((user, perm_reason))
continue continue
duration = time_and_reason.get("duration", None) until = time_and_reason.get("until", None)
reason = time_and_reason.get("reason", None) reason = time_and_reason.get("reason", None)
time = "" time = ""
until = None duration = None
if duration: if until:
until = datetime.now(timezone.utc) + duration duration = time_and_reason.get("duration")
time = _(" for {duration}").format( length = humanize_timedelta(timedelta=duration)
duration=humanize_timedelta(timedelta=duration) time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until)
) )
else: else:
default_duration = await self.config.guild(ctx.guild).default_time() default_duration = await self.config.guild(ctx.guild).default_time()
if default_duration: if default_duration:
until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) duration = timedelta(seconds=default_duration)
time = _(" for {duration}").format( until = ctx.message.created_at + duration
duration=humanize_timedelta( length = humanize_timedelta(seconds=default_duration)
timedelta=timedelta(seconds=default_duration) time = _(" for {length} until {duration}").format(
) length=length, duration=discord.utils.format_dt(until)
) )
guild = ctx.guild guild = ctx.guild
author = ctx.author author = ctx.author