aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-03-23 21:27:56 +0100
committersalmonik <raisersoft@proton.me>2026-03-23 21:27:56 +0100
commitd779d5b494d8bf7c7e483f54bef3be5787426e82 (patch)
treef989a49bb44bd68e73fe81a4cdc0369b73a928f4
parentwe moved to data folder (diff)
downloadsenator-sperma-d779d5b494d8bf7c7e483f54bef3be5787426e82.tar.gz
senator-sperma-d779d5b494d8bf7c7e483f54bef3be5787426e82.zip
sanitize inputs for math
Diffstat (limited to '')
-rw-r--r--cogs/math_commands.py58
1 files changed, 53 insertions, 5 deletions
diff --git a/cogs/math_commands.py b/cogs/math_commands.py
index bf164b3..e30c92b 100644
--- a/cogs/math_commands.py
+++ b/cogs/math_commands.py
@@ -5,12 +5,45 @@
5 5
6import logging 6import logging
7import asyncio 7import asyncio
8import re
8 9
9from discord import ApplicationContext 10from discord import ApplicationContext
10from discord.ext import commands 11from discord.ext import commands
11 12
12logger = logging.getLogger(__name__) 13logger = logging.getLogger(__name__)
13 14
15MATH_SANITIZE_PATTERN = re.compile(r'^[\d\s\+\-\*\/\^\%\(\)\.\,\=\\<\>\!\|\&\~\?\:\'\"\[\]\{\}a-zA-Z]+$')
16
17
18def 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
14 47
15class Math(commands.Cog): 48class Math(commands.Cog):
16 def __init__(self, bot): 49 def __init__(self, bot):
@@ -21,13 +54,28 @@ class Math(commands.Cog):
21 description="wrug szyskih matfisuf" 54 description="wrug szyskih matfisuf"
22 ) 55 )
23 async def math(self, ctx: ApplicationContext, equation: str): 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
24 try: 62 try:
25 math = await asyncio.create_subprocess_exec(f"qalc -e '{equation}'") 63 math_proc = await asyncio.create_subprocess_exec(
26 result = await math.wait() 64 "qalc", "-e", sanitized,
27 await ctx.respond(f"{equation} = {result.decode('utf-8').strip()}") 65 stdout=asyncio.subprocess.PIPE,
28 logger.info(f"Math command executed: {equation}") 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}")
29 except Exception as e: 77 except Exception as e:
30 await ctx.respond(e, ephemeral=True) 78 await ctx.respond(f"Error: {str(e)}", ephemeral=True)
31 logger.error(f"Error in math command: {e}", exc_info=True) 79 logger.error(f"Error in math command: {e}", exc_info=True)
32 80
33 81