Compare commits

...

5 Commits

Author SHA1 Message Date
Raphael Michel
f4c8446cd5 Bump to 4.4.1 2022-01-26 13:43:14 +01:00
Raphael Michel
84fdcacb17 [SECURITY] Make redirect view dependent on referer 2022-01-26 13:42:05 +01:00
Raphael Michel
2c7c04ae88 [SECURITY] Fix (non-exploitable) XSS issue 2022-01-26 13:42:05 +01:00
Raphael Michel
5e3f9178f5 Bump version to 4.4.0 2021-10-29 15:37:30 +02:00
Raphael Michel
03ea47715d Fix check_order_transactions on SQLite 2021-10-29 15:37:22 +02:00
10 changed files with 84 additions and 18 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__ = "4.4.0.dev0" __version__ = "4.4.1"

View File

@@ -43,7 +43,7 @@ class Command(BaseCommand):
order=OuterRef('pk') order=OuterRef('pk')
).order_by().values('order').annotate(p=Sum('price')).values('p'), ).order_by().values('order').annotate(p=Sum('price')).values('p'),
output_field=models.DecimalField(decimal_places=2, max_digits=10) output_field=models.DecimalField(decimal_places=2, max_digits=10)
), Value(Decimal(0)), output_field=models.DecimalField(decimal_places=2, max_digits=10) ), Value(0), output_field=models.DecimalField(decimal_places=2, max_digits=10)
), ),
fee_total=Coalesce( fee_total=Coalesce(
Subquery( Subquery(
@@ -51,7 +51,7 @@ class Command(BaseCommand):
order=OuterRef('pk') order=OuterRef('pk')
).order_by().values('order').annotate(p=Sum('value')).values('p'), ).order_by().values('order').annotate(p=Sum('value')).values('p'),
output_field=models.DecimalField(decimal_places=2, max_digits=10) output_field=models.DecimalField(decimal_places=2, max_digits=10)
), Value(Decimal(0)), output_field=models.DecimalField(decimal_places=2, max_digits=10) ), Value(0), output_field=models.DecimalField(decimal_places=2, max_digits=10)
), ),
tx_total=Coalesce( tx_total=Coalesce(
Subquery( Subquery(
@@ -59,12 +59,12 @@ class Command(BaseCommand):
order=OuterRef('pk') order=OuterRef('pk')
).order_by().values('order').annotate(p=Sum(F('price') * F('count'))).values('p'), ).order_by().values('order').annotate(p=Sum(F('price') * F('count'))).values('p'),
output_field=models.DecimalField(decimal_places=2, max_digits=10) output_field=models.DecimalField(decimal_places=2, max_digits=10)
), Value(Decimal(0)), output_field=models.DecimalField(decimal_places=2, max_digits=10) ), Value(0), output_field=models.DecimalField(decimal_places=2, max_digits=10)
), ),
).annotate( ).annotate(
correct_total=Case( correct_total=Case(
When(Q(status=Order.STATUS_CANCELED) | Q(status=Order.STATUS_EXPIRED) | Q(require_approval=True), When(Q(status=Order.STATUS_CANCELED) | Q(status=Order.STATUS_EXPIRED) | Q(require_approval=True),
then=Value(Decimal(0))), then=Value(0)),
default=F('position_total') + F('fee_total'), default=F('position_total') + F('fee_total'),
output_field=models.DecimalField(decimal_places=2, max_digits=10) output_field=models.DecimalField(decimal_places=2, max_digits=10)
), ),
@@ -73,6 +73,9 @@ class Command(BaseCommand):
tx_total=F('correct_total') tx_total=F('correct_total')
).select_related('event') ).select_related('event')
for o in qs: for o in qs:
if abs(o.tx_total - o.correct_total) < Decimal('0.00001') and abs(o.position_total + o.fee_total - o.total) < Decimal('0.00001'):
# Ignore SQLite which treats Decimals like floats…
continue
print(f"Error in order {o.full_code}: status={o.status}, sum(positions)+sum(fees)={o.position_total + o.fee_total}, " print(f"Error in order {o.full_code}: status={o.status}, sum(positions)+sum(fees)={o.position_total + o.fee_total}, "
f"order.total={o.total}, sum(transactions)={o.tx_total}, expected={o.correct_total}") f"order.total={o.total}, sum(transactions)={o.tx_total}, expected={o.correct_total}")

