From 9c27d18d6c37ce36a05dad0bfdc3f0fec1cfa176 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 2 Jan 2018 17:07:21 -0500 Subject: [PATCH] Fix bulk creation of Secrets via API --- netbox/secrets/api/serializers.py | 9 ++++++++- netbox/secrets/api/views.py | 24 +++++++----------------- netbox/secrets/tests/test_api.py | 12 ++++++++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/netbox/secrets/api/serializers.py b/netbox/secrets/api/serializers.py index 6eb84efaa..a4e61a018 100644 --- a/netbox/secrets/api/serializers.py +++ b/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) diff --git a/netbox/secrets/api/views.py b/netbox/secrets/api/views.py index a105e0505..d2fb2ef00 100644 --- a/netbox/secrets/api/views.py +++ b/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): """ diff --git a/netbox/secrets/tests/test_api.py b/netbox/secrets/tests/test_api.py index 52cb289c5..0bf93eafd 100644 --- a/netbox/secrets/tests/test_api.py +++ b/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', }, ]