ソースを参照

Merge pull request #48 from desec-io/20170113_IPvalidation

IP Address Validation
Peter Thomassen 8 年 前
コミット
1eb2607800

+ 25 - 0
api/desecapi/migrations/0014_ip_validation.py

@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-01-11 15:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('desecapi', '0013_acme_challenge'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='domain',
+            name='aaaarecord',
+            field=models.GenericIPAddressField(blank=False, null=True, protocol='IPv6'),
+        ),
+        migrations.AlterField(
+            model_name='domain',
+            name='arecord',
+            field=models.GenericIPAddressField(blank=False, null=True, protocol='IPv4'),
+        ),
+    ]

+ 4 - 2
api/desecapi/models.py

@@ -7,6 +7,8 @@ from django.utils import timezone
 from django.core.exceptions import ValidationError
 from desecapi import pdns
 import datetime, time
+import django.core.exceptions
+import rest_framework.exceptions
 
 
 class MyUserManager(BaseUserManager):
@@ -96,8 +98,8 @@ class Domain(models.Model):
     created = models.DateTimeField(auto_now_add=True)
     updated = models.DateTimeField(null=True)
     name = models.CharField(max_length=191, unique=True)
-    arecord = models.CharField(max_length=255, blank=True)
-    aaaarecord = models.CharField(max_length=1024, blank=True)
+    arecord = models.GenericIPAddressField(protocol='IPv4', blank=False, null=True)
+    aaaarecord = models.GenericIPAddressField(protocol='IPv6', blank=False, null=True)
     owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='domains')
     acme_challenge = models.CharField(max_length=255, blank=True)
     _dirtyName = False

+ 8 - 8
api/desecapi/pdns.py

@@ -69,16 +69,16 @@ def _pdns_put(url):
     return r
 
 
-def _delete_or_replace_rrset(name, type, value, ttl=60):
+def _delete_or_replace_rrset(name, rr_type, value, ttl=60):
     """
     Return pdns API json to either replace or delete a record set, depending on whether value is empty or not.
     """