View File

@@ -0,0 +1,26 @@
{% extends "error.html" %}
{% load i18n %}
{% load rich_text %}
{% load static %}
{% block title %}{% trans "Redirect" %}{% endblock %}
{% block content %}
<i class="fa fa-link fa-fw big-icon"></i>
<div class="error-details">
<h1>{% trans "Redirect" %}</h1>
<h3>
{% blocktrans trimmed with host="<strong>"|add:hostname|add:"</strong>"|safe %}
The link you clicked on wants to redirect you to a destination on the website {{ host }}.
{% endblocktrans %}
{% blocktrans trimmed %}
Please only proceed if you trust this website to be safe.
{% endblocktrans %}
</h3>
<p>
<a href="{{ url }}" class="btn btn-primary btn-lg">
{% blocktrans trimmed with host=hostname %}
Proceed to {{ host }}
{% endblocktrans %}
</a>
</p>
</div>
{% endblock %}

View File

@@ -24,6 +24,21 @@ import urllib.parse
from django.core import signing from django.core import signing
from django.http import HttpResponseBadRequest, HttpResponseRedirect from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.urls import reverse from django.urls import reverse
from django.shortcuts import render
def _is_samesite_referer(request):
referer = request.META.get('HTTP_REFERER')
if referer is None:
return False
referer = urllib.parse.urlparse(referer)
# Make sure we have a valid URL for Referer.
if '' in (referer.scheme, referer.netloc):
return False
return (referer.scheme, referer.netloc) == (request.scheme, request.get_host())
def redir_view(request): def redir_view(request):
@@ -32,6 +47,14 @@ def redir_view(request):
url = signer.unsign(request.GET.get('url', '')) url = signer.unsign(request.GET.get('url', ''))
except signing.BadSignature: except signing.BadSignature:
return HttpResponseBadRequest('Invalid parameter') return HttpResponseBadRequest('Invalid parameter')
if not _is_samesite_referer(request):
u = urllib.parse.urlparse(url)
return render(request, 'pretixbase/redirect.html', {
'hostname': u.hostname,
'url': url,
})
r = HttpResponseRedirect(url) r = HttpResponseRedirect(url)
r['X-Robots-Tag'] = 'noindex' r['X-Robots-Tag'] = 'noindex'
return r return r

View File

@@ -74,17 +74,17 @@
{{ c.datetime|date:"SHORT_DATETIME_FORMAT" }} {{ c.datetime|date:"SHORT_DATETIME_FORMAT" }}
{% if c.type == "exit" %} {% if c.type == "exit" %}
{% if c.auto_checked_in %} {% if c.auto_checked_in %}
<span class="fa fa-fw fa-hourglass-end" data-toggle="tooltip_html" <span class="fa fa-fw fa-hourglass-end" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically marked not present: {{ date }}{% endblocktrans %}"></span> title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically marked not present: {{ date }}{% endblocktrans %}"></span>
{% endif %} {% endif %}
{% elif c.forced and c.successful %} {% elif c.forced and c.successful %}
<span class="fa fa-fw fa-warning" data-toggle="tooltip_html" <span class="fa fa-fw fa-warning" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}"></span> title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}"></span>
{% elif c.forced and not c.successful %} {% elif c.forced and not c.successful %}
<br> <br>
<small class="text-muted">{% trans "Failed in offline mode" %}</small> <small class="text-muted">{% trans "Failed in offline mode" %}</small>
{% elif c.auto_checked_in %} {% elif c.auto_checked_in %}
<span class="fa fa-fw fa-magic" data-toggle="tooltip_html" <span class="fa fa-fw fa-magic" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}"></span> title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}"></span>
{% endif %} {% endif %}
</td> </td>

View File

@@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
<div class="quotabox availability" data-toggle="tooltip_html" data-placement="top" <div class="quotabox availability" data-toggle="tooltip_html" data-placement="top"
title="{% trans "Quota:" %} {{ q.name }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}"> title="{% trans "Quota:" %} {{ q.name|force_escape|force_escape }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}">
{% if q.size|default_if_none:"NONE" == "NONE" %} {% if q.size|default_if_none:"NONE" == "NONE" %}
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success progress-bar-100"> <div class="progress-bar progress-bar-success progress-bar-100">

