Easier PCI DSS compliance for payment pages (#4273)

* Assign names to compressed scripts

* Make PCI-relevant pages detectable

* Make payment summary markup more consistant to easy work in tracking plugin

* Add docs note
This commit is contained in:
Raphael Michel
2024-07-31 13:11:38 +02:00
committed by GitHub
parent 78cfbd6460
commit 13720e731e
12 changed files with 68 additions and 20 deletions

View File

@@ -2,7 +2,7 @@
{% load compress %}
{% load i18n %}
{% compress js %}
{% compress js file paypal %}
<script type="text/javascript" src="{% static "pretixplugins/paypal2/pretix-paypal.js" %}"></script>
{% endcompress %}

View File

@@ -185,6 +185,10 @@ class XHRView(View):
class PayView(PaypalOrderView, TemplateView):
template_name = ''
def dispatch(self, request, *args, **kwargs):
self.request.pci_dss_payment_page = True
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
if self.payment.state != OrderPayment.PAYMENT_STATE_CREATED:
return self._redirect_to_order()

View File

@@ -2,10 +2,10 @@
{% load compress %}
{% load i18n %}
{% compress js %}
{% compress js file stripe %}
<script type="text/javascript" src="{% static "pretixplugins/stripe/pretix-stripe.js" %}"></script>
{% endcompress %}
{% compress css %}
{% compress css file stripe %}
<link type="text/css" rel="stylesheet" href="{% static "pretixplugins/stripe/pretix-stripe.css" %}">
{% endcompress %}
{% if testmode %}

View File

@@ -1263,6 +1263,7 @@ class PaymentStep(CartMixin, TemplateFlowStep):
def post(self, request):
self.request = request
self.request.pci_dss_payment_page = True
if "remove_payment" in request.POST:
self._remove_payment(request.POST["remove_payment"])
@@ -1427,6 +1428,10 @@ class PaymentStep(CartMixin, TemplateFlowStep):
return True
def get(self, request):
self.request.pci_dss_payment_page = True
return super().get(request)
class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
priority = 1001

View File

@@ -78,6 +78,11 @@ of every page in the frontend. You will get the request as the keyword argument
``request`` and are expected to return plain HTML.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
**Note:** If PCI DSS compliance is important to you and you keep an inventory according to
rule 6.4.3 of PCI DSS, all plugins that are not required to load on a payment page should
not return additional JavaScripts if ``getattr(request, 'pci_dss_payment_page', False)``
is ``True``.
"""
seatingframe_html_head = EventPluginSignal()
@@ -112,6 +117,11 @@ of every page in the frontend. You will get the request as the keyword argument
``request`` and are expected to return plain HTML.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
**Note:** If PCI DSS compliance is important to you and you keep an inventory according to
rule 6.4.3 of PCI DSS, all plugins that are not required to load on a payment page should
not return additional JavaScripts if ``getattr(request, 'pci_dss_payment_page', False)``
is ``True``.
"""
footer_link = EventPluginSignal()

View File

@@ -8,7 +8,7 @@
<html{% if rtl %} dir="rtl" class="rtl"{% endif %} lang="{{ html_locale }}">
<head>
<title>{% block thetitle %}{% endblock %}</title>
{% compress css %}
{% compress css file presale %}
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixpresale/scss/main.scss" %}"/>
{% endcompress %}
{% if css_theme %}
@@ -92,7 +92,7 @@
<script src="{% statici18n request.LANGUAGE_CODE %}"></script>
{% endif %}
{% if request.session.iframe_session %}
{% compress js %}
{% compress js file iframeresizer %}
<script type="text/javascript" src="{% static "iframeresizer/iframeResizer.contentWindow.js" %}"></script>
{% endcompress %}
{% endif %}

View File

@@ -50,19 +50,15 @@
<ul class="list-group">
{% for payment, rendered_block in payments %}
<li class="list-group-item payment">
{% if payments|length > 1 %}
<div class="row">
<div class="col-sm-10 col-xs-12">
<h4>{{ payment.provider_name }}</h4>
{{ rendered_block }}
</div>
<div class="col-sm-2 col-xs-12 text-right">
<h4>{{ payment.payment_amount|money:request.event.currency }}</h4>
</div>
<div class="row">
<div class="{% if payments|length > 1 %}col-sm-10 {% endif %}col-xs-12">
<h4 {% if payments|length == 1 %}class="sr-only"{% endif %}>{{ payment.provider_name }}</h4>
{{ rendered_block }}
</div>
{% else %}
{{ rendered_block }}
{% endif %}
<div class="col-sm-2 col-xs-12 text-right {% if payments|length == 1 %}sr-only{% endif %}">
<h4>{{ payment.payment_amount|money:request.event.currency }}</h4>
</div>
</div>
</li>
{% endfor %}
</ul>

View File

@@ -1,6 +1,6 @@
{% load static %}
{% load compress %}
{% compress js %}
{% compress js file walletdetection %}
<script type="text/javascript" src="{% static "pretixpresale/js/walletdetection.js" %}"></script>
{% endcompress %}

View File

@@ -1,6 +1,6 @@
{% load static %}
{% load compress %}
{% compress js %}
{% compress js file presale %}
<script type="text/javascript" src="{% static "jquery/js/jquery-3.6.4.min.js" %}"></script>
<script type="text/javascript" src="{% static "moment/moment-with-locales.js" %}"></script>
<script type="text/javascript" src="{% static "moment/moment-timezone-with-data-1970-2030.js" %}"></script>

View File

@@ -359,6 +359,7 @@ class OrderPaymentStart(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
self.request.pci_dss_payment_page = True
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if (self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED)
@@ -553,6 +554,7 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
self.request.pci_dss_payment_page = True
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) or self.order._can_be_paid() is not True: