Move more signature functionality to the document signature app
This commit is contained in:
@@ -1,37 +1,49 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from documents.models import Document
|
from documents.models import Document, DocumentVersion
|
||||||
from navigation.api import register_links, register_top_menu, \
|
from navigation.api import register_links, register_top_menu, \
|
||||||
register_model_list_columns, register_multi_item_links, \
|
register_model_list_columns, register_multi_item_links, \
|
||||||
register_sidebar_template
|
register_sidebar_template
|
||||||
from main.api import register_diagnostic, register_maintenance_links
|
from django_gpg.runtime import gpg
|
||||||
from permissions.api import register_permission, set_namespace_title
|
from django_gpg.exceptions import GPGDecryptionError
|
||||||
#from project_setup.api import register_setup
|
#from main.api import register_diagnostic, register_maintenance_links
|
||||||
|
|
||||||
#from django_gpg.api import Key
|
from .models import DocumentVersionSignature
|
||||||
|
from .permissions import (
|
||||||
|
PERMISSION_DOCUMENT_VERIFY,
|
||||||
|
PERMISSION_SIGNATURE_UPLOAD,
|
||||||
|
PERMISSION_SIGNATURE_DOWNLOAD
|
||||||
|
)
|
||||||
|
|
||||||
PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')}
|
|
||||||
PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')}
|
|
||||||
PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')}
|
|
||||||
|
|
||||||
# Permission setup
|
|
||||||
set_namespace_title('document_signatures', _(u'Document signatures'))
|
|
||||||
register_permission(PERMISSION_DOCUMENT_VERIFY)
|
|
||||||
register_permission(PERMISSION_SIGNATURE_UPLOAD)
|
|
||||||
register_permission(PERMISSION_SIGNATURE_DOWNLOAD)
|
|
||||||
|
|
||||||
def has_embedded_signature(context):
|
def has_embedded_signature(context):
|
||||||
return context['object'].signature_state
|
return DocumentVersionSignature.objects.has_embedded_signature(context['object'])
|
||||||
|
|
||||||
def doesnt_have_detached_signature(context):
|
def doesnt_have_detached_signature(context):
|
||||||
return context['object'].has_detached_signature() == False
|
return DocumentVersionSignature.objects.has_detached_signature(context['object']) == False
|
||||||
|
|
||||||
|
def document_pre_open_hook(descriptor):
|
||||||
|
try:
|
||||||
|
result = gpg.decrypt_file(descriptor)
|
||||||
|
# gpg return a string, turn it into a file like object
|
||||||
|
return StringIO(result.data)
|
||||||
|
except GPGDecryptionError:
|
||||||
|
# At least return the original raw content
|
||||||
|
return descriptor
|
||||||
|
|
||||||
document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature}
|
document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature}
|
||||||
document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature}
|
document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature}
|
||||||
document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]}
|
document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]}
|
||||||
|
|
||||||
register_links(Document, [document_verify], menu_name='form_header')
|
register_links(Document, [document_verify], menu_name='form_header')
|
||||||
|
|
||||||
register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar')
|
register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar')
|
||||||
|
|
||||||
|
|
||||||
|
DocumentVersion.register_pre_open_hook(1, document_pre_open_hook)
|
||||||
|
|||||||
@@ -1,8 +1,97 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from documents.models import DocumentVersion, get_filename_from_uuid
|
from documents.models import DocumentVersion, get_filename_from_uuid
|
||||||
from documents.conf.settings import STORAGE_BACKEND
|
from documents.conf.settings import STORAGE_BACKEND
|
||||||
|
from django_gpg.runtime import gpg
|
||||||
|
from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentVersionSignatureManager(models.Manager):
|
||||||
|
#def update_signed_state(self, document):
|
||||||
|
# document_signature, created = self.model.get_or_create(
|
||||||
|
# document_version=document.latest_version,
|
||||||
|
# )
|
||||||
|
# if document.exists():
|
||||||
|
# descriptor = document.open()
|
||||||
|
# try:
|
||||||
|
# document_signature.signature_state = gpg.verify_file(descriptor).status
|
||||||
|
# # TODO: give use choice for auto public key fetch?
|
||||||
|
# # OR maybe new config option
|
||||||
|
# except GPGVerificationError:
|
||||||
|
# document_signature.signature_state = None
|
||||||
|
# finally:
|
||||||
|
# document_signature.save()
|
||||||
|
|
||||||
|
def add_detached_signature(self, document, detached_signature):
|
||||||
|
document_signature, created = self.model.objects.get_or_create(
|
||||||
|
document_version=document.latest_version,
|
||||||
|
)
|
||||||
|
if not self.signature_state(document):
|
||||||
|
document_signature.signature_file = detached_signature
|
||||||
|
document_signature.save()
|
||||||
|
else:
|
||||||
|
raise Exception('document already has an embedded signature')
|
||||||
|
|
||||||
|
def has_detached_signature(self, document):
|
||||||
|
document_signature, created = self.model.objects.get_or_create(
|
||||||
|
document_version=document.latest_version,
|
||||||
|
)
|
||||||
|
if document_signature.signature_file:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_embedded_signature(self, document):
|
||||||
|
logger.debug('document: %s' % document)
|
||||||
|
|
||||||
|
if self.signature_state(document):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def signature_state(self, document):
|
||||||
|
document_signature, created = self.model.objects.get_or_create(
|
||||||
|
document_version=document.latest_version,
|
||||||
|
)
|
||||||
|
logger.debug('created: %s' % created)
|
||||||
|
if created and document.exists():
|
||||||
|
descriptor = document.open(raw=True)
|
||||||
|
try:
|
||||||
|
document_signature.signature_state = gpg.verify_file(descriptor).status
|
||||||
|
# TODO: give use choice for auto public key fetch?
|
||||||
|
# OR maybe new config option
|
||||||
|
except GPGVerificationError:
|
||||||
|
document_signature.signature_state = None
|
||||||
|
finally:
|
||||||
|
document_signature.save()
|
||||||
|
|
||||||
|
#document_signature.signature_state = self.verify_signature(document).status
|
||||||
|
#document_signature.save()
|
||||||
|
|
||||||
|
return document_signature.signature_state
|
||||||
|
|
||||||
|
def detached_signature(self, document):
|
||||||
|
document_signature, created = self.model.objects.get_or_create(
|
||||||
|
document_version=document.latest_version,
|
||||||
|
)
|
||||||
|
return document_signature.signature_file.storage.open(document_signature.signature_file.path)
|
||||||
|
|
||||||
|
def verify_signature(self, document):
|
||||||
|
if self.has_detached_signature(document):
|
||||||
|
logger.debug('has detached signature')
|
||||||
|
args = (document.open(), self.detached_signature(document))
|
||||||
|
else:
|
||||||
|
args = (document.open(raw=True),)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return gpg.verify_w_retry(*args)
|
||||||
|
except GPGVerificationError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class DocumentVersionSignature(models.Model):
|
class DocumentVersionSignature(models.Model):
|
||||||
@@ -13,45 +102,7 @@ class DocumentVersionSignature(models.Model):
|
|||||||
signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False)
|
signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False)
|
||||||
signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False)
|
signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False)
|
||||||
|
|
||||||
def update_signed_state(self, save=True):
|
objects = DocumentVersionSignatureManager()
|
||||||
if self.exists():
|
|
||||||
try:
|
|
||||||
self.signature_state = gpg.verify_file(self.open()).status
|
|
||||||
# TODO: give use choice for auto public key fetch?
|
|
||||||
# OR maybe new config option
|
|
||||||
except GPGVerificationError:
|
|
||||||
self.signature_state = None
|
|
||||||
|
|
||||||
if save:
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def add_detached_signature(self, detached_signature):
|
|
||||||
if not self.signature_state:
|
|
||||||
self.signature_file = detached_signature
|
|
||||||
self.save()
|
|
||||||
else:
|
|
||||||
raise Exception('document already has an embedded signature')
|
|
||||||
|
|
||||||
def has_detached_signature(self):
|
|
||||||
if self.signature_file:
|
|
||||||
return self.signature_file.storage.exists(self.signature_file.path)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def detached_signature(self):
|
|
||||||
return self.signature_file.storage.open(self.signature_file.path)
|
|
||||||
|
|
||||||
def verify_signature(self):
|
|
||||||
try:
|
|
||||||
if self.has_detached_signature():
|
|
||||||
logger.debug('has detached signature')
|
|
||||||
signature = gpg.verify_w_retry(self.open(), self.detached_signature())
|
|
||||||
else:
|
|
||||||
signature = gpg.verify_w_retry(self.open(raw=True))
|
|
||||||
except GPGVerificationError:
|
|
||||||
signature = None
|
|
||||||
|
|
||||||
return signature
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'document version signature')
|
verbose_name = _(u'document version signature')
|
||||||
|
|||||||
15
apps/document_signatures/permissions.py
Normal file
15
apps/document_signatures/permissions.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from permissions.api import register_permission, set_namespace_title
|
||||||
|
|
||||||
|
PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')}
|
||||||
|
PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')}
|
||||||
|
PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')}
|
||||||
|
|
||||||
|
# Permission setup
|
||||||
|
set_namespace_title('document_signatures', _(u'Document signatures'))
|
||||||
|
register_permission(PERMISSION_DOCUMENT_VERIFY)
|
||||||
|
register_permission(PERMISSION_SIGNATURE_UPLOAD)
|
||||||
|
register_permission(PERMISSION_SIGNATURE_DOWNLOAD)
|
||||||
@@ -38,7 +38,7 @@ def document_verify(request, document_pk):
|
|||||||
|
|
||||||
RecentDocument.objects.add_document_for_user(request.user, document)
|
RecentDocument.objects.add_document_for_user(request.user, document)
|
||||||
|
|
||||||
signature = document.verify_signature()
|
signature = DocumentVersionSignature.objects.verify_signature(document)
|
||||||
|
|
||||||
signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None))
|
signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None))
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ def document_verify(request, document_pk):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if document.signature_state:
|
if DocumentVersionSignature.objects.has_embedded_signature(document):
|
||||||
signature_type = _(u'embedded')
|
signature_type = _(u'embedded')
|
||||||
else:
|
else:
|
||||||
signature_type = _(u'detached')
|
signature_type = _(u'detached')
|
||||||
@@ -88,7 +88,7 @@ def document_signature_upload(request, document_pk):
|
|||||||
form = DetachedSignatureForm(request.POST, request.FILES)
|
form = DetachedSignatureForm(request.POST, request.FILES)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
try:
|
try:
|
||||||
document.add_detached_signature(request.FILES['file'])
|
DocumentVersionSignature.objects.add_detached_signature(document, request.FILES['file'])
|
||||||
messages.success(request, _(u'Detached signature uploaded successfully.'))
|
messages.success(request, _(u'Detached signature uploaded successfully.'))
|
||||||
return HttpResponseRedirect(next)
|
return HttpResponseRedirect(next)
|
||||||
except Exception, msg:
|
except Exception, msg:
|
||||||
@@ -112,8 +112,8 @@ def document_signature_download(request, document_pk):
|
|||||||
document = get_object_or_404(Document, pk=document_pk)
|
document = get_object_or_404(Document, pk=document_pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if document.has_detached_signature():
|
if DocumentVersionSignature.objects.has_detached_signature(document):
|
||||||
signature = document.detached_signature()
|
signature = DocumentVersionSignature.objects.detached_signature(document)
|
||||||
return serve_file(
|
return serve_file(
|
||||||
request,
|
request,
|
||||||
signature,
|
signature,
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ from mimetype.api import (get_mimetype, get_icon_file_path,
|
|||||||
get_error_icon_file_path)
|
get_error_icon_file_path)
|
||||||
from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION,
|
from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION,
|
||||||
DEFAULT_PAGE_NUMBER)
|
DEFAULT_PAGE_NUMBER)
|
||||||
from django_gpg.runtime import gpg
|
|
||||||
from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError
|
|
||||||
|
|
||||||
from documents.conf.settings import CHECKSUM_FUNCTION
|
from documents.conf.settings import CHECKSUM_FUNCTION
|
||||||
from documents.conf.settings import UUID_FUNCTION
|
from documents.conf.settings import UUID_FUNCTION
|
||||||
|
|||||||
Reference in New Issue
Block a user