mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Closes #1739: Enabled custom fields for secrets
This commit is contained in:
parent
9e2ac7b3f4
commit
0c0799f3bf
@ -6,6 +6,7 @@ CUSTOMFIELD_MODELS = (
|
||||
'provider', 'circuit', # Circuits
|
||||
'site', 'rack', 'devicetype', 'device', # DCIM
|
||||
'aggregate', 'prefix', 'ipaddress', 'vlan', 'vrf', 'service', # IPAM
|
||||
'secret', # Secrets
|
||||
'tenant', # Tenancy
|
||||
'cluster', 'virtualmachine', # Virtualization
|
||||
)
|
||||
|
@ -5,6 +5,7 @@ from rest_framework.validators import UniqueTogetherValidator
|
||||
from taggit.models import Tag
|
||||
|
||||
from dcim.api.serializers import NestedDeviceSerializer
|
||||
from extras.api.customfields import CustomFieldModelSerializer
|
||||
from secrets.models import Secret, SecretRole
|
||||
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
|
||||
@ -32,7 +33,7 @@ class NestedSecretRoleSerializer(WritableNestedSerializer):
|
||||
# Secrets
|
||||
#
|
||||
|
||||
class SecretSerializer(ValidatedModelSerializer):
|
||||
class SecretSerializer(CustomFieldModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
role = NestedSecretRoleSerializer()
|
||||
plaintext = serializers.CharField()
|
||||
@ -40,7 +41,9 @@ class SecretSerializer(ValidatedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Secret
|
||||
fields = ['id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'created', 'last_updated']
|
||||
fields = [
|
||||
'id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
validators = []
|
||||
|
||||
def validate(self, data):
|
||||
|
@ -4,6 +4,7 @@ import django_filters
|
||||
from django.db.models import Q
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from utilities.filters import NumericInFilter
|
||||
from .models import Secret, SecretRole
|
||||
|
||||
@ -15,7 +16,7 @@ class SecretRoleFilter(django_filters.FilterSet):
|
||||
fields = ['name', 'slug']
|
||||
|
||||
|
||||
class SecretFilter(django_filters.FilterSet):
|
||||
class SecretFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
id__in = NumericInFilter(name='id', lookup_expr='in')
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
|
@ -7,8 +7,8 @@ from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.forms import AddRemoveTagsForm
|
||||
from utilities.forms import BootstrapMixin, BulkEditForm, FilterChoiceField, FlexibleModelChoiceField, SlugField
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldForm
|
||||
from utilities.forms import BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField
|
||||
from .models import Secret, SecretRole, UserKey
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ class SecretRoleCSVForm(forms.ModelForm):
|
||||
# Secrets
|
||||
#
|
||||
|
||||
class SecretForm(BootstrapMixin, forms.ModelForm):
|
||||
class SecretForm(BootstrapMixin, CustomFieldForm):
|
||||
plaintext = forms.CharField(
|
||||
max_length=65535,
|
||||
required=False,
|
||||
@ -129,7 +129,7 @@ class SecretCSVForm(forms.ModelForm):
|
||||
return s
|
||||
|
||||
|
||||
class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
||||
class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Secret.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
role = forms.ModelChoiceField(queryset=SecretRole.objects.all(), required=False)
|
||||
name = forms.CharField(max_length=100, required=False)
|
||||
@ -138,7 +138,8 @@ class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
||||
nullable_fields = ['name']
|
||||
|
||||
|
||||
class SecretFilterForm(BootstrapMixin, forms.Form):
|
||||
class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = Secret
|
||||
q = forms.CharField(required=False, label='Search')
|
||||
role = FilterChoiceField(
|
||||
queryset=SecretRole.objects.annotate(filter_count=Count('secrets')),
|
||||
|
@ -8,12 +8,14 @@ from Crypto.Util import strxor
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.hashers import make_password, check_password
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_bytes, python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from extras.models import CustomFieldModel
|
||||
from utilities.models import ChangeLoggedModel
|
||||
from .exceptions import InvalidKey
|
||||
from .hashers import SecretValidationHasher
|
||||
@ -311,7 +313,7 @@ class SecretRole(ChangeLoggedModel):
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Secret(ChangeLoggedModel):
|
||||
class Secret(ChangeLoggedModel, CustomFieldModel):
|
||||
"""
|
||||
A Secret stores an AES256-encrypted copy of sensitive data, such as passwords or secret keys. An irreversible
|
||||
SHA-256 hash is stored along with the ciphertext for validation upon decryption. Each Secret is assigned to a
|
||||
@ -343,6 +345,11 @@ class Secret(ChangeLoggedModel):
|
||||
max_length=128,
|
||||
editable=False
|
||||
)
|
||||
custom_field_values = GenericRelation(
|
||||
to='extras.CustomFieldValue',
|
||||
content_type_field='obj_type',
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
|
@ -69,7 +69,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'extras/inc/tags_panel.html' with tags=secret.tags.all url='secrets:secret_list' %}
|
||||
{% include 'inc/custom_fields_panel.html' with custom_fields=secret.get_custom_fields %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% if secret|decryptable_by:request.user %}
|
||||
@ -101,6 +101,7 @@
|
||||
You do not have permission to decrypt this secret.
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'extras/inc/tags_panel.html' with tags=secret.tags.all url='secrets:secret_list' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -54,6 +54,14 @@
|
||||
{% render_field form.plaintext2 %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_custom_fields form %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
|
Loading…
Reference in New Issue
Block a user