Files
mayan-edms/mayan/apps/document_signatures/views.py
Roberto Rosario 36a51eeb73 Switch to full app paths
Instead of inserting the path of the apps into the Python app,
the apps are now referenced by their full import path.

This solves name clashes with external or native Python libraries.
Example: Mayan statistics app vs. Python new statistics library.

Every app reference is now prepended with 'mayan.apps'.

Existing config.yml files need to be updated manually.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
2019-04-05 02:02:57 -04:00

390 lines
13 KiB
Python

from __future__ import absolute_import, unicode_literals
import logging
from django.contrib import messages
from django.core.files import File
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.generics import (
ConfirmView, FormView, SingleObjectCreateView, SingleObjectDeleteView,
SingleObjectDetailView, SingleObjectDownloadView, SingleObjectListView
)
from mayan.apps.common.utils import TemporaryFile
from mayan.apps.django_gpg.exceptions import NeedPassphrase, PassphraseError
from mayan.apps.django_gpg.permissions import permission_key_sign
from mayan.apps.documents.models import DocumentVersion
from .forms import (
DocumentVersionSignatureCreateForm,
DocumentVersionSignatureDetailForm
)
from .icons import icon_document_signature_list
from .links import (
link_document_version_signature_detached_create,
link_document_version_signature_embedded_create,
link_document_version_signature_upload
)
from .models import DetachedSignature, SignatureBaseModel
from .permissions import (
permission_document_version_sign_detached,
permission_document_version_sign_embedded,
permission_document_version_signature_delete,
permission_document_version_signature_download,
permission_document_version_signature_upload,
permission_document_version_signature_verify,
permission_document_version_signature_view,
)
from .tasks import task_verify_missing_embedded_signature
logger = logging.getLogger(__name__)
class DocumentVersionDetachedSignatureCreateView(FormView):
form_class = DocumentVersionSignatureCreateForm
def form_valid(self, form):
key = form.cleaned_data['key']
passphrase = form.cleaned_data['passphrase'] or None
AccessControlList.objects.check_access(
permissions=permission_key_sign, user=self.request.user, obj=key
)
try:
with self.get_document_version().open() as file_object:
detached_signature = key.sign_file(
file_object=file_object, detached=True,
passphrase=passphrase
)
except NeedPassphrase:
messages.error(
self.request, _('Passphrase is needed to unlock this key.')
)
return HttpResponseRedirect(
reverse(
'signatures:document_version_signature_detached_create',
args=(self.get_document_version().pk,)
)
)
except PassphraseError:
messages.error(
self.request, _('Passphrase is incorrect.')
)
return HttpResponseRedirect(
reverse(
'signatures:document_version_signature_detached_create',
args=(self.get_document_version().pk,)
)
)
else:
temporary_file_object = TemporaryFile()
temporary_file_object.write(detached_signature.data)
temporary_file_object.seek(0)
DetachedSignature.objects.create(
document_version=self.get_document_version(),
signature_file=File(temporary_file_object)
)
temporary_file_object.close()
messages.success(
self.request, _('Document version signed successfully.')
)
return super(
DocumentVersionDetachedSignatureCreateView, self
).form_valid(form)
def dispatch(self, request, *args, **kwargs):
AccessControlList.objects.check_access(
permissions=permission_document_version_sign_detached,
user=request.user, obj=self.get_document_version().document
)
return super(
DocumentVersionDetachedSignatureCreateView, self
).dispatch(request, *args, **kwargs)
def get_document_version(self):
return get_object_or_404(DocumentVersion, pk=self.kwargs['pk'])
def get_extra_context(self):
return {
'object': self.get_document_version(),
'title': _(
'Sign document version "%s" with a detached signature'
) % self.get_document_version(),
}
def get_form_kwargs(self):
result = super(
DocumentVersionDetachedSignatureCreateView, self
).get_form_kwargs()
result.update({'user': self.request.user})
return result
def get_post_action_redirect(self):
return reverse(
'signatures:document_version_signature_list',
args=(self.get_document_version().pk,)
)
class DocumentVersionEmbeddedSignatureCreateView(FormView):
form_class = DocumentVersionSignatureCreateForm
def form_valid(self, form):
key = form.cleaned_data['key']
passphrase = form.cleaned_data['passphrase'] or None
AccessControlList.objects.check_access(
permissions=permission_key_sign, user=self.request.user, obj=key
)
try:
with self.get_document_version().open() as file_object:
signature_result = key.sign_file(
binary=True, file_object=file_object, passphrase=passphrase
)
except NeedPassphrase:
messages.error(
self.request, _('Passphrase is needed to unlock this key.')
)
return HttpResponseRedirect(
reverse(
'signatures:document_version_signature_embedded_create',
args=(self.get_document_version().pk,)
)
)
except PassphraseError:
messages.error(
self.request, _('Passphrase is incorrect.')
)
return HttpResponseRedirect(
reverse(
'signatures:document_version_signature_embedded_create',
args=(self.get_document_version().pk,)
)
)
else:
temporary_file_object = TemporaryFile()
temporary_file_object.write(signature_result.data)
temporary_file_object.seek(0)
new_version = self.get_document_version().document.new_version(
file_object=temporary_file_object, _user=self.request.user
)
temporary_file_object.close()
messages.success(
self.request, _('Document version signed successfully.')
)
return HttpResponseRedirect(
reverse(
'signatures:document_version_signature_list',
args=(new_version.pk,)
)
)
return super(
DocumentVersionEmbeddedSignatureCreateView, self
).form_valid(form)
def dispatch(self, request, *args, **kwargs):
AccessControlList.objects.check_access(
permissions=permission_document_version_sign_embedded,
user=request.user, obj=self.get_document_version().document
)
return super(
DocumentVersionEmbeddedSignatureCreateView, self
).dispatch(request, *args, **kwargs)
def get_document_version(self):
return get_object_or_404(DocumentVersion, pk=self.kwargs['pk'])
def get_extra_context(self):
return {
'object': self.get_document_version(),
'title': _(
'Sign document version "%s" with a embedded signature'
) % self.get_document_version(),
}
def get_form_kwargs(self):
result = super(
DocumentVersionEmbeddedSignatureCreateView, self
).get_form_kwargs()
result.update({'user': self.request.user})
return result
class DocumentVersionSignatureDeleteView(SingleObjectDeleteView):
model = DetachedSignature
object_permission = permission_document_version_signature_delete
object_permission_related = 'document_version.document'
def get_extra_context(self):
return {
'object': self.get_object().document_version,
'signature': self.get_object(),
'title': _('Delete detached signature: %s') % self.get_object()
}
def get_post_action_redirect(self):
return reverse(
'signatures:document_version_signature_list',
args=(self.get_object().document_version.pk,)
)
class DocumentVersionSignatureDetailView(SingleObjectDetailView):
form_class = DocumentVersionSignatureDetailForm
object_permission = permission_document_version_signature_view
object_permission_related = 'document_version.document'
def get_extra_context(self):
return {
'hide_object': True,
'object': self.get_object().document_version,
'signature': self.get_object(),
'title': _(
'Details for signature: %s'
) % self.get_object(),
}
def get_queryset(self):
return SignatureBaseModel.objects.select_subclasses()
class DocumentVersionSignatureDownloadView(SingleObjectDownloadView):
model = DetachedSignature
object_permission = permission_document_version_signature_download
object_permission_related = 'document_version.document'
def get_file(self):
signature = self.get_object()
return DocumentVersionSignatureDownloadView.VirtualFile(
signature.signature_file, name=force_text(signature)
)
class DocumentVersionSignatureListView(SingleObjectListView):
def dispatch(self, request, *args, **kwargs):
AccessControlList.objects.check_access(
permissions=permission_document_version_signature_view,
user=request.user, obj=self.get_document_version()
)
return super(
DocumentVersionSignatureListView, self
).dispatch(request, *args, **kwargs)
def get_document_version(self):
return get_object_or_404(DocumentVersion, pk=self.kwargs['pk'])
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_document_signature_list,
'no_results_text': _(
'Signatures help provide authorship evidence and tamper '
'detection. They are very secure and hard to '
'forge. A signature can be embedded as part of the document '
'itself or uploaded as a separate file.'
),
'no_results_secondary_links': [
link_document_version_signature_detached_create.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
link_document_version_signature_embedded_create.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
link_document_version_signature_upload.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
],
'no_results_title': _('There are no signatures for this document.'),
'object': self.get_document_version(),
'title': _(
'Signatures for document version: %s'
) % self.get_document_version(),
}
def get_object_list(self):
return self.get_document_version().signatures.all()
class DocumentVersionSignatureUploadView(SingleObjectCreateView):
fields = ('signature_file',)
model = DetachedSignature
def dispatch(self, request, *args, **kwargs):
AccessControlList.objects.check_access(
permissions=permission_document_version_signature_upload,
user=request.user, obj=self.get_document_version()
)
return super(
DocumentVersionSignatureUploadView, self
).dispatch(request, *args, **kwargs)
def get_document_version(self):
return get_object_or_404(DocumentVersion, pk=self.kwargs['pk'])
def get_extra_context(self):
return {
'object': self.get_document_version(),
'title': _(
'Upload detached signature for document version: %s'
) % self.get_document_version(),
}
def get_instance_extra_data(self):
return {'document_version': self.get_document_version()}
def get_post_action_redirect(self):
return reverse(
'signatures:document_version_signature_list',
args=(self.get_document_version().pk,)
)
class AllDocumentSignatureVerifyView(ConfirmView):
extra_context = {
'message': _(
'On large databases this operation may take some time to execute.'
), 'title': _('Verify all document for signatures?'),
}
view_permission = permission_document_version_signature_verify
def get_post_action_redirect(self):
return reverse('common:tools_list')
def view_action(self):
task_verify_missing_embedded_signature.delay()
messages.success(
self.request, _('Signature verification queued successfully.')
)