Browse Source

Fix bulk creation of Secrets via API

Jeremy Stretch 7 years ago
parent
commit
9c27d18d6c
3 changed files with 23 additions and 22 deletions
  1. 8 1
      netbox/secrets/api/serializers.py
  2. 7 17
      netbox/secrets/api/views.py
  3. 8 4
      netbox/secrets/tests/test_api.py

+ 8 - 1
netbox/secrets/api/serializers.py

@@ -50,8 +50,15 @@ class WritableSecretSerializer(serializers.ModelSerializer):
 
     def validate(self, data):
 
+        # Encrypt plaintext data using the master key provided from the view context
+        if data.get('plaintext'):
+            s = Secret(plaintext=data['plaintext'])
+            s.encrypt(self.context['master_key'])
+            data['ciphertext'] = s.ciphertext
+            data['hash'] = s.hash
+
         # Validate uniqueness of name if one has been provided.
-        if data.get('name', None):
+        if data.get('name'):
             validator = UniqueTogetherValidator(queryset=Secret.objects.all(), fields=('device', 'role', 'name'))
             validator.set_context(self)
             validator(data)

+ 7 - 17
netbox/secrets/api/views.py

@@ -56,17 +56,13 @@ class SecretViewSet(ModelViewSet):
 
     master_key = None
 
-    def _get_encrypted_fields(self, serializer):
-        """
-        Since we can't call encrypt() on the serializer like we can on the Secret model, we need to calculate the
-        ciphertext and hash values by encrypting a dummy copy. These can be passed to the serializer's save() method.
-        """
-        s = Secret(plaintext=serializer.validated_data['plaintext'])
-        s.encrypt(self.master_key)
-        return ({
-            'ciphertext': s.ciphertext,
-            'hash': s.hash,
-        })
+    def get_serializer_context(self):
+
+        # Make the master key available to the serializer for encrypting plaintext values
+        context = super(SecretViewSet, self).get_serializer_context()
+        context['master_key'] = self.master_key
+
+        return context
 
     def initial(self, request, *args, **kwargs):
 
@@ -128,12 +124,6 @@ class SecretViewSet(ModelViewSet):
         serializer = self.get_serializer(queryset, many=True)
         return Response(serializer.data)
 
-    def perform_create(self, serializer):
-        serializer.save(**self._get_encrypted_fields(serializer))
-
-    def perform_update(self, serializer):
-        serializer.save(**self._get_encrypted_fields(serializer))
-
 
 class GetSessionKeyViewSet(ViewSet):
     """

+ 8 - 4
netbox/secrets/tests/test_api.py

@@ -164,9 +164,9 @@ class SecretTest(HttpStatusMixin, APITestCase):
         }
 
         self.plaintext = {
-            'secret1': 'Secret#1Plaintext',
-            'secret2': 'Secret#2Plaintext',
-            'secret3': 'Secret#3Plaintext',
+            'secret1': 'Secret #1 Plaintext',
+            'secret2': 'Secret #2 Plaintext',
+            'secret3': 'Secret #3 Plaintext',
         }
 
         site = Site.objects.create(name='Test Site 1', slug='test-site-1')
@@ -213,7 +213,8 @@ class SecretTest(HttpStatusMixin, APITestCase):
         data = {
             'device': self.device.pk,
             'role': self.secretrole1.pk,
-            'plaintext': 'Secret#4Plaintext',
+            'name': 'Test Secret 4',
+            'plaintext': 'Secret #4 Plaintext',
         }
 
         url = reverse('secrets-api:secret-list')
@@ -233,16 +234,19 @@ class SecretTest(HttpStatusMixin, APITestCase):
             {
                 'device': self.device.pk,
                 'role': self.secretrole1.pk,
+                'name': 'Test Secret 4',
                 'plaintext': 'Secret #4 Plaintext',
             },
             {
                 'device': self.device.pk,
                 'role': self.secretrole1.pk,
+                'name': 'Test Secret 5',
                 'plaintext': 'Secret #5 Plaintext',
             },
             {
                 'device': self.device.pk,
                 'role': self.secretrole1.pk,
+                'name': 'Test Secret 6',
                 'plaintext': 'Secret #6 Plaintext',
             },
         ]