Add key management view to the setup menu, add keyserver query view, add keyserver key import, add respective icons

This commit is contained in:
Roberto Rosario
2011-12-05 13:37:24 -04:00
parent 8b3e391e05
commit 553d73020d
9 changed files with 229 additions and 17 deletions

View File

@@ -7,13 +7,40 @@ from navigation.api import register_links, register_top_menu, \
from main.api import register_diagnostic, register_maintenance_links from main.api import register_diagnostic, register_maintenance_links
from permissions.api import register_permission, set_namespace_title from permissions.api import register_permission, set_namespace_title
from project_setup.api import register_setup from project_setup.api import register_setup
from hkp import Key as KeyServerKey
from django_gpg.api import Key
PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')} PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')}
PERMISSION_KEY_VIEW = {'namespace': 'django_gpg', 'name': 'key_view', 'label': _(u'View keys')}
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 setup # Permission setup
set_namespace_title('django_gpg', _(u'Signatures')) set_namespace_title('django_gpg', _(u'Signatures'))
register_permission(PERMISSION_DOCUMENT_VERIFY) register_permission(PERMISSION_DOCUMENT_VERIFY)
register_permission(PERMISSION_KEY_VIEW)
register_permission(PERMISSION_KEY_DELETE)
register_permission(PERMISSION_KEYSERVER_QUERY)
register_permission(PERMISSION_KEY_RECEIVE)
document_verify = {'text': _(u'Signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} # Setup views
private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]}
public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]}
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 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, [document_verify], menu_name='form_header')
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])
register_links(KeyServerKey, [key_receive])
register_setup(private_keys)
register_setup(public_keys)

View File

