diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index 7fe12a221c..b4d2c83950 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -16,6 +16,8 @@ PERMISSION_KEY_VIEW = {'namespace': 'django_gpg', 'name': 'key_view', 'label': _ PERMISSION_KEY_DELETE = {'namespace': 'django_gpg', 'name': 'key_delete', 'label': _(u'Delete keys')} PERMISSION_KEYSERVER_QUERY = {'namespace': 'django_gpg', 'name': 'keyserver_query', 'label': _(u'Query keyservers')} PERMISSION_KEY_RECEIVE = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Import key from keyservers')} +PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'django_gpg', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} +PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Download detached signatures')} # Permission setup set_namespace_title('django_gpg', _(u'Signatures')) @@ -24,6 +26,11 @@ register_permission(PERMISSION_KEY_VIEW) register_permission(PERMISSION_KEY_DELETE) register_permission(PERMISSION_KEYSERVER_QUERY) register_permission(PERMISSION_KEY_RECEIVE) +register_permission(PERMISSION_SIGNATURE_UPLOAD) +register_permission(PERMISSION_SIGNATURE_DOWNLOAD) + +def has_embedded_signature(context): + return context['object'].signature_state # Setup views private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} @@ -31,12 +38,16 @@ public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'ob key_delete = {'text': _(u'delete'), 'view': 'key_delete', 'args': ['object.fingerprint', 'object.type'], 'famfam': 'key_delete', 'permissions': [PERMISSION_KEY_DELETE]} key_query = {'text': _(u'Query keyservers'), 'view': 'key_query', 'famfam': 'zoom', 'permissions': [PERMISSION_KEYSERVER_QUERY]} key_receive = {'text': _(u'Import'), 'view': 'key_receive', 'args': 'object.keyid', 'famfam': 'key_add', 'keep_query': True, 'permissions': [PERMISSION_KEY_RECEIVE]} +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': has_embedded_signature} # Document views 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_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') + register_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') register_links(Key, [key_delete]) @@ -44,3 +55,6 @@ register_links(KeyServerKey, [key_receive]) register_setup(private_keys) register_setup(public_keys) + + + diff --git a/apps/django_gpg/forms.py b/apps/django_gpg/forms.py index 619035fd5d..b961daf037 100644 --- a/apps/django_gpg/forms.py +++ b/apps/django_gpg/forms.py @@ -11,3 +11,9 @@ class KeySearchForm(forms.Form): label=_(u'Term'), help_text=_(u'Name, e-mail, key ID or key fingerprint to look for.') ) + + +class DetachedSignatureForm(forms.Form): + file = forms.FileField( + label=_(u'Signature file'), + ) diff --git a/apps/django_gpg/urls.py b/apps/django_gpg/urls.py index 20c4c69360..4a22882d06 100644 --- a/apps/django_gpg/urls.py +++ b/apps/django_gpg/urls.py @@ -5,7 +5,8 @@ urlpatterns = patterns('django_gpg.views', url(r'^list/private/$', 'key_list', {'secret': True}, 'key_private_list'), url(r'^list/public/$', 'key_list', {'secret': False}, 'key_public_list'), url(r'^verify/(?P\d+)/$', 'document_verify', (), 'document_verify'), + url(r'^upload/signature/(?P\d+)/$', 'document_signature_upload', (), 'document_signature_upload'), + url(r'^download/signature/(?P\d+)/$', 'document_signature_download', (), 'document_signature_download'), url(r'^query/$', 'key_query', (), 'key_query'), url(r'^receive/(?P.+)/$', 'key_receive', (), 'key_receive'), - ) diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 31bad2c530..d908d011e0 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -15,14 +15,16 @@ from documents.models import Document, RecentDocument from permissions.api import check_permissions from common.utils import pretty_size, parse_range, urlquote, \ return_diff, encapsulate - +from filetransfers.api import serve_file + from django_gpg.api import Key, SIGNATURE_STATES from django_gpg.runtime import gpg from django_gpg.exceptions import GPGVerificationError, KeyFetchingError from django_gpg import (PERMISSION_DOCUMENT_VERIFY, PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, PERMISSION_KEYSERVER_QUERY, - PERMISSION_KEY_RECEIVE) -from django_gpg.forms import KeySearchForm + PERMISSION_KEY_RECEIVE, PERMISSION_SIGNATURE_UPLOAD, + PERMISSION_SIGNATURE_DOWNLOAD) +from django_gpg.forms import KeySearchForm, DetachedSignatureForm logger = logging.getLogger(__name__) @@ -193,10 +195,8 @@ def document_verify(request, document_pk): document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) - try: - signature = gpg.verify_w_retry(document.open(raw=True)) - except GPGVerificationError: - signature = None + + signature = document.verify_signature() signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None)) @@ -230,3 +230,56 @@ def document_verify(request, document_pk): 'document': document, 'paragraphs': paragraphs, }, context_instance=RequestContext(request)) + + +def document_signature_upload(request, document_pk): + check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + document = get_object_or_404(Document, pk=document_pk) + + RecentDocument.objects.add_document_for_user(request.user, document) + + post_action_redirect = None + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + form = DetachedSignatureForm(request.POST, request.FILES) + if form.is_valid(): + try: + document.add_detached_signature(request.FILES['file']) + messages.success(request, _(u'Detached signature uploaded successfully.')) + return HttpResponseRedirect(next) + except Exception, msg: + messages.error(request, msg) + return HttpResponseRedirect(previous) + else: + form = DetachedSignatureForm() + + return render_to_response('generic_form.html', { + 'title': _(u'Upload detached signature for: %s') % document, + 'form_icon': 'key_delete.png', + 'next': next, + 'form': form, + 'previous': previous, + 'object': document, + }, context_instance=RequestContext(request)) + + +def document_signature_download(request, document_pk): + check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) + document = get_object_or_404(Document, pk=document_pk) + + try: + if document.has_detached_signature(): + signature = document.detached_signature() + return serve_file( + request, + signature, + save_as=u'"%s.sig"' % document.filename, + content_type=u'application/octet-stream' + ) + except Exception, e: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + + return HttpResponseRedirect(request.META['HTTP_REFERER'])