Compare commits

...

2 Commits

Author SHA1 Message Date
Mira Weller
7e57ab582e Bump version to 2024.6.1 2024-08-23 15:43:31 +02:00
Mira
d9d638a232 Escape HTML in placeholder samples in mail preview (#4413)
CVE-2024-8113
2024-08-23 15:20:22 +02:00
5 changed files with 12 additions and 9 deletions

View File

@@ -19,4 +19,4 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
__version__ = "2024.6.0" __version__ = "2024.6.1"

View File

@@ -38,6 +38,7 @@ from datetime import datetime
from django import forms from django import forms
from django.utils.formats import get_format from django.utils.formats import get_format
from django.utils.functional import lazy from django.utils.functional import lazy
from django.utils.html import escape
from django.utils.timezone import get_current_timezone, now from django.utils.timezone import get_current_timezone, now
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -64,7 +65,7 @@ def format_placeholders_help_text(placeholders, event=None):
placeholders = [(k, v.render_sample(event) if event else v) for k, v in placeholders.items()] placeholders = [(k, v.render_sample(event) if event else v) for k, v in placeholders.items()]
placeholders.sort(key=lambda x: x[0]) placeholders.sort(key=lambda x: x[0])
phs = [ phs = [
'<button type="button" class="content-placeholder" title="%s">{%s}</button>' % (_("Sample: %s") % v if v else "", k) '<button type="button" class="content-placeholder" title="%s">{%s}</button>' % (escape(_("Sample: %s") % v) if v else "", escape(k))
for k, v in placeholders for k, v in placeholders
] ]
return _('Available placeholders: {list}').format( return _('Available placeholders: {list}').format(

View File

@@ -62,6 +62,7 @@ from django.http import (
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.http import url_has_allowed_host_and_scheme from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _, gettext_noop from django.utils.translation import gettext, gettext_lazy as _, gettext_noop
@@ -736,7 +737,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
else: else:
ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format( ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'), _('This value will be replaced based on dynamic parameters.'),
s escape(s)
) )
return ctx return ctx
@@ -786,7 +787,7 @@ class MailSettingsRendererPreview(MailSettingsPreview):
def placeholders(self, item): def placeholders(self, item):
ctx = {} ctx = {}
for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item]).values(): for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item]).values():
ctx[p.identifier] = str(p.render_sample(self.request.event)) ctx[p.identifier] = escape(str(p.render_sample(self.request.event)))
return ctx return ctx
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

View File

@@ -50,7 +50,7 @@ from django.http import (
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.urls import resolve, reverse from django.urls import resolve, reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import format_html from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -562,7 +562,7 @@ class VoucherBulkMailPreview(EventPermissionRequiredMixin, View):
else: else:
ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format( ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'), _('This value will be replaced based on dynamic parameters.'),
s escape(s)
) )
return self.SafeDict(ctx) return self.SafeDict(ctx)

View File

@@ -46,6 +46,7 @@ from django.shortcuts import get_object_or_404, redirect
from django.template.loader import get_template from django.template.loader import get_template
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, ngettext from django.utils.translation import gettext_lazy as _, ngettext
from django.views.generic import DeleteView, FormView, ListView, TemplateView from django.views.generic import DeleteView, FormView, ListView, TemplateView
@@ -193,7 +194,7 @@ class BaseSenderView(EventPermissionRequiredMixin, FormView):
for k, v in get_available_placeholders(self.request.event, self.context_parameters).items(): for k, v in get_available_placeholders(self.request.event, self.context_parameters).items():
context_dict[k] = '<span class="placeholder" title="{}">{}</span>'.format( context_dict[k] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'), _('This value will be replaced based on dynamic parameters.'),
v.render_sample(self.request.event) escape(v.render_sample(self.request.event))
) )
subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[]) subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[])
@@ -608,7 +609,7 @@ class CreateRule(EventPermissionRequiredMixin, CreateView):
'position_or_address']).items(): 'position_or_address']).items():
context_dict[k] = '<span class="placeholder" title="{}">{}</span>'.format( context_dict[k] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'), _('This value will be replaced based on dynamic parameters.'),
v.render_sample(self.request.event) escape(v.render_sample(self.request.event))
) )
subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[]) subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[])
@@ -684,7 +685,7 @@ class UpdateRule(EventPermissionRequiredMixin, UpdateView):
for k, v in get_available_placeholders(self.request.event, ['event', 'order', 'position_or_address']).items(): for k, v in get_available_placeholders(self.request.event, ['event', 'order', 'position_or_address']).items():
placeholders[k] = '<span class="placeholder" title="{}">{}</span>'.format( placeholders[k] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'), _('This value will be replaced based on dynamic parameters.'),
v.render_sample(self.request.event) escape(v.render_sample(self.request.event))
) )
subject = bleach.clean(self.object.subject.localize(lang), tags=[]) subject = bleach.clean(self.object.subject.localize(lang), tags=[])