View File

@@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
<a class="quotabox" data-toggle="tooltip_html" data-placement="top" <a class="quotabox" data-toggle="tooltip_html" data-placement="top"
title="{% trans "Quota:" %} {{ q.name }}{% if q.cached_avail.1 is not None %}<br>{% blocktrans with num=q.cached_avail.1 %}Currently available: {{ num }}{% endblocktrans %}{% endif %}" title="{% trans "Quota:" %} {{ q.name|force_escape|force_escape }}{% if q.cached_avail.1 is not None %}<br>{% blocktrans with num=q.cached_avail.1 %}Currently available: {{ num }}{% endblocktrans %}{% endif %}"
href="{% url "control:event.items.quotas.show" event=q.event.slug organizer=q.event.organizer.slug quota=q.pk %}"> href="{% url "control:event.items.quotas.show" event=q.event.slug organizer=q.event.organizer.slug quota=q.pk %}">
{% if q.size|default_if_none:"NONE" == "NONE" %} {% if q.size|default_if_none:"NONE" == "NONE" %}
<div class="progress"> <div class="progress">

View File

@@ -360,19 +360,19 @@
{% if line.checkins.all %} {% if line.checkins.all %}
{% for c in line.all_checkins.all %} {% for c in line.all_checkins.all %}
{% if not c.successful %} {% if not c.successful %}
<span class="fa fa-fw fa-exclamation-circle text-danger" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Denied scan: {{ date }}{% endblocktrans %}<br>{{ c.get_error_reason_display }}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw fa-exclamation-circle text-danger" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Denied scan: {{ date }}{% endblocktrans %}<br>{{ c.get_error_reason_display }}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% elif c.type == "exit" %} {% elif c.type == "exit" %}
{% if c.auto_checked_in %} {% if c.auto_checked_in %}
<span class="fa fa-fw text-success fa-hourglass-end" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically marked not present: {{ date }}{% endblocktrans %}"></span> <span class="fa fa-fw text-success fa-hourglass-end" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically marked not present: {{ date }}{% endblocktrans %}"></span>
{% else %} {% else %}
<span class="fa fa-fw text-success fa-sign-out" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Exit scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw text-success fa-sign-out" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Exit scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% endif %} {% endif %}
{% elif c.forced %} {% elif c.forced %}
<span class="fa fa-fw fa-warning text-warning" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw fa-warning text-warning" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% elif c.auto_checked_in %} {% elif c.auto_checked_in %}
<span class="fa fa-fw fa-magic text-success" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw fa-magic text-success" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% else %} {% else %}
<span class="fa fa-fw fa-check text-success" data-toggle="tooltip_html" title="{{ c.list.name }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span> <span class="fa fa-fw fa-check text-success" data-toggle="tooltip_html" title="{{ c.list.name|force_escape|force_escape }}<br>{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Entry scan: {{ date }}{% endblocktrans %}{% if c.gate %}<br>{{ c.gate }}{% endif %}"></span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@@ -3,7 +3,7 @@
<div class="form-horizontal stripe-container"> <div class="form-horizontal stripe-container">
{% if is_moto %} {% if is_moto %}
<h1> <h1>
<span class="label label-info pull-right flip" data-toggle="tooltip_html" title="{% trans "This transaction will be marked as Mail Order/Telephone Order, exempting it from Strong Customer Authentication (SCA) whenever possible" %}">MOTO</span> <span class="label label-info pull-right flip" data-toggle="tooltip" title="{% trans "This transaction will be marked as Mail Order/Telephone Order, exempting it from Strong Customer Authentication (SCA) whenever possible" %}">MOTO</span>
</h1> </h1>
<div class="clearfix"></div> <div class="clearfix"></div>
{% endif %} {% endif %}

View File

@@ -675,7 +675,21 @@ $(function () {
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip_html"]').tooltip({ $('[data-toggle="tooltip_html"]').tooltip({
'html': true 'html': true,
'whiteList': {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role'],
b: [],
br: [],
code: [],
div: [], // required for template
h3: ['class', 'role'], // required for template
i: [],
small: [],
span: [],
strong: [],
u: [],
}
}); });
var url = document.location.toString(); var url = document.location.toString();