Compare commits

..

1 Commits

Author SHA1 Message Date
Martin Gross
582b8d815e PPv2: Handle payment execution/capture calls properly even if no captures are present yet. 2026-02-19 17:45:52 +01:00
2 changed files with 38 additions and 40 deletions

View File

@@ -34,7 +34,9 @@ def set_cookie_without_samesite(request, response, key, *args, **kwargs):
if not is_secure:
# https://www.chromestatus.com/feature/5633521622188032
return
useragent = request.headers.get('User-Agent', '')
if should_send_same_site_none(useragent):
# Chromium is rolling out SameSite=Lax as a default
# https://www.chromestatus.com/feature/5088147346030592
@@ -45,33 +47,13 @@ def set_cookie_without_samesite(request, response, key, *args, **kwargs):
# This will only work on secure cookies as well
# https://www.chromestatus.com/feature/5633521622188032
response.cookies[key]['secure'] = is_secure
# CHIPS
response.cookies[key]['Partitioned'] = True
if has_safari_partitioned_bug(useragent):
# There may be partitioned cookies set from previous sessions, which override
# these non-partitioned ones. Delete these partitioned cookies.
response.delete_cookie(key)
response.cookies[key + ":Partitioned"] = response.cookies[key]
del response.cookies[key]
# re-set the cookie without Partitioned
response.set_cookie(key, *args, **kwargs)
response.cookies[key]['samesite'] = 'None'
response.cookies[key]['secure'] = is_secure
if can_send_partitioned_cookie(useragent):
# CHIPS
response.cookies[key]['Partitioned'] = True
# Based on https://www.chromium.org/updates/same-site/incompatible-clients
# Copyright 2019 Google LLC.
# SPDX-License-Identifier: Apache-2.0
def should_send_same_site_none(useragent):
# Dont send `SameSite=None` to known incompatible clients.
return not has_web_kit_same_site_bug(useragent) and not drops_unrecognized_same_site_cookies(useragent)
def has_safari_partitioned_bug(useragent):
def can_send_partitioned_cookie(useragent):
# Safari currently exhibits a bug where Partitioned cookies (CHIPS) are not
# sent back to the originating site after multi-hop cross-site redirects,
# breaking SSO login flows in pretix.
@@ -87,7 +69,17 @@ def has_safari_partitioned_bug(useragent):
#
# - https://bugs.webkit.org/show_bug.cgi?id=292975
# - https://bugs.webkit.org/show_bug.cgi?id=306194
return is_safari(useragent)
return not is_safari(useragent)
# Based on https://www.chromium.org/updates/same-site/incompatible-clients
# Copyright 2019 Google LLC.
# SPDX-License-Identifier: Apache-2.0
def should_send_same_site_none(useragent):
# Dont send `SameSite=None` to known incompatible clients.
return not has_web_kit_same_site_bug(useragent) and not drops_unrecognized_same_site_cookies(useragent)
def has_web_kit_same_site_bug(useragent):

View File

@@ -786,23 +786,29 @@ class PaypalMethod(BasePaymentProvider):
else:
pp_captured_order = response.result
for purchaseunit in pp_captured_order.purchase_units:
for capture in purchaseunit.payments.captures:
try:
ReferencedPayPalObject.objects.get_or_create(order=payment.order, payment=payment, reference=capture.id)
except ReferencedPayPalObject.MultipleObjectsReturned:
pass
if capture.status != 'COMPLETED':
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
'soon as the payment completed.'))
payment.info = json.dumps(pp_captured_order.dict())
payment.state = OrderPayment.PAYMENT_STATE_PENDING
payment.save()
return
payment.refresh_from_db()
any_captures = False
all_captures_completed = True
for purchaseunit in pp_captured_order.purchase_units:
for capture in purchaseunit.payments.captures:
try:
ReferencedPayPalObject.objects.get_or_create(order=payment.order, payment=payment, reference=capture.id)
except ReferencedPayPalObject.MultipleObjectsReturned:
pass
if capture.status != 'COMPLETED':
all_captures_completed = False
else:
any_captures = True
if not (any_captures and all_captures_completed):
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
'soon as the payment completed.'))
payment.info = json.dumps(pp_captured_order.dict())
payment.state = OrderPayment.PAYMENT_STATE_PENDING
payment.save()
return
if pp_captured_order.status != 'COMPLETED':
payment.fail(info=pp_captured_order.dict())
logger.error('Invalid state: %s' % repr(pp_captured_order.dict()))