Просмотр исходного кода

wip #893: some input sanity checks for user API's

Rafał Pitoń 7 лет назад
Родитель
Сommit
e24149a6b9

+ 14 - 0
misago/core/decorators.py

@@ -1,3 +1,5 @@
+from rest_framework import serializers
+
 from .errorpages import not_allowed
 
 
@@ -19,3 +21,15 @@ def require_POST(f):
             return f(request, *args, **kwargs)
 
     return decorator
+
+
+def require_dict_data(f):
+    def decorator(request, *args, **kwargs):
+        if request.method == 'POST':
+            DummySerializer(data=request.data).is_valid(raise_exception=True)
+        return f(request, *args, **kwargs)
+    return decorator
+
+
+class DummySerializer(serializers.Serializer):
+    pass

+ 5 - 0
misago/users/api/auth.py

@@ -9,6 +9,7 @@ from django.utils.translation import ugettext as _
 from django.views.decorators.csrf import csrf_protect
 
 from misago.conf import settings
+from misago.core.decorators import require_dict_data
 from misago.core.mail import mail_user
 from misago.users.bans import get_user_ban
 from misago.users.forms.auth import AuthenticationForm, ResendActivationForm, ResetPasswordForm
@@ -32,6 +33,7 @@ def gateway(request):
 @api_view(['POST'])
 @permission_classes((UnbannedAnonOnly, ))
 @csrf_protect
+@require_dict_data
 def login(request):
     """
     POST /auth/ with CSRF, username and password
@@ -85,6 +87,7 @@ def get_criteria(request):
 @api_view(['POST'])
 @permission_classes((UnbannedAnonOnly, ))
 @csrf_protect
+@require_dict_data
 def send_activation(request):
     """
     POST /auth/send-activation/ with CSRF token and email
@@ -123,6 +126,7 @@ def send_activation(request):
 @api_view(['POST'])
 @permission_classes((UnbannedOnly, ))
 @csrf_protect
+@require_dict_data
 def send_password_form(request):
     """
     POST /auth/send-password-form/ with CSRF token and email
@@ -167,6 +171,7 @@ class PasswordChangeFailed(Exception):
 @api_view(['POST'])
 @permission_classes((UnbannedOnly, ))
 @csrf_protect
+@require_dict_data
 def change_forgotten_password(request, pk, token):
     """
     POST /auth/change-password/user/token/ with CSRF and new password

+ 2 - 0
misago/users/api/userendpoints/avatar.py

@@ -7,12 +7,14 @@ from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext as _
 
 from misago.conf import settings
+from misago.core.decorators import require_dict_data
 from misago.core.utils import format_plaintext_for_html
 from misago.users import avatars
 from misago.users.models import AvatarGallery
 from misago.users.serializers import ModerateAvatarSerializer
 
 
+@require_dict_data
 def avatar_endpoint(request, pk=None):
     if request.user.is_avatar_locked:
         if request.user.avatar_lock_user_message:

+ 37 - 1
misago/users/tests/test_auth_api.py

@@ -84,6 +84,15 @@ class GatewayTests(TestCase):
         response = self.client.post('/api/auth/')
         self.assertContains(response, 'empty_data', status_code=400)
 
+    def test_submit_invalid(self):
+        """login api errors for invalid data"""
+        response = self.client.post(
+            '/api/auth/',
+            'false',
+            content_type="application/json",
+        )
+        self.assertContains(response, "Invalid data.", status_code=400)
+
     def test_login_banned(self):
         """login api fails to sign banned user in"""
         UserModel.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
@@ -279,7 +288,16 @@ class SendActivationAPITests(TestCase):
 
         self.assertTrue(not mail.outbox)
 
-    def test_submit_invalid(self):
+    def test_submit_invalid_data(self):
+        """login api errors for invalid data"""
+        response = self.client.post(
+            self.link,
+            'false',
+            content_type="application/json",
+        )
+        self.assertContains(response, "Invalid data.", status_code=400)
+
+    def test_submit_invalid_email(self):
         """request activation link api errors for invalid email"""
         response = self.client.post(
             self.link,
@@ -403,6 +421,15 @@ class SendPasswordFormAPITests(TestCase):
 
         self.assertTrue(not mail.outbox)
 
+    def test_submit_invalid_data(self):
+        """login api errors for invalid data"""
+        response = self.client.post(
+            self.link,
+            'false',
+            content_type="application/json",
+        )
+        self.assertContains(response, "Invalid data.", status_code=400)
+
     def test_submit_inactive_user(self):
         """request change password form link api errors for inactive users"""
         self.user.requires_activation = 1
@@ -462,6 +489,15 @@ class ChangePasswordAPITests(TestCase):
         user = UserModel.objects.get(id=self.user.pk)
         self.assertTrue(user.check_password(' n3wp4ss! '))
 
+    def test_submit_invalid_data(self):
+        """login api errors for invalid data"""
+        response = self.client.post(
+            self.link % (self.user.pk, make_password_change_token(self.user)),
+            'false',
+            content_type="application/json",
+        )
+        self.assertContains(response, "Invalid data.", status_code=400)
+
     def test_invalid_token_link(self):
         """api errors on invalid user id link"""
         response = self.client.post(self.link % (self.user.pk, 'asda7ad89sa7d9s789as'))

+ 9 - 0
misago/users/tests/test_user_create_api.py

@@ -23,6 +23,15 @@ class UserCreateTests(UserTestCase):
         response = self.client.post(self.api_link)
         self.assertEqual(response.status_code, 400)
 
+    def test_invalid_data(self):
+        """invalid request data errors with code 400"""
+        response = self.client.post(
+            self.api_link,
+            'false',
+            content_type="application/json",
+        )
+        self.assertEqual(response.status_code, 400)
+
     def test_authenticated_request(self):
         """authentiated user request errors with code 403"""
         self.login_user(self.get_authenticated_user())