diff --git a/api/config/settings/common.py b/api/config/settings/common.py index 13624511c..3000feddb 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -536,11 +536,11 @@ REST_FRAMEWORK = { ), "DEFAULT_AUTHENTICATION_CLASSES": ( "oauth2_provider.contrib.rest_framework.OAuth2Authentication", - "rest_framework.authentication.SessionAuthentication", "funkwhale_api.common.authentication.JSONWebTokenAuthenticationQS", "funkwhale_api.common.authentication.BearerTokenHeaderAuth", "funkwhale_api.common.authentication.JSONWebTokenAuthentication", "rest_framework.authentication.BasicAuthentication", + "rest_framework.authentication.SessionAuthentication", ), "DEFAULT_PERMISSION_CLASSES": ( "funkwhale_api.users.oauth.permissions.ScopePermission", diff --git a/api/funkwhale_api/common/permissions.py b/api/funkwhale_api/common/permissions.py index 4ab405eb4..237fc4ae4 100644 --- a/api/funkwhale_api/common/permissions.py +++ b/api/funkwhale_api/common/permissions.py @@ -47,6 +47,6 @@ class OwnerPermission(BasePermission): owner_field = getattr(view, "owner_field", "user") owner = operator.attrgetter(owner_field)(obj) - if owner != request.user: + if not owner or not request.user.is_authenticated or owner != request.user: raise Http404 return True diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py index f19c6b884..a0dc36b62 100644 --- a/api/funkwhale_api/radios/radios.py +++ b/api/funkwhale_api/radios/radios.py @@ -47,6 +47,8 @@ class SessionRadio(SimpleRadio): qs = Track.objects.all() if not self.session: return qs + if not self.session.user: + return qs query = moderation_filters.get_filtered_content_query( config=moderation_filters.USER_FILTER_CONFIG["TRACK"], user=self.session.user, @@ -62,7 +64,9 @@ class SessionRadio(SimpleRadio): if self.session: queryset = self.filter_from_session(queryset) if kwargs.pop("filter_playable", True): - queryset = queryset.playable_by(self.session.user.actor) + queryset = queryset.playable_by( + self.session.user.actor if self.session.user else None + ) queryset = self.filter_queryset(queryset) return queryset @@ -129,7 +133,7 @@ class CustomRadio(SessionRadio): try: user = data["user"] except KeyError: - user = context["user"] + user = context.get("user") try: assert data["custom_radio"].user == user or data["custom_radio"].is_public except KeyError: diff --git a/api/funkwhale_api/radios/serializers.py b/api/funkwhale_api/radios/serializers.py index 9bffbf5b9..397452ecc 100644 --- a/api/funkwhale_api/radios/serializers.py +++ b/api/funkwhale_api/radios/serializers.py @@ -70,7 +70,7 @@ class RadioSessionSerializer(serializers.ModelSerializer): return data def create(self, validated_data): - validated_data["user"] = self.context["user"] + validated_data["user"] = self.context.get("user") if validated_data.get("related_object_id"): radio = registry[validated_data["radio_type"]]() validated_data["related_object"] = radio.get_related_object( diff --git a/api/funkwhale_api/radios/views.py b/api/funkwhale_api/radios/views.py index fa0a6fe4a..0a5f1cd6c 100644 --- a/api/funkwhale_api/radios/views.py +++ b/api/funkwhale_api/radios/views.py @@ -1,5 +1,5 @@ from django.db.models import Q -from rest_framework import mixins, permissions, status, viewsets +from rest_framework import mixins, status, viewsets from rest_framework.decorators import action from rest_framework.response import Response @@ -28,6 +28,7 @@ class RadioViewSet( required_scope = "radios" owner_field = "user" owner_checks = ["write"] + anonymous_policy = "setting" def get_queryset(self): queryset = models.Radio.objects.all() @@ -82,11 +83,30 @@ class RadioSessionViewSet( serializer_class = serializers.RadioSessionSerializer queryset = models.RadioSession.objects.all() - permission_classes = [permissions.IsAuthenticated] + permission_classes = [] def get_queryset(self): queryset = super().get_queryset() - return queryset.filter(user=self.request.user) + if self.request.user.is_authenticated: + return queryset.filter( + Q(user=self.request.user) + | Q(session_key=self.request.session.session_key) + ) + + return queryset.filter(session_key=self.request.session.session_key).exclude( + session_key=None + ) + + def perform_create(self, serializer): + if ( + not self.request.user.is_authenticated + and not self.request.session.session_key + ): + self.request.session.create() + return serializer.save( + user=self.request.user if self.request.user.is_authenticated else None, + session_key=self.request.session.session_key, + ) def get_serializer_context(self): context = super().get_serializer_context() @@ -97,14 +117,19 @@ class RadioSessionViewSet( class RadioSessionTrackViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet): serializer_class = serializers.RadioSessionTrackSerializer queryset = models.RadioSessionTrack.objects.all() - permission_classes = [permissions.IsAuthenticated] + permission_classes = [] def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) session = serializer.validated_data["session"] + if not request.user.is_authenticated and not request.session.session_key: + self.request.session.create() try: - assert request.user == session.user + assert (request.user == session.user) or ( + request.session.session_key == session.session_key + and session.session_key + ) except AssertionError: return Response(status=status.HTTP_403_FORBIDDEN) session.radio.pick() diff --git a/changes/changelog.d/563.bugfix b/changes/changelog.d/563.bugfix new file mode 100644 index 000000000..14f49b75e --- /dev/null +++ b/changes/changelog.d/563.bugfix @@ -0,0 +1 @@ +Fixed unplayable radios for anonymous users (#563) diff --git a/front/src/components/library/Radios.vue b/front/src/components/library/Radios.vue index 68eb11f0b..9b2f7bf82 100644 --- a/front/src/components/library/Radios.vue +++ b/front/src/components/library/Radios.vue @@ -10,9 +10,9 @@ Instance radios
- + - +
diff --git a/front/src/store/auth.js b/front/src/store/auth.js index 29c4c5d71..52cc98a6d 100644 --- a/front/src/store/auth.js +++ b/front/src/store/auth.js @@ -118,10 +118,6 @@ export default { } }, fetchProfile ({commit, dispatch, state}) { - if (document) { - // this is to ensure we do not have any leaking cookie set by django - document.cookie = 'sessionid=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;' - } return new Promise((resolve, reject) => { axios.get('users/users/me/').then((response) => {