mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-10-25 16:18:32 +00:00
Notifications - Fix |regex_replace doing nothing when rendered outside the main thread (#4577)
This commit is contained in:
1 parent
7dc82a36e2
commit
d88f8d7b0b
2 files changed
+22
-2
No files matched your search
@@ -5,6 +5,7 @@ Provides regex_replace filter for pattern-based string replacements in templates
|
||||
"""
|
||||
import re
|
||||
import signal
|
||||
import threading
|
||||
from loguru import logger
|
||||
|
||||
|
||||
@@ -68,11 +69,15 @@ def regex_replace(value: str, pattern: str, replacement: str = '', count: int =
|
||||
def timeout_handler(signum, frame):
|
||||
raise TimeoutError("Regex operation timed out")
|
||||
|
||||
# signal.signal() only works in the main thread, but notifications are rendered
|
||||
# in the notification runner threads, so only use the alarm where it can be set
|
||||
use_alarm = hasattr(signal, 'SIGALRM') and threading.current_thread() is threading.main_thread()
|
||||
|
||||
try:
|
||||
# Set up timeout for regex operation (Unix-like systems only)
|
||||
# This prevents ReDoS attacks
|
||||
old_handler = None
|
||||
if hasattr(signal, 'SIGALRM'):
|
||||
if use_alarm:
|
||||
old_handler = signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.alarm(REGEX_TIMEOUT_SECONDS)
|
||||
|
||||
@@ -80,7 +85,7 @@ def regex_replace(value: str, pattern: str, replacement: str = '', count: int =
|
||||
result = re.sub(pattern, replacement, value_str, count=count)
|
||||
finally:
|
||||
# Cancel the alarm
|
||||
if hasattr(signal, 'SIGALRM'):
|
||||
if use_alarm:
|
||||
signal.alarm(0)
|
||||
if old_handler is not None:
|
||||
signal.signal(signal.SIGALRM, old_handler)
|
||||
|
||||
@@ -244,6 +244,21 @@ def test_regex_replace_with_notification_context():
|
||||
|
||||
assert "value1 value2 " in finalRender
|
||||
|
||||
def test_regex_replace_outside_main_thread():
|
||||
"""Test regex_replace also works when rendered outside the main thread, like in the notification runners."""
|
||||
import threading
|
||||
|
||||
results = []
|
||||
|
||||
def render_in_thread():
|
||||
results.append(render("{{ 'hello world 123' | regex_replace('[0-9]+', 'no-more-numbers') }}"))
|
||||
|
||||
thread = threading.Thread(target=render_in_thread)
|
||||
thread.start()
|
||||
thread.join()
|
||||
|
||||
assert results == ["hello world no-more-numbers"]
|
||||
|
||||
def test_regex_replace_security_large_input():
|
||||
"""Test regex_replace handles large input safely."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user