Browse Source

feat(api): make sure domains are well-formed, closes #2

Peter Thomassen 8 years ago
parent
commit
ac02fd4d59

+ 0 - 0
api/desecapi/migrations/0012_auto_20170124_1411.py → api/desecapi/migrations/0012_move_dyn_flag.py


+ 20 - 0
api/desecapi/tests/testdomains.py

@@ -30,6 +30,7 @@ class UnauthenticatedDomainTests(APITestCase):
         response = self.client.delete(url, format='json')
         self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
 
+
 class AuthenticatedDomainTests(APITestCase):
     def setUp(self):
         if not hasattr(self, 'owner'):
@@ -101,6 +102,12 @@ class AuthenticatedDomainTests(APITestCase):
         response = self.client.post(url, data)
         self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
 
+    def testCanPostComplicatedDomains(self):
+        url = reverse('domain-list')
+        data = {'name': 'very.long.domain.name.' + utils.generateDomainname()}
+        response = self.client.post(url, data)
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
     def testCanUpdateARecord(self):
         url = reverse('domain-detail', args=(self.ownedDomains[1].pk,))
         response = self.client.get(url)
@@ -167,6 +174,7 @@ class AuthenticatedDomainTests(APITestCase):
         self.assertTrue(("/%d" % self.ownedDomains[1].pk) in url)
         self.assertTrue("/" + self.ownedDomains[1].name in urlByName)
 
+
 class AuthenticatedDynDomainTests(APITestCase):
     def setUp(self):
         if not hasattr(self, 'owner'):
@@ -186,6 +194,18 @@ class AuthenticatedDynDomainTests(APITestCase):
         self.assertTrue(data['name'] in email)
         self.assertTrue(self.token in email)
 
+    def testCantPostNonDynDomains(self):
+        url = reverse('domain-list')
+
+        data = {'name': utils.generateDomainname()}
+        response = self.client.post(url, data)
+        self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
+
+        data = {'name': 'very.long.domain.' + utils.generateDynDomainname()}
+        response = self.client.post(url, data)
+        self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
+
+
     def testLimitDynDomains(self):
         httpretty.enable()
         httpretty.register_uri(httpretty.POST, settings.POWERDNS_API + '/zones')

+ 14 - 3
api/desecapi/views.py

@@ -26,6 +26,11 @@ from desecapi.forms import UnlockForm
 from django.shortcuts import render
 from django.http import HttpResponseRedirect
 from desecapi.emails import send_account_lock_email
+import re
+
+# TODO Generalize?
+patternDyn = re.compile(r'^[A-Za-z][A-Za-z0-9-]*\.dedyn\.io$')
+patternNonDyn = re.compile(r'^([A-Za-z][A-Za-z0-9-]*\.)+[A-Za-z]+$')
 
 
 def get_client_ip(request):
@@ -40,15 +45,21 @@ class DomainList(generics.ListCreateAPIView):
         return Domain.objects.filter(owner=self.request.user.pk)
 
     def perform_create(self, serializer):
+        pattern = patternDyn if self.request.user.dyn else patternNonDyn
+        if pattern.match(serializer.validated_data['name']) is None or "--" in serializer.validated_data['name']:
+            ex = ValidationError(detail={"detail": "This domain name is not well-formed, by policy.", "code": "domain-illformed"})
+            ex.status_code = status.HTTP_409_CONFLICT
+            raise ex
+
         queryset = Domain.objects.filter(name=serializer.validated_data['name'])
         if queryset.exists():
             ex = ValidationError(detail={"detail": "This domain name is already registered.", "code": "domain-taken"})
-            ex.status_code = 409
+            ex.status_code = status.HTTP_409_CONFLICT
             raise ex
 
         if self.request.user.limit_domains is not None and self.request.user.domains.count() >= self.request.user.limit_domains:
             ex = ValidationError(detail={"detail": "You reached the maximum number of domains allowed for your account.", "code": "domain-limit"})
-            ex.status_code = 403
+            ex.status_code = status.HTTP_403_FORBIDDEN
             raise ex
 
         obj = serializer.save(owner=self.request.user)
@@ -111,7 +122,7 @@ class DnsQuery(APIView):
         desecio = resolver.Resolver()
 
         if not 'domain' in request.GET:
-            return Response(status=400)
+            return Response(status=status.HTTP_400_BAD_REQUEST)
 
         domain = str(request.GET['domain'])