diff --git a/src/pretix/base/models/log.py b/src/pretix/base/models/log.py
index d850f5540..c8d45569e 100644
--- a/src/pretix/base/models/log.py
+++ b/src/pretix/base/models/log.py
@@ -5,6 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property
+from django.utils.html import escape
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from pretix.base.models.event import SubEvent
@@ -68,7 +69,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'code': co.code
}),
- 'val': co.code,
+ 'val': escape(co.code),
}
elif isinstance(co, Voucher):
a_text = _('Voucher {val}…')
@@ -78,7 +79,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'voucher': co.id
}),
- 'val': co.code[:6],
+ 'val': escape(co.code[:6]),
}
elif isinstance(co, Item):
a_text = _('Product {val}')
@@ -88,7 +89,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'item': co.id
}),
- 'val': co.name,
+ 'val': escape(co.name),
}
elif isinstance(co, SubEvent):
a_text = pgettext_lazy('subevent', 'Date {val}')
@@ -98,7 +99,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'subevent': co.id
}),
- 'val': str(co)
+ 'val': escape(str(co))
}
elif isinstance(co, Quota):
a_text = _('Quota {val}')
@@ -108,7 +109,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'quota': co.id
}),
- 'val': co.name,
+ 'val': escape(co.name),
}
elif isinstance(co, ItemCategory):
a_text = _('Category {val}')
@@ -118,7 +119,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'category': co.id
}),
- 'val': co.name,
+ 'val': escape(co.name),
}
elif isinstance(co, Question):
a_text = _('Question {val}')
@@ -128,7 +129,7 @@ class LogEntry(models.Model):
'organizer': self.event.organizer.slug,
'question': co.id
}),
- 'val': co.question,
+ 'val': escape(co.question),
}
if a_text and a_map:
diff --git a/src/pretix/base/templatetags/escapejson.py b/src/pretix/base/templatetags/escapejson.py
new file mode 100644
index 000000000..832cc711e
--- /dev/null
+++ b/src/pretix/base/templatetags/escapejson.py
@@ -0,0 +1,13 @@
+from django import template
+from django.template.defaultfilters import stringfilter
+
+from pretix.helpers.escapejson import escapejson
+
+register = template.Library()
+
+
+@register.filter("escapejson")
+@stringfilter
+def escapejs_filter(value):
+ """Hex encodes characters for use in a application/json type script."""
+ return escapejson(value)
diff --git a/src/pretix/control/templates/pretixcontrol/items/question.html b/src/pretix/control/templates/pretixcontrol/items/question.html
index 01a162133..11fd3a17a 100644
--- a/src/pretix/control/templates/pretixcontrol/items/question.html
+++ b/src/pretix/control/templates/pretixcontrol/items/question.html
@@ -1,6 +1,7 @@
{% extends "pretixcontrol/items/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
+{% load escapejson %}
{% load formset_tags %}
{% block title %}{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}{% endblock %}
{% block inside %}
@@ -58,7 +59,7 @@
-
+
diff --git a/src/pretix/control/templates/pretixcontrol/items/quota.html b/src/pretix/control/templates/pretixcontrol/items/quota.html
index de7e51fea..251b710df 100644
--- a/src/pretix/control/templates/pretixcontrol/items/quota.html
+++ b/src/pretix/control/templates/pretixcontrol/items/quota.html
@@ -1,6 +1,7 @@
{% extends "pretixcontrol/items/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
+{% load escapejson %}
{% load eventsignal %}
{% block title %}{% blocktrans with name=quota.name %}Quota: {{ name }}{% endblocktrans %}{% endblock %}
{% block inside %}
@@ -25,7 +26,7 @@
-
+
diff --git a/src/pretix/control/views/dashboards.py b/src/pretix/control/views/dashboards.py
index ede7eb764..9e8261fc4 100644
--- a/src/pretix/control/views/dashboards.py
+++ b/src/pretix/control/views/dashboards.py
@@ -8,6 +8,7 @@ from django.shortcuts import render
from django.template.loader import get_template
from django.utils import formats
from django.utils.formats import date_format
+from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
from pretix.base.models import (
@@ -136,7 +137,7 @@ def quota_widgets(sender, **kwargs):
status, left = q.availability()
widgets.append({
'content': NUM_WIDGET.format(num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
- text=_('{quota} left').format(quota=q.name)),
+ text=_('{quota} left').format(quota=escape(q.name))),
'display_size': 'small',
'priority': 50,
'url': reverse('control:event.items.quotas.show', kwargs={
@@ -258,7 +259,8 @@ def user_event_widgets(**kwargs):
for event in events:
widgets.append({
'content': '
{event}{df}{dt}
'.format(
- event=event.name, df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
+ event=escape(event.name),
+ df=date_format(event.date_from, 'SHORT_DATE_FORMAT') if event.date_from else '',
dt=date_format(event.date_to, 'SHORT_DATE_FORMAT') if event.date_to else ''
),
'display_size': 'small',
diff --git a/src/pretix/helpers/escapejson.py b/src/pretix/helpers/escapejson.py
new file mode 100644
index 000000000..6628e54be
--- /dev/null
+++ b/src/pretix/helpers/escapejson.py
@@ -0,0 +1,16 @@
+from django.utils import six
+from django.utils.encoding import force_text
+from django.utils.functional import keep_lazy
+from django.utils.safestring import SafeText, mark_safe
+
+_json_escapes = {
+ ord('>'): '\\u003E',
+ ord('<'): '\\u003C',
+ ord('&'): '\\u0026',
+}
+
+
+@keep_lazy(six.text_type, SafeText)
+def escapejson(value):
+ """Hex encodes characters for use in a application/json type script."""
+ return mark_safe(force_text(value).translate(_json_escapes))
diff --git a/src/pretix/plugins/statistics/templates/pretixplugins/statistics/index.html b/src/pretix/plugins/statistics/templates/pretixplugins/statistics/index.html
index 24f476118..a87eb49e4 100644
--- a/src/pretix/plugins/statistics/templates/pretixplugins/statistics/index.html
+++ b/src/pretix/plugins/statistics/templates/pretixplugins/statistics/index.html
@@ -2,6 +2,7 @@
{% load i18n %}
{% load compress %}
{% load staticfiles %}
+{% load escapejson %}
{% block title %}{% trans "Statistics" %}{% endblock %}
{% block content %}
{% trans "Statistics" %}
@@ -30,9 +31,9 @@
-
-
-
+
+
+
{% else %}