diff options
Diffstat (limited to 'cogs/math_commands.py')
| -rw-r--r-- | cogs/math_commands.py | 83 |
1 files changed, 0 insertions, 83 deletions
diff --git a/cogs/math_commands.py b/cogs/math_commands.py deleted file mode 100644 index e30c92b..0000000 --- a/cogs/math_commands.py +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | # This file is part of Senator Sperma | ||
| 2 | # Licensed under the GPL-3.0 License | ||
| 3 | # Copyright (C) 2026 Salmonik @ salmonik@tuta.io | ||
| 4 | # https://codeberg.org/salmonik/senator-sperma | ||
| 5 | |||
| 6 | import logging | ||
| 7 | import asyncio | ||
| 8 | import re | ||
| 9 | |||
| 10 | from discord import ApplicationContext | ||
| 11 | from discord.ext import commands | ||
| 12 | |||
| 13 | logger = logging.getLogger(__name__) | ||
| 14 | |||
| 15 | MATH_SANITIZE_PATTERN = re.compile(r'^[\d\s\+\-\*\/\^\%\(\)\.\,\=\\<\>\!\|\&\~\?\:\'\"\[\]\{\}a-zA-Z]+$') | ||
| 16 | |||
| 17 | |||
| 18 | def sanitize_math_input(equation: str) -> str | None: | ||
| 19 | if not equation or len(equation) > 1000: | ||
| 20 | return None | ||
| 21 | equation = equation.strip() | ||
| 22 | if not equation: | ||
| 23 | return None | ||
| 24 | if not MATH_SANITIZE_PATTERN.match(equation): | ||
| 25 | return None | ||
| 26 | for char in equation: | ||
| 27 | if ord(char) < 32 or ord(char) > 126: | ||
| 28 | return None | ||
| 29 | if equation.count('(') != equation.count(')'): | ||
| 30 | return None | ||
| 31 | if equation.count('[') != equation.count(']'): | ||
| 32 | return None | ||
| 33 | if equation.count('{') != equation.count('}'): | ||
| 34 | return None | ||
| 35 | dangerous_patterns = [ | ||
| 36 | r'eval', r'exec', r'__import__', r'os\.', r'sys\.', | ||
| 37 | r'subprocess', r'open(', r'file', r'shutil', | ||
| 38 | r'lambda:', r'compile', r'dir(', r'vars(', | ||
| 39 | r'\|\|', r'&&', r';', r'`', r'\$', r'\\n', r'\\r', | ||
| 40 | r'\x', r'\0', r'\a', r'\b', r'\f', r'\v', | ||
| 41 | ] | ||
| 42 | for pattern in dangerous_patterns: | ||
| 43 | if re.search(pattern, equation, re.IGNORECASE): | ||
| 44 | return None | ||
| 45 | return equation | ||
| 46 | |||
| 47 | |||
| 48 | class Math(commands.Cog): | ||
| 49 | def __init__(self, bot): | ||
| 50 | self.bot = bot | ||
| 51 | |||
| 52 | @commands.slash_command( | ||
| 53 | name="math", | ||
| 54 | description="wrug szyskih matfisuf" | ||
| 55 | ) | ||
| 56 | async def math(self, ctx: ApplicationContext, equation: str): | ||
| 57 | sanitized = sanitize_math_input(equation) | ||
| 58 | if sanitized is None: | ||
| 59 | await ctx.respond("Invalid equation. Only basic math expressions allowed.", ephemeral=True) | ||
| 60 | logger.warning(f"Math command rejected invalid input: {equation}") | ||
| 61 | return | ||
| 62 | try: | ||
| 63 | math_proc = await asyncio.create_subprocess_exec( | ||
| 64 | "qalc", "-e", sanitized, | ||
| 65 | stdout=asyncio.subprocess.PIPE, | ||
| 66 | stderr=asyncio.subprocess.PIPE | ||
| 67 | ) | ||
| 68 | stdout, stderr = await math_proc.communicate() | ||
| 69 | if math_proc.returncode != 0: | ||
| 70 | error_output = stderr.decode('utf-8', errors='replace').strip() | ||
| 71 | await ctx.respond(f"Calculation error: {error_output}", ephemeral=True) | ||
| 72 | logger.error(f"qalc error: {error_output}") | ||
| 73 | return | ||
| 74 | result = stdout.decode('utf-8', errors='replace').strip() | ||
| 75 | await ctx.respond(f"{sanitized} = {result}") | ||
| 76 | logger.info(f"Math command executed: {sanitized}") | ||
| 77 | except Exception as e: | ||
| 78 | await ctx.respond(f"Error: {str(e)}", ephemeral=True) | ||
| 79 | logger.error(f"Error in math command: {e}", exc_info=True) | ||
| 80 | |||
| 81 | |||
| 82 | def setup(bot): | ||
| 83 | bot.add_cog(Math(bot)) | ||