@@ -1,16 +1,20 @@
import types import types
from StringIO import StringIO from StringIO import StringIO
from pickle import dumps from pickle import dumps
import logging
import gnupg
from django.core.files.base import File from django.core.files.base import File
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.http import urlquote_plus
from django_gpg.exceptions import GPGVerificationError, GPGSigningError, \ from hkp import KeyServer
GPGDecryptionError, KeyDeleteError, KeyGenerationError, \ import gnupg
KeyFetchingError, KeyDoesNotExist
from django_gpg.exceptions import (GPGVerificationError, GPGSigningError,
GPGDecryptionError, KeyDeleteError, KeyGenerationError,
KeyFetchingError, KeyDoesNotExist, KeyImportError)
logger = logging.getLogger(__name__)
KEY_TYPES = { KEY_TYPES = {
'pub': _(u'Public'), 'pub': _(u'Public'),
@@ -31,6 +35,8 @@ KEY_SECONDARY_CLASSES = (
((KEY_CLASS_ELG), _(u'Elgamal')), ((KEY_CLASS_ELG), _(u'Elgamal')),
) )
KEYSERVER_DEFAULT_PORT = 11371
SIGNATURE_STATE_BAD = 'signature bad' SIGNATURE_STATE_BAD = 'signature bad'
SIGNATURE_STATE_NONE = None SIGNATURE_STATE_NONE = None
SIGNATURE_STATE_ERROR = 'signature error' SIGNATURE_STATE_ERROR = 'signature error'
@@ -300,3 +306,26 @@ class GPG(object):
return Key.get(self, import_result.fingerprints[0], secret=False) return Key.get(self, import_result.fingerprints[0], secret=False)
raise KeyFetchingError raise KeyFetchingError
def query(self, term):
results = {}
for keyserver in self.keyservers:
url = u'http://%s' % keyserver
server = KeyServer(url)
try:
key_list = server.search(term)
for key in key_list:
results[key.keyid] = key
except:
pass
return results.values()
def import_key(self, key_data):
import_result = self.gpg.import_keys(key_data)
logger.debug('import_result: %s' % import_result)
if import_result:
return Key.get(self, import_result.fingerprints[0], secret=False)
raise KeyImportError

View File

@@ -29,3 +29,6 @@ class KeyFetchingError(GPGException):
class KeyDoesNotExist(GPGException): class KeyDoesNotExist(GPGException):
pass pass
class KeyImportError(GPGException):
pass

13
apps/django_gpg/forms.py Normal file
View File

@@ -0,0 +1,13 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.conf import settings
class KeySearchForm(forms.Form):
term = forms.CharField(
label=_(u'Term'),
help_text=_(u'Name, e-mail, key ID or key fingerprint to look for.')
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -5,4 +5,7 @@ urlpatterns = patterns('django_gpg.views',
url(r'^list/private/$', 'key_list', {'secret': True}, 'key_private_list'), url(r'^list/private/$', 'key_list', {'secret': True}, 'key_private_list'),
url(r'^list/public/$', 'key_list', {'secret': False}, 'key_public_list'), url(r'^list/public/$', 'key_list', {'secret': False}, 'key_public_list'),
url(r'^verify/(?P<document_pk>\d+)/$', 'document_verify', (), 'document_verify'), url(r'^verify/(?P<document_pk>\d+)/$', 'document_verify', (), 'document_verify'),
url(r'^query/$', 'key_query', (), 'key_query'),
url(r'^receive/(?P<key_id>.+)/$', 'key_receive', (), 'key_receive'),
) )

View File

@@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
import logging
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
@@ -12,45 +13,181 @@ from django.template.defaultfilters import force_escape
from documents.models import Document, RecentDocument from documents.models import Document, RecentDocument
from permissions.api import check_permissions from permissions.api import check_permissions
from common.utils import pretty_size, parse_range, urlquote, \
return_diff, encapsulate
from django_gpg.api import Key, SIGNATURE_STATES from django_gpg.api import Key, SIGNATURE_STATES
from django_gpg.runtime import gpg from django_gpg.runtime import gpg
from django_gpg.exceptions import GPGVerificationError from django_gpg.exceptions import GPGVerificationError, KeyFetchingError
from django_gpg import PERMISSION_DOCUMENT_VERIFY 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
logger = logging.getLogger(__name__)
def key_receive(request, key_id):
check_permissions(request.user, [PERMISSION_KEY_RECEIVE])
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':
try:
term = request.GET.get('term')
results = gpg.query(term)
keys_dict = dict([(key.keyid, key) for key in results])
key = gpg.import_key(keys_dict[key_id].key)
messages.success(request, _(u'Key: %s, imported successfully.') % key)
return HttpResponseRedirect(next)
except (KeyFetchingError, KeyError, TypeError):
messages.error(request, _(u'Unable to import key id: %s') % key_id)
return HttpResponseRedirect(previous)
return render_to_response('generic_confirm.html', {
'title': _(u'Import key'),
'message': _(u'Are you sure you wish to import key id: %s?') % key_id,
'form_icon': 'key_add.png',
'next': next,
'previous': previous,
'submit_method': 'GET',
}, context_instance=RequestContext(request))
def key_list(request, secret=True): def key_list(request, secret=True):
check_permissions(request.user, [PERMISSION_KEY_VIEW])
if secret: if secret:
object_list = Key.get_all(gpg, secret=True) object_list = Key.get_all(gpg, secret=True)
title = _(u'Private key list') title = _(u'private keys')
else: else:
object_list = Key.get_all(gpg) object_list = Key.get_all(gpg)
title = _(u'Public key list') title = _(u'public keys')
return render_to_response('key_list.html', { return render_to_response('generic_list.html', {
'object_list': object_list, 'object_list': object_list,
'title': title, 'title': title,
'hide_object': True,
'extra_columns': [
{
'name': _(u'Key ID'),
'attribute': 'key_id',
},
{
'name': _(u'Owner'),
'attribute': encapsulate(lambda x: u', '.join(x.uids)),
},
]
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
def key_delete(request, fingerprint, key_type): def key_delete(request, fingerprint, key_type):
check_permissions(request.user, [PERMISSION_KEY_DELETE])
secret = key_type == 'sec'
key = Key.get(gpg, fingerprint, secret=secret)
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': if request.method == 'POST':
try: try:
secret = key_type == 'sec'
key = Key.get(gpg, fingerprint, secret=secret)
gpg.delete_key(key) gpg.delete_key(key)
messages.success(request, _(u'Key: %s, deleted successfully.') % fingerprint) messages.success(request, _(u'Key: %s, deleted successfully.') % fingerprint)
return HttpResponseRedirect(reverse('home_view')) return HttpResponseRedirect(next)
except Exception, msg: except Exception, msg:
messages.error(request, msg) messages.error(request, msg)
return HttpResponseRedirect(reverse('home_view')) return HttpResponseRedirect(previous)
return render_to_response('generic_confirm.html', { return render_to_response('generic_confirm.html', {
'title': _(u'Delete key'), 'title': _(u'Delete key'),
'message': _(u'Are you sure you wish to delete key:%s? If you try to delete a public key that is part of a public/private pair the private key will be deleted as well.') % Key.get(gpg, fingerprint) 'delete_view': True,
'message': _(u'Are you sure you wish to delete key: %s? If you try to delete a public key that is part of a public/private pair the private key will be deleted as well.') % key,
'form_icon': 'key_delete.png',
'next': next,
'previous': previous,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
def key_query(request):
check_permissions(request.user, [PERMISSION_KEYSERVER_QUERY])
subtemplates_list = []
term = request.GET.get('term')
form = KeySearchForm(initial={'term': term})
subtemplates_list.append(
{
'name': 'generic_form_subtemplate.html',
'context': {
'title': _(u'Query key server'),
'form': form,
'submit_method': 'GET',
},
}
)
if term:
results = gpg.query(term)
subtemplates_list.append(
{
'name': 'generic_list_subtemplate.html',
'context': {
'title': _(u'results'),
'object_list': results,
'hide_object': True,
'extra_columns': [
{
'name': _(u'ID'),
'attribute': 'keyid',
},
{
'name': _(u'type'),
'attribute': 'algo',
},
{
'name': _(u'creation date'),
'attribute': 'creation_date',
},
{
'name': _(u'disabled'),
'attribute': 'disabled',
},
{
'name': _(u'expiration date'),
'attribute': 'expiration_date',
},
{
'name': _(u'expired'),
'attribute': 'expired',
},
{
'name': _(u'length'),
'attribute': 'key_length',
},
{
'name': _(u'revoked'),
'attribute': 'revoked',
},
{
'name': _(u'Identifies'),
'attribute': encapsulate(lambda x: u', '.join([identity.uid for identity in x.identities])),
},
]
},
}
)
return render_to_response('generic_form.html', {
'subtemplates_list': subtemplates_list,
}, context_instance=RequestContext(request))
def document_verify(request, document_pk): def document_verify(request, document_pk):
check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY])
document = get_object_or_404(Document, pk=document_pk) document = get_object_or_404(Document, pk=document_pk)