"""Contains all the views of Signer App."""
from typing import Any
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.db.models import ProtectedError, QuerySet
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views import View
from django.views.generic import DetailView, ListView
from django.views.generic.edit import FormView
from signer.forms import (
SignerAddFileImportPkcs12Form,
SignerAddFileImportSeparateFilesForm,
SignerAddFileTypeSelectForm,
SignerAddMethodSelectForm,
SignHashForm,
)
from signer.models import SignedMessageModel, SignerModel
from trustpoint.logger import LoggerMixin
from trustpoint.settings import UIConfig
from trustpoint.views.base import BulkDeleteView, ContextDataMixin, SortableTableMixin
[docs]
class SignerContextMixin(ContextDataMixin):
"""Mixin which adds context_data for the Signer pages."""
[docs]
context_page_category = 'signer'
[docs]
class SignerTableView(SignerContextMixin, SortableTableMixin[SignerModel], ListView[SignerModel]):
"""Signer Table View."""
[docs]
template_name = 'signer/signers.html'
[docs]
context_object_name = 'signers'
[docs]
paginate_by = UIConfig.paginate_by
[docs]
default_sort_param = 'unique_name'
[docs]
class SignerAddMethodSelectView(SignerContextMixin, FormView[SignerAddMethodSelectForm]):
"""View to select the method to add a Signer."""
[docs]
template_name = 'signer/add/method_select.html'
[docs]
class SignerAddFileImportFileTypeSelectView(SignerContextMixin, FormView[SignerAddFileTypeSelectForm]):
"""View to select the file type when importing a Signer."""
[docs]
template_name = 'signer/add/file_type_select.html'
[docs]
class SignerAddFileImportPkcs12View(SignerContextMixin, FormView[SignerAddFileImportPkcs12Form]):
"""View to import an Issuing CA from a PKCS12 file."""
[docs]
template_name = 'signer/add/file_import.html'
[docs]
success_url = reverse_lazy('signer:signer_list')
[docs]
class SignerAddFileImportSeparateFilesView(SignerContextMixin, FormView[SignerAddFileImportSeparateFilesForm]):
"""View to import a Signer from separate PEM files."""
[docs]
template_name = 'signer/add/file_import.html'
[docs]
success_url = reverse_lazy('signer:signer_list')
[docs]
class SignerConfigView(LoggerMixin, SignerContextMixin, DetailView[SignerModel]):
"""View to display the details of a Signer."""
[docs]
http_method_names = ('get',)
[docs]
success_url = reverse_lazy('signer:signer_list')
[docs]
ignore_url = reverse_lazy('signer:signer_list')
[docs]
template_name = 'signer/signer_config.html'
[docs]
context_object_name = 'signer'
[docs]
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
"""Adds the issued certificates to the context.
Args:
**kwargs: Keyword arguments passed to super().get_context_data()
Returns:
The context to render the page.
"""
return super().get_context_data(**kwargs)
[docs]
class SignedMessagesListView(SignerContextMixin, ListView[SignedMessageModel]):
"""View to display all signed messages by a specific Signer."""
[docs]
model = SignedMessageModel
[docs]
template_name = 'signer/signed_messages.html'
[docs]
context_object_name = 'signed_messages'
[docs]
def get_queryset(self) -> QuerySet[SignedMessageModel]:
"""Gets the required and filtered QuerySet.
Returns:
The filtered QuerySet.
"""
signer = get_object_or_404(SignerModel, pk=self.kwargs['pk'])
return SignedMessageModel.objects.filter(signer=signer).order_by('-created_at')
[docs]
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
"""Adds the signer model object to the context.
Args:
**kwargs: Keyword arguments passed to super().get_context_data()
Returns:
The context to render the page.
"""
context = super().get_context_data(**kwargs)
context['signer'] = get_object_or_404(SignerModel, pk=self.kwargs['pk'])
return context
[docs]
class SignerBulkDeleteConfirmView(SignerContextMixin, BulkDeleteView):
"""View to confirm the deletion of multiple Signers."""
[docs]
success_url = reverse_lazy('signer:signer_list')
[docs]
ignore_url = reverse_lazy('signer:signer_list')
[docs]
template_name = 'signer/confirm_delete.html'
[docs]
context_object_name = 'signers'
[docs]
class SignHashView(LoggerMixin, SignerContextMixin, FormView[SignHashForm]):
"""View for signing a hash value with a selected signer."""
[docs]
template_name = 'signer/sign_hash.html'
[docs]
success_url = reverse_lazy('signer:signer_list')
[docs]
class SignHashSuccessView(SignerContextMixin, View):
"""View to display the signature result."""
[docs]
template_name = 'signer/sign_hash_success.html'
[docs]
def get(self, request: HttpRequest) -> HttpResponse:
"""Display the signature result.
Args:
request: The HTTP request.
Returns:
HttpResponse with the signature result.
"""
signature_data = request.session.pop('last_signature', None)
if not signature_data:
messages.warning(request, _('No signature data available.'))
return HttpResponseRedirect(reverse_lazy('signer:sign_hash'))
context = self.get_context_data()
context.update(signature_data)
return render(request, self.template_name, context)
[docs]
def get_context_data(self, **kwargs: Any) -> dict[Any, Any]:
"""Get context data for the view."""
del kwargs
context = super().get_context_data() if hasattr(super(), 'get_context_data') else {}
context['context_page_category'] = 'signer'
return context