1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Merge branch 'import_headers' into develop

This commit is contained in:
Jeremy Stretch
2017-06-07 15:54:59 -04:00
35 changed files with 838 additions and 1516 deletions

View File

@@ -7,7 +7,7 @@ from django import forms
from django.db.models import Count
from dcim.models import Device
from utilities.forms import BootstrapMixin, BulkEditForm, BulkImportForm, CSVDataField, FilterChoiceField, SlugField
from utilities.forms import BootstrapMixin, BulkEditForm, FilterChoiceField, FlexibleModelChoiceField, SlugField
from .models import Secret, SecretRole, UserKey
@@ -65,27 +65,40 @@ class SecretForm(BootstrapMixin, forms.ModelForm):
})
class SecretFromCSVForm(forms.ModelForm):
device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, to_field_name='name',
error_messages={'invalid_choice': 'Device not found.'})
role = forms.ModelChoiceField(queryset=SecretRole.objects.all(), to_field_name='name',
error_messages={'invalid_choice': 'Invalid secret role.'})
plaintext = forms.CharField()
class SecretCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Device name or ID',
error_messages={
'invalid_choice': 'Device not found.',
}
)
role = forms.ModelChoiceField(
queryset=SecretRole.objects.all(),
to_field_name='name',
help_text='Name of assigned role',
error_messages={
'invalid_choice': 'Invalid secret role.',
}
)
plaintext = forms.CharField(
help_text='Plaintext secret data'
)
class Meta:
model = Secret
fields = ['device', 'role', 'name', 'plaintext']
help_texts = {
'name': 'Name or username',
}
def save(self, *args, **kwargs):
s = super(SecretFromCSVForm, self).save(*args, **kwargs)
s = super(SecretCSVForm, self).save(*args, **kwargs)
s.plaintext = str(self.cleaned_data['plaintext'])
return s
class SecretImportForm(BootstrapMixin, BulkImportForm):
csv = CSVDataField(csv_form=SecretFromCSVForm, widget=forms.Textarea(attrs={'class': 'requires-session-key'}))
class SecretBulkEditForm(BootstrapMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=Secret.objects.all(), widget=forms.MultipleHiddenInput)
role = forms.ModelChoiceField(queryset=SecretRole.objects.all(), required=False)

View File

@@ -16,7 +16,7 @@ urlpatterns = [
# Secrets
url(r'^secrets/$', views.SecretListView.as_view(), name='secret_list'),
url(r'^secrets/import/$', views.secret_import, name='secret_import'),
url(r'^secrets/import/$', views.SecretBulkImportView.as_view(), name='secret_import'),
url(r'^secrets/edit/$', views.SecretBulkEditView.as_view(), name='secret_bulk_edit'),
url(r'^secrets/delete/$', views.SecretBulkDeleteView.as_view(), name='secret_bulk_delete'),
url(r'^secrets/(?P<pk>\d+)/$', views.SecretView.as_view(), name='secret'),

View File

@@ -12,7 +12,9 @@ from django.utils.decorators import method_decorator
from django.views.generic import View
from dcim.models import Device
from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
)
from . import filters, forms, tables
from .decorators import userkey_required
from .models import SecretRole, Secret, SessionKey
@@ -185,58 +187,50 @@ class SecretDeleteView(PermissionRequiredMixin, ObjectDeleteView):
default_return_url = 'secrets:secret_list'
@permission_required('secrets.add_secret')
@userkey_required()
def secret_import(request):
class SecretBulkImportView(BulkImportView):
permission_required = 'ipam.add_vlan'
model_form = forms.SecretCSVForm
table = tables.SecretTable
default_return_url = 'secrets:secret_list'
session_key = request.COOKIES.get('session_key', None)
master_key = None
if request.method == 'POST':
form = forms.SecretImportForm(request.POST)
def _save_obj(self, obj_form):
"""
Encrypt each object before saving it to the database.
"""
obj = obj_form.save(commit=False)
obj.encrypt(self.master_key)
obj.save()
return obj
if session_key is None:
form.add_error(None, "No session key was provided with the request. Unable to encrypt secret data.")
def post(self, request):
if form.is_valid():
# Grab the session key from cookies.
session_key = request.COOKIES.get('session_key')
if session_key:
new_secrets = []
session_key = base64.b64decode(session_key)
master_key = None
# Attempt to derive the master key using the provided session key.
try:
sk = SessionKey.objects.get(userkey__user=request.user)
master_key = sk.get_master_key(session_key)
self.master_key = sk.get_master_key(base64.b64decode(session_key))
except SessionKey.DoesNotExist:
form.add_error(None, "No session key found for this user.")
messages.error(request, "No session key found for this user.")
if master_key is None:
form.add_error(None, "Invalid private key! Unable to encrypt secret data.")
if self.master_key is not None:
return super(SecretBulkImportView, self).post(request)
else:
try:
with transaction.atomic():
for secret in form.cleaned_data['csv']:
secret.encrypt(master_key)
secret.save()
new_secrets.append(secret)
messages.error(request, "Invalid private key! Unable to encrypt secret data.")
table = tables.SecretTable(new_secrets)
messages.success(request, "Imported {} new secrets.".format(len(new_secrets)))
else:
messages.error(request, "No session key was provided with the request. Unable to encrypt secret data.")
return render(request, 'import_success.html', {
'table': table,
'return_url': 'secrets:secret_list',
})
except IntegrityError as e:
form.add_error('csv', "Record {}: {}".format(len(new_secrets) + 1, e.__cause__))
else:
form = forms.SecretImportForm()
return render(request, 'secrets/secret_import.html', {
'form': form,
'return_url': 'secrets:secret_list',
})
return render(request, self.template_name, {
'form': self._import_form(request.POST),
'fields': self.model_form().fields,
'obj_type': self.model_form._meta.model._meta.verbose_name,
'return_url': self.default_return_url,
})
class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):