-    if value != "":
+    if value:
         return \
             {
                 "records": [
                     {
-                        "type": type,
+                        "type": rr_type,
                         "name": name,
                         "disabled": False,
                         "content": value,
@@ -86,14 +86,14 @@ def _delete_or_replace_rrset(name, type, value, ttl=60):
                 ],
                 "ttl": ttl,
                 "changetype": "REPLACE",
-                "type": type,
+                "type": rr_type,
                 "name": name,
             }
     else:
         return \
             {
                 "changetype": "DELETE",
-                "type": type,
+                "type": rr_type,
                 "name": name
             }
 
@@ -138,7 +138,7 @@ def notify_zone(name):
     """
     Commands pdns to notify the zone to the pdns slaves.
     """
-    return _pdns_put('/zones/%s/notify' % normalize_hostname(name))
+    _pdns_put('/zones/%s/notify' % normalize_hostname(name))
 
 
 def set_dyn_records(name, a, aaaa, acme_challenge=''):
@@ -160,7 +160,7 @@ def set_dyn_records(name, a, aaaa, acme_challenge=''):
     notify_zone(name)
 
 
-def set_rrset(zone, name, type, value):
+def set_rrset(zone, name, rr_type, value):
     """
     Commands pdns to set or delete a record set for the zone with the given name.
     If value is empty, the rrset will be deleted.
@@ -170,6 +170,6 @@ def set_rrset(zone, name, type, value):
 
     _pdns_patch('/zones/' + zone, {
         "rrsets": [
-            _delete_or_replace_rrset(name, type, value),
+            _delete_or_replace_rrset(name, rr_type, value),
         ]
     })

+ 16 - 11
api/desecapi/tests/testdomains.py

@@ -7,6 +7,7 @@ from desecapi.models import Domain
 from django.core import mail
 import httpretty
 from django.conf import settings
+import json
 
 
 class UnauthenticatedDomainTests(APITestCase):
@@ -95,7 +96,7 @@ class AuthenticatedDomainTests(APITestCase):
         url = reverse('domain-detail', args=(self.ownedDomains[1].pk,))
         response = self.client.get(url)
         response.data['arecord'] = '1.2.3.4'
-        response = self.client.put(url, response.data)
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         response = self.client.get(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -106,7 +107,9 @@ class AuthenticatedDomainTests(APITestCase):
         response = self.client.get(url)
         newname = utils.generateDomainname()
         response.data['name'] = newname
-        response = self.client.put(url, response.data)
+        response.data['arecord'] = None
+        response.data['aaaarecord'] = None
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
         response = self.client.get(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -114,7 +117,7 @@ class AuthenticatedDomainTests(APITestCase):
 
     def testCantPutOtherDomains(self):
         url = reverse('domain-detail', args=(self.otherDomains[1].pk,))
-        response = self.client.put(url, {})
+        response = self.client.put(url, json.dumps({}), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
     def testCanPostDomains(self):
@@ -154,7 +157,8 @@ class AuthenticatedDomainTests(APITestCase):
         url = reverse('domain-detail', args=(self.ownedDomains[1].pk,))
         response = self.client.get(url)
         response.data['arecord'] = '10.13.3.7'
-        response = self.client.put(url, response.data)
+        response.data['aaaarecord'] = None
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         response = self.client.get(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -163,8 +167,9 @@ class AuthenticatedDomainTests(APITestCase):
     def testCanUpdateAAAARecord(self):
         url = reverse('domain-detail', args=(self.ownedDomains[1].pk,))
         response = self.client.get(url)
+        response.data['arecord'] = None
         response.data['aaaarecord'] = 'fe80::a11:10ff:fee0:ff77'
-        response = self.client.put(url, response.data)
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         response = self.client.get(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -174,7 +179,7 @@ class AuthenticatedDomainTests(APITestCase):
         url = reverse('domain-detail', args=(self.ownedDomains[1].pk,))
         response = self.client.get(url)
         response.data['acme_challenge'] = 'test_challenge'
-        response = self.client.put(url, response.data)
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         response = self.client.get(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -234,7 +239,7 @@ class AuthenticatedDomainTests(APITestCase):
         httpretty.register_uri(httpretty.PUT, settings.NSLORD_PDNS_API + '/zones/' + response.data['name'] + './notify')
 
         response.data['arecord'] = '10.13.3.7'
-        response = self.client.put(url, response.data)
+        self.client.put(url, json.dumps(response.data), content_type='application/json')
 
         self.assertTrue('10.13.3.7' in httpretty.httpretty.latest_requests[-2].parsed_body)
 
@@ -247,7 +252,7 @@ class AuthenticatedDomainTests(APITestCase):
         httpretty.register_uri(httpretty.PUT, settings.NSLORD_PDNS_API + '/zones/' + response.data['name'] + './notify')
 
         response.data['arecord'] = '10.13.3.10'
-        response = self.client.put(url, response.data)
+        response = self.client.put(url, json.dumps(response.data), content_type='application/json')
 
         self.assertEqual(httpretty.httpretty.latest_requests[-2].method, 'PATCH')
         self.assertTrue('10.13.3.10' in httpretty.httpretty.latest_requests[-2].parsed_body)
@@ -298,9 +303,9 @@ class AuthenticatedDynDomainTests(APITestCase):
         self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
         self.assertEqual(httpretty.last_request().method, 'PATCH')
         self.assertEqual(httpretty.last_request().headers['Host'], 'nslord:8081')
-        self.assertTrue('"NS"' in httpretty.last_request().parsed_body
-                        and '"' + self.ownedDomains[1].name + '."' in httpretty.last_request().parsed_body
-                        and '"DELETE"' in httpretty.last_request().parsed_body)
+        self.assertTrue('"NS"' in httpretty.last_request().parsed_body)
+        self.assertTrue('"' + self.ownedDomains[1].name + '."' in httpretty.last_request().parsed_body)
+        self.assertTrue('"DELETE"' in httpretty.last_request().parsed_body)
 
         httpretty.reset()
         httpretty.register_uri(httpretty.DELETE, settings.NSLORD_PDNS_API + '/zones/' + self.ownedDomains[1].name + '.')