From e4c7cd2c35aceee72e2ff39809b40fc926982469 Mon Sep 17 00:00:00 2001 From: Gerard Paligot Date: Mon, 4 May 2015 19:08:58 +0200 Subject: [PATCH] fix(mp): Throws a 403 exception when a user try to quote a wrong post. 1. Creates a decorator.py file in the mp module. 2. Adds the method is_participant to apply checks on view. 3. Adds this permission on the view PrivatePostAnswer. 4. Adds a test case. --- zds/mp/decorator.py | 23 +++++++++++++++++++++++ zds/mp/tests/tests_views.py | 19 +++++++++++++++++++ zds/mp/views.py | 5 ++--- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 zds/mp/decorator.py diff --git a/zds/mp/decorator.py b/zds/mp/decorator.py new file mode 100644 index 0000000000..1b7a7bb3ef --- /dev/null +++ b/zds/mp/decorator.py @@ -0,0 +1,23 @@ +# coding: utf-8 + +from django.core.exceptions import PermissionDenied +from django.shortcuts import get_object_or_404 +from zds.mp.models import PrivateTopic, PrivatePost + + +def is_participant(func): + """ + Checks if the current user is a participant of the private topic specified in the URL + and if the post specified in the GET parameter `cite` is on the private topic. + :param func: the decorated function + :return: `True` if the current user can read and write, `False` otherwise. + """ + def _is_participant(request, *args, **kwargs): + private_topic = get_object_or_404(PrivateTopic, pk=kwargs.get('pk')) + if not request.user == private_topic.author and request.user not in list(private_topic.participants.all()): + raise PermissionDenied + if 'cite' in request.GET: + if PrivatePost.objects.filter(privatetopic=private_topic).filter(pk=request.GET.get('cite')).count() != 1: + raise PermissionDenied + return func(request, *args, **kwargs) + return _is_participant diff --git a/zds/mp/tests/tests_views.py b/zds/mp/tests/tests_views.py index ba29bae9f1..59963ff8d7 100644 --- a/zds/mp/tests/tests_views.py +++ b/zds/mp/tests/tests_views.py @@ -492,6 +492,25 @@ def test_fail_cite_post_no_exist(self): self.assertEqual(404, response.status_code) + def test_fail_cite_post_not_in_current_topic(self): + another_topic = PrivateTopicFactory(author=self.profile2.user) + another_post = PrivatePostFactory( + privatetopic=another_topic, + author=self.profile2.user, + position_in_topic=1) + + response = self.client.get(reverse('private-posts-new', args=[self.topic1.pk, self.topic1.slug()]) + + '?cite={}'.format(another_post.pk)) + + self.assertEqual(403, response.status_code) + + def test_success_cite_post(self): + + response = self.client.get(reverse('private-posts-new', args=[self.topic1.pk, self.topic1.slug()]) + + '?cite={}'.format(self.post2.pk)) + + self.assertEqual(200, response.status_code) + def test_success_preview_answer(self): response = self.client.post( diff --git a/zds/mp/views.py b/zds/mp/views.py index 9a60db666c..3a26cfbd00 100644 --- a/zds/mp/views.py +++ b/zds/mp/views.py @@ -23,6 +23,7 @@ from django.utils.translation import ugettext as _ from zds.member.models import Profile +from zds.mp.decorator import is_participant from zds.utils.mps import send_mp from zds.utils.paginator import ZdSPagingListView from zds.utils.templatetags.emarkdown import emarkdown @@ -287,6 +288,7 @@ class PrivatePostAnswer(CreateView): queryset = PrivateTopic.objects.all() @method_decorator(login_required) + @method_decorator(is_participant) def dispatch(self, request, *args, **kwargs): return super(PrivatePostAnswer, self).dispatch(request, *args, **kwargs) @@ -296,9 +298,6 @@ def get_object(self, queryset=None): .filter(privatetopic=self.topic) \ .prefetch_related() \ .order_by("-pubdate")[:settings.ZDS_APP['forum']['posts_per_page']] - if not self.request.user == self.topic.author \ - and self.request.user not in list(self.topic.participants.all()): - raise PermissionDenied return self.topic def get(self, request, *args, **kwargs):