From 958e318b4cf4195807d35bf03211f0700cc61650 Mon Sep 17 00:00:00 2001 From: Lukas Bockstaller Date: Mon, 13 Apr 2026 13:37:57 +0200 Subject: [PATCH] add permission checks in to_representation --- src/pretix/api/serializers/media.py | 39 +++++++++++++++++++++++-- src/pretix/api/serializers/organizer.py | 19 ++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/pretix/api/serializers/media.py b/src/pretix/api/serializers/media.py index 894c1bcf0..ea1cee8cd 100644 --- a/src/pretix/api/serializers/media.py +++ b/src/pretix/api/serializers/media.py @@ -31,7 +31,7 @@ from pretix.api.serializers.order import OrderPositionSerializer from pretix.api.serializers.organizer import ( CustomerSerializer, GiftCardSerializer, ) -from pretix.base.models import Order, OrderPosition, ReusableMedium +from pretix.base.models import Device, Order, OrderPosition, ReusableMedium, TeamAPIToken, User logger = logging.getLogger(__name__) @@ -80,8 +80,7 @@ class ReusableMediaSerializer(I18nAwareModelSerializer): ) if 'linked_orderposition' in self.context['request'].query_params.getlist('expand'): - # No additional permission check performed, documented limitation of the permission system - # Would get to complex/unusable otherwise since the permission depends on the event + # Permission Check performed in to_representation self.fields['linked_orderposition'] = NestedOrderPositionSerializer(read_only=True) else: self.fields['linked_orderposition'] = serializers.PrimaryKeyRelatedField( @@ -117,6 +116,40 @@ class ReusableMediaSerializer(I18nAwareModelSerializer): ) return data + def to_representation(self, instance): + request = self.context.get('request') + + # late permission evaluations for checks that depend on the actual linked events + if 'linked_orderposition' in self.context['request'].query_params.getlist('expand'): + if instance.linked_orderposition is not None: + event = instance.linked_orderposition.order.event + if not ( + request.user if request.user and request.user.is_authenticated else request.auth + ).has_event_permission(organizer=event.organizer, event=event, perm_name='event.orders:read', request=request): + pos_serializer = self.fields['linked_orderposition'] + allowed = {'id'} + for field_name in list(pos_serializer.fields.keys()): + if field_name not in allowed: + pos_serializer.fields.pop(field_name) + + if 'linked_giftcard.owner_ticket' in self.context['request'].query_params.getlist('expand'): + gc = instance.linked_giftcard + if gc is not None and gc.owner_ticket is not None: + event = gc.owner_ticket.order.event + if not ( + request.user if request.user and request.user.is_authenticated else request.auth + ).has_event_permission(organizer=event.organizer, event=event, perm_name='event.orders:read', request=request): + ticket_serializer = self.fields['linked_giftcard'].fields['owner_ticket'] + allowed = {'id'} + for field_name in list(ticket_serializer.fields.keys()): + if field_name not in allowed: + ticket_serializer.fields.pop(field_name) + + + return super().to_representation(instance) + + + class Meta: model = ReusableMedium fields = ( diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py index 05f25976a..bc1686045 100644 --- a/src/pretix/api/serializers/organizer.py +++ b/src/pretix/api/serializers/organizer.py @@ -286,6 +286,25 @@ class GiftCardSerializer(I18nAwareModelSerializer): ) return data + def to_representation(self, instance): + request = self.context.get('request') + + # late permission evaluations for checks that depend on the actual linked events + if 'owner_ticket' in self.context['request'].query_params.getlist('expand'): + owner_ticket = instance.owner_ticket + if owner_ticket: + event = owner_ticket.order.event + if not ( + request.user if request.user and request.user.is_authenticated else request.auth + ).has_event_permission(organizer=event.organizer, event=event, perm_name='event.orders:read', request=request): + ticket_serializer = self.fields['owner_ticket'].read + allowed = {'id'} + for field_name in list(ticket_serializer.fields.keys()): + if field_name not in allowed: + ticket_serializer.fields.pop(field_name) + + return super().to_representation(instance) + class Meta: model = GiftCard fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions', 'owner_ticket',