Update Django GPG app
Add keyword arguments to all calls. Rename URL parameters to be
explicit ("key_id"). Add key delete view test. Update tests
to use a mixin for repeated key creation code. Grant permissions
and access the proper way using self.grant_permission and
self.grant_access.
Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -31,6 +31,8 @@ class APIKeyView(generics.RetrieveDestroyAPIView):
|
|||||||
get: Return the details of the selected key.
|
get: Return the details of the selected key.
|
||||||
"""
|
"""
|
||||||
filter_backends = (MayanObjectPermissionsFilter,)
|
filter_backends = (MayanObjectPermissionsFilter,)
|
||||||
|
lookup_field = 'pk'
|
||||||
|
lookup_url_kwarg = 'key_id'
|
||||||
mayan_object_permissions = {
|
mayan_object_permissions = {
|
||||||
'DELETE': (permission_key_delete,),
|
'DELETE': (permission_key_delete,),
|
||||||
'GET': (permission_key_view,),
|
'GET': (permission_key_view,),
|
||||||
|
|||||||
@@ -17,6 +17,24 @@ class GPGBackend(object):
|
|||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class KeyStub(object):
|
||||||
|
def __init__(self, raw):
|
||||||
|
self.fingerprint = raw['keyid']
|
||||||
|
self.key_type = raw['type']
|
||||||
|
self.date = date.fromtimestamp(int(raw['date']))
|
||||||
|
if raw['expires']:
|
||||||
|
self.expires = date.fromtimestamp(int(raw['expires']))
|
||||||
|
else:
|
||||||
|
self.expires = None
|
||||||
|
self.length = raw['length']
|
||||||
|
self.user_id = raw['uids']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_id(self):
|
||||||
|
return self.fingerprint[-8:]
|
||||||
|
key_id.fget.short_description = _('Key ID')
|
||||||
|
|
||||||
|
|
||||||
class PythonGNUPGBackend(GPGBackend):
|
class PythonGNUPGBackend(GPGBackend):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _import_key(gpg, **kwargs):
|
def _import_key(gpg, **kwargs):
|
||||||
@@ -136,24 +154,6 @@ class PythonGNUPGBackend(GPGBackend):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class KeyStub(object):
|
|
||||||
def __init__(self, raw):
|
|
||||||
self.fingerprint = raw['keyid']
|
|
||||||
self.key_type = raw['type']
|
|
||||||
self.date = date.fromtimestamp(int(raw['date']))
|
|
||||||
if raw['expires']:
|
|
||||||
self.expires = date.fromtimestamp(int(raw['expires']))
|
|
||||||
else:
|
|
||||||
self.expires = None
|
|
||||||
self.length = raw['length']
|
|
||||||
self.user_id = raw['uids']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def key_id(self):
|
|
||||||
return self.fingerprint[-8:]
|
|
||||||
key_id.fget.short_description = _('Key ID')
|
|
||||||
|
|
||||||
|
|
||||||
class SignatureVerification(object):
|
class SignatureVerification(object):
|
||||||
def __init__(self, raw):
|
def __init__(self, raw):
|
||||||
self.user_id = raw['username']
|
self.user_id = raw['username']
|
||||||
|
|||||||
@@ -44,6 +44,6 @@ class KeyDetailForm(DetailForm):
|
|||||||
|
|
||||||
class KeySearchForm(forms.Form):
|
class KeySearchForm(forms.Form):
|
||||||
term = forms.CharField(
|
term = forms.CharField(
|
||||||
label=_('Term'),
|
help_text=_('Name, e-mail, key ID or key fingerprint to look for.'),
|
||||||
help_text=_('Name, e-mail, key ID or key fingerprint to look for.')
|
label=_('Term')
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,16 +11,18 @@ from .permissions import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
link_key_delete = Link(
|
link_key_delete = Link(
|
||||||
args=('resolved_object.pk',), permissions=(permission_key_delete,),
|
kwargs={'key_id': 'resolved_object.pk'},
|
||||||
tags='dangerous', text=_('Delete'), view='django_gpg:key_delete',
|
permissions=(permission_key_delete,), tags='dangerous', text=_('Delete'),
|
||||||
|
view='django_gpg:key_delete'
|
||||||
)
|
)
|
||||||
link_key_detail = Link(
|
link_key_detail = Link(
|
||||||
args=('resolved_object.pk',), permissions=(permission_key_view,),
|
kwargs={'key_id': 'resolved_object.pk'}, permissions=(permission_key_view,),
|
||||||
text=_('Details'), view='django_gpg:key_detail',
|
text=_('Details'), view='django_gpg:key_detail'
|
||||||
)
|
)
|
||||||
link_key_download = Link(
|
link_key_download = Link(
|
||||||
args=('resolved_object.pk',), permissions=(permission_key_download,),
|
kwargs={'key_id': 'resolved_object.pk'},
|
||||||
text=_('Download'), view='django_gpg:key_download',
|
permissions=(permission_key_download,), text=_('Download'),
|
||||||
|
view='django_gpg:key_download'
|
||||||
)
|
)
|
||||||
link_key_query = Link(
|
link_key_query = Link(
|
||||||
icon_class=icon_keyserver_search,
|
icon_class=icon_keyserver_search,
|
||||||
@@ -28,7 +30,7 @@ link_key_query = Link(
|
|||||||
view='django_gpg:key_query'
|
view='django_gpg:key_query'
|
||||||
)
|
)
|
||||||
link_key_receive = Link(
|
link_key_receive = Link(
|
||||||
args='object.key_id', keep_query=True,
|
keep_query=True, kwargs={'key_id': 'object.key_id'},
|
||||||
permissions=(permission_key_receive,), text=_('Import'),
|
permissions=(permission_key_receive,), text=_('Import'),
|
||||||
view='django_gpg:key_receive',
|
view='django_gpg:key_receive',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ if platform.system() == 'OpenBSD':
|
|||||||
else:
|
else:
|
||||||
DEFAULT_GPG_PATH = '/usr/bin/gpg1'
|
DEFAULT_GPG_PATH = '/usr/bin/gpg1'
|
||||||
|
|
||||||
|
DEFAULT_KEYSERVER = 'pool.sks-keyservers.net'
|
||||||
DEFAULT_SETTING_GPG_BACKEND = 'mayan.apps.django_gpg.classes.PythonGNUPGBackend'
|
DEFAULT_SETTING_GPG_BACKEND = 'mayan.apps.django_gpg.classes.PythonGNUPGBackend'
|
||||||
|
|
||||||
ERROR_MSG_BAD_PASSPHRASE = 'BAD_PASSPHRASE'
|
ERROR_MSG_BAD_PASSPHRASE = 'BAD_PASSPHRASE'
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ class Key(models.Model):
|
|||||||
raise ValidationError(_('Key already exists.'))
|
raise ValidationError(_('Key already exists.'))
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('django_gpg:key_detail', args=(self.pk,))
|
return reverse(
|
||||||
|
viewname='django_gpg:key_detail', kwargs={'key_pk': self.pk}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def key_id(self):
|
def key_id(self):
|
||||||
|
|||||||
@@ -7,23 +7,23 @@ from mayan.apps.permissions import PermissionNamespace
|
|||||||
namespace = PermissionNamespace(label=_('Key management'), name='django_gpg')
|
namespace = PermissionNamespace(label=_('Key management'), name='django_gpg')
|
||||||
|
|
||||||
permission_key_delete = namespace.add_permission(
|
permission_key_delete = namespace.add_permission(
|
||||||
name='key_delete', label=_('Delete keys')
|
label=_('Delete keys'), name='key_delete'
|
||||||
)
|
)
|
||||||
permission_key_download = namespace.add_permission(
|
permission_key_download = namespace.add_permission(
|
||||||
name='key_download', label=_('Download keys')
|
label=_('Download keys'), name='key_download'
|
||||||
)
|
)
|
||||||
permission_key_receive = namespace.add_permission(
|
permission_key_receive = namespace.add_permission(
|
||||||
name='key_receive', label=_('Import keys from keyservers')
|
label=_('Import keys from keyservers'), name='key_receive'
|
||||||
)
|
)
|
||||||
permission_key_sign = namespace.add_permission(
|
permission_key_sign = namespace.add_permission(
|
||||||
name='key_sign', label=_('Use keys to sign content')
|
label=_('Use keys to sign content'), name='key_sign'
|
||||||
)
|
)
|
||||||
permission_key_upload = namespace.add_permission(
|
permission_key_upload = namespace.add_permission(
|
||||||
name='key_upload', label=_('Upload keys')
|
label=_('Upload keys'), name='key_upload'
|
||||||
)
|
)
|
||||||
permission_key_view = namespace.add_permission(
|
permission_key_view = namespace.add_permission(
|
||||||
name='key_view', label=_('View keys')
|
label=_('View keys'), name='key_view'
|
||||||
)
|
)
|
||||||
permission_keyserver_query = namespace.add_permission(
|
permission_keyserver_query = namespace.add_permission(
|
||||||
name='keyserver_query', label=_('Query keyservers')
|
label=_('Query keyservers'), name='keyserver_query'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from .models import Key
|
|||||||
class KeySerializer(serializers.ModelSerializer):
|
class KeySerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
|
'lookup_url_kwarg': 'key_id',
|
||||||
'url': {'view_name': 'rest_api:key-detail'},
|
'url': {'view_name': 'rest_api:key-detail'},
|
||||||
}
|
}
|
||||||
fields = (
|
fields = (
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
from mayan.apps.smart_settings import Namespace
|
from mayan.apps.smart_settings import Namespace
|
||||||
|
|
||||||
from .literals import DEFAULT_GPG_PATH, DEFAULT_SETTING_GPG_BACKEND
|
from .literals import (
|
||||||
|
DEFAULT_GPG_PATH, DEFAULT_KEYSERVER, DEFAULT_SETTING_GPG_BACKEND
|
||||||
|
)
|
||||||
|
|
||||||
namespace = Namespace(name='django_gpg', label=_('Signatures'))
|
namespace = Namespace(name='django_gpg', label=_('Signatures'))
|
||||||
|
|
||||||
@@ -23,6 +25,6 @@ setting_gpg_backend_arguments = namespace.add_setting(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
setting_keyserver = namespace.add_setting(
|
setting_keyserver = namespace.add_setting(
|
||||||
global_name='SIGNATURES_KEYSERVER', default='pool.sks-keyservers.net',
|
global_name='SIGNATURES_KEYSERVER', default=DEFAULT_KEYSERVER,
|
||||||
help_text=_('Keyserver used to query for keys.')
|
help_text=_('Keyserver used to query for keys.')
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,18 @@ import os
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
MOCK_SEARCH_KEYS_RESPONSE = [
|
||||||
|
{
|
||||||
|
'algo': u'1',
|
||||||
|
'date': u'1311475606',
|
||||||
|
'expires': u'1643601600',
|
||||||
|
'keyid': u'607138F1AECC5A5CA31CB7715F3F7F75D210724D',
|
||||||
|
'length': u'2048',
|
||||||
|
'type': u'pub',
|
||||||
|
'uids': [u'Roberto Rosario <roberto.rosario.gonzalez@gmail.com>']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
TEST_DETACHED_SIGNATURE = os.path.join(
|
TEST_DETACHED_SIGNATURE = os.path.join(
|
||||||
settings.BASE_DIR, 'apps', 'django_gpg', 'tests', 'contrib',
|
settings.BASE_DIR, 'apps', 'django_gpg', 'tests', 'contrib',
|
||||||
'test_files', 'test_file.txt.asc'
|
'test_files', 'test_file.txt.asc'
|
||||||
|
|||||||
9
mayan/apps/django_gpg/tests/mixins.py
Normal file
9
mayan/apps/django_gpg/tests/mixins.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from ..models import Key
|
||||||
|
|
||||||
|
from .literals import TEST_KEY_DATA
|
||||||
|
|
||||||
|
|
||||||
|
class KeyTestMixin(object):
|
||||||
|
def _create_test_key(self):
|
||||||
|
# Creating a Key instance is analogous to importing a key
|
||||||
|
self.test_key = Key.objects.create(key_data=TEST_KEY_DATA)
|
||||||
@@ -32,7 +32,7 @@ class KeyAPITestCase(BaseAPITestCase):
|
|||||||
def test_key_create_view_no_permission(self):
|
def test_key_create_view_no_permission(self):
|
||||||
response = self._request_key_create_view()
|
response = self._request_key_create_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
self.assertEqual(Key.objects.all().count(), 0)
|
self.assertEqual(Key.objects.count(), 0)
|
||||||
|
|
||||||
def test_key_create_view_with_permission(self):
|
def test_key_create_view_with_permission(self):
|
||||||
self.grant_permission(permission=permission_key_upload)
|
self.grant_permission(permission=permission_key_upload)
|
||||||
@@ -50,7 +50,7 @@ class KeyAPITestCase(BaseAPITestCase):
|
|||||||
|
|
||||||
def _request_key_delete_view(self):
|
def _request_key_delete_view(self):
|
||||||
return self.delete(
|
return self.delete(
|
||||||
viewname='rest_api:key-detail', args=(self.key.pk,)
|
viewname='rest_api:key-detail', kwargs={'key_id': self.key.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_key_delete_view_no_access(self):
|
def test_key_delete_view_no_access(self):
|
||||||
@@ -72,7 +72,7 @@ class KeyAPITestCase(BaseAPITestCase):
|
|||||||
|
|
||||||
def _request_key_detail_view(self):
|
def _request_key_detail_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='rest_api:key-detail', args=(self.key.pk,)
|
viewname='rest_api:key-detail', kwargs={'key_id': self.key.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_key_detail_view_no_access(self):
|
def test_key_detail_view_no_access(self):
|
||||||
|
|||||||
@@ -17,22 +17,12 @@ from ..exceptions import (
|
|||||||
from ..models import Key
|
from ..models import Key
|
||||||
|
|
||||||
from .literals import (
|
from .literals import (
|
||||||
TEST_DETACHED_SIGNATURE, TEST_FILE, TEST_KEY_DATA, TEST_KEY_FINGERPRINT,
|
MOCK_SEARCH_KEYS_RESPONSE, TEST_DETACHED_SIGNATURE, TEST_FILE,
|
||||||
TEST_KEY_PASSPHRASE, TEST_RECEIVE_KEY, TEST_SEARCH_FINGERPRINT,
|
TEST_KEY_FINGERPRINT, TEST_KEY_PASSPHRASE, TEST_RECEIVE_KEY,
|
||||||
TEST_SEARCH_UID, TEST_SIGNED_FILE, TEST_SIGNED_FILE_CONTENT
|
TEST_SEARCH_FINGERPRINT, TEST_SEARCH_UID, TEST_SIGNED_FILE,
|
||||||
|
TEST_SIGNED_FILE_CONTENT
|
||||||
)
|
)
|
||||||
|
from .mixins import KeyTestMixin
|
||||||
MOCK_SEARCH_KEYS_RESPONSE = [
|
|
||||||
{
|
|
||||||
'algo': u'1',
|
|
||||||
'date': u'1311475606',
|
|
||||||
'expires': u'1643601600',
|
|
||||||
'keyid': u'607138F1AECC5A5CA31CB7715F3F7F75D210724D',
|
|
||||||
'length': u'2048',
|
|
||||||
'type': u'pub',
|
|
||||||
'uids': [u'Roberto Rosario <roberto.rosario.gonzalez@gmail.com>']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def mock_recv_keys(self, keyserver, *keyids):
|
def mock_recv_keys(self, keyserver, *keyids):
|
||||||
@@ -45,12 +35,11 @@ def mock_recv_keys(self, keyserver, *keyids):
|
|||||||
return ImportResult()
|
return ImportResult()
|
||||||
|
|
||||||
|
|
||||||
class KeyTestCase(BaseTestCase):
|
class KeyTestCase(KeyTestMixin, BaseTestCase):
|
||||||
def test_key_instance_creation(self):
|
def test_key_instance_creation(self):
|
||||||
# Creating a Key instance is analogous to importing a key
|
self._create_test_key()
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
|
||||||
|
|
||||||
self.assertEqual(key.fingerprint, TEST_KEY_FINGERPRINT)
|
self.assertEqual(self.test_key.fingerprint, TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
@mock.patch.object(gnupg.GPG, 'search_keys', autospec=True)
|
@mock.patch.object(gnupg.GPG, 'search_keys', autospec=True)
|
||||||
def test_key_search(self, search_keys):
|
def test_key_search(self, search_keys):
|
||||||
@@ -92,7 +81,7 @@ class KeyTestCase(BaseTestCase):
|
|||||||
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
def test_embedded_verification_with_key(self):
|
def test_embedded_verification_with_key(self):
|
||||||
Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
||||||
result = Key.objects.verify_file(signed_file)
|
result = Key.objects.verify_file(signed_file)
|
||||||
@@ -100,7 +89,7 @@ class KeyTestCase(BaseTestCase):
|
|||||||
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
def test_embedded_verification_with_correct_fingerprint(self):
|
def test_embedded_verification_with_correct_fingerprint(self):
|
||||||
Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
||||||
result = Key.objects.verify_file(
|
result = Key.objects.verify_file(
|
||||||
@@ -111,14 +100,14 @@ class KeyTestCase(BaseTestCase):
|
|||||||
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
def test_embedded_verification_with_incorrect_fingerprint(self):
|
def test_embedded_verification_with_incorrect_fingerprint(self):
|
||||||
Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
||||||
with self.assertRaises(KeyDoesNotExist):
|
with self.assertRaises(KeyDoesNotExist):
|
||||||
Key.objects.verify_file(signed_file, key_fingerprint='999')
|
Key.objects.verify_file(signed_file, key_fingerprint='999')
|
||||||
|
|
||||||
def test_signed_file_decryption(self):
|
def test_signed_file_decryption(self):
|
||||||
Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
||||||
result = Key.objects.decrypt_file(file_object=signed_file)
|
result = Key.objects.decrypt_file(file_object=signed_file)
|
||||||
@@ -145,7 +134,7 @@ class KeyTestCase(BaseTestCase):
|
|||||||
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
def test_detached_verification_with_key(self):
|
def test_detached_verification_with_key(self):
|
||||||
Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_DETACHED_SIGNATURE, mode='rb') as signature_file:
|
with open(TEST_DETACHED_SIGNATURE, mode='rb') as signature_file:
|
||||||
with open(TEST_FILE, mode='rb') as test_file:
|
with open(TEST_FILE, mode='rb') as test_file:
|
||||||
@@ -157,29 +146,29 @@ class KeyTestCase(BaseTestCase):
|
|||||||
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
||||||
|
|
||||||
def test_detached_signing_no_passphrase(self):
|
def test_detached_signing_no_passphrase(self):
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with self.assertRaises(NeedPassphrase):
|
with self.assertRaises(NeedPassphrase):
|
||||||
with open(TEST_FILE, mode='rb') as test_file:
|
with open(TEST_FILE, mode='rb') as test_file:
|
||||||
key.sign_file(
|
self.test_key.sign_file(
|
||||||
file_object=test_file, detached=True,
|
file_object=test_file, detached=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_detached_signing_bad_passphrase(self):
|
def test_detached_signing_bad_passphrase(self):
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with self.assertRaises(PassphraseError):
|
with self.assertRaises(PassphraseError):
|
||||||
with open(TEST_FILE, mode='rb') as test_file:
|
with open(TEST_FILE, mode='rb') as test_file:
|
||||||
key.sign_file(
|
self.test_key.sign_file(
|
||||||
file_object=test_file, detached=True,
|
file_object=test_file, detached=True,
|
||||||
passphrase='bad passphrase'
|
passphrase='bad passphrase'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_detached_signing_with_passphrase(self):
|
def test_detached_signing_with_passphrase(self):
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
with open(TEST_FILE, mode='rb') as test_file:
|
with open(TEST_FILE, mode='rb') as test_file:
|
||||||
detached_signature = key.sign_file(
|
detached_signature = self.test_key.sign_file(
|
||||||
file_object=test_file, detached=True,
|
file_object=test_file, detached=True,
|
||||||
passphrase=TEST_KEY_PASSPHRASE
|
passphrase=TEST_KEY_PASSPHRASE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,62 +5,79 @@ from django_downloadview.test import assert_download_response
|
|||||||
from mayan.apps.common.tests import GenericViewTestCase
|
from mayan.apps.common.tests import GenericViewTestCase
|
||||||
|
|
||||||
from ..models import Key
|
from ..models import Key
|
||||||
from ..permissions import permission_key_download, permission_key_upload
|
from ..permissions import (
|
||||||
|
permission_key_delete, permission_key_download, permission_key_upload
|
||||||
|
)
|
||||||
|
|
||||||
from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
|
from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
|
||||||
|
from .mixins import KeyTestMixin
|
||||||
|
|
||||||
|
|
||||||
class KeyViewTestCase(GenericViewTestCase):
|
class KeyViewTestCase(KeyTestMixin, GenericViewTestCase):
|
||||||
def test_key_download_view_no_permission(self):
|
def _request_key_delete_view(self):
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
return self.post(
|
||||||
|
viewname='django_gpg:key_delete',
|
||||||
self.login_user()
|
kwargs={'key_id': self.test_key.pk}
|
||||||
|
|
||||||
response = self.get(
|
|
||||||
viewname='django_gpg:key_download', args=(key.pk,)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
def test_key_delete_view_no_permission(self):
|
||||||
|
self._create_test_key()
|
||||||
|
|
||||||
|
response = self._request_key_delete_view()
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_key_delete_view_with_access(self):
|
||||||
|
self._create_test_key()
|
||||||
|
|
||||||
|
self.grant_access(obj=self.test_key, permission=permission_key_delete)
|
||||||
|
|
||||||
|
response = self._request_key_delete_view()
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
self.assertEqual(Key.objects.count(), 0)
|
||||||
|
|
||||||
|
def _request_key_download_view(self):
|
||||||
|
return self.get(
|
||||||
|
viewname='django_gpg:key_download',
|
||||||
|
kwargs={'key_id': self.test_key.pk}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_key_download_view_no_permission(self):
|
||||||
|
self._create_test_key()
|
||||||
|
|
||||||
|
response = self._request_key_download_view()
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_key_download_view_with_permission(self):
|
def test_key_download_view_with_permission(self):
|
||||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
self._create_test_key()
|
||||||
|
|
||||||
self.login_user()
|
self.grant_access(obj=self.test_key, permission=permission_key_download)
|
||||||
|
|
||||||
self.role.permissions.add(permission_key_download.stored_permission)
|
|
||||||
|
|
||||||
self.expected_content_type = 'application/octet-stream; charset=utf-8'
|
self.expected_content_type = 'application/octet-stream; charset=utf-8'
|
||||||
|
|
||||||
response = self.get(
|
response = self._request_key_download_view()
|
||||||
viewname='django_gpg:key_download', args=(key.pk,)
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_download_response(
|
assert_download_response(
|
||||||
self, response=response, content=key.key_data,
|
test_case=self, response=response, content=self.test_key.key_data,
|
||||||
basename=key.key_id,
|
basename=self.test_key.key_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_key_upload_view_no_permission(self):
|
def _request_key_upload_view(self):
|
||||||
self.login_user()
|
return self.post(
|
||||||
|
|
||||||
response = self.post(
|
|
||||||
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA}
|
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_key_upload_view_no_permission(self):
|
||||||
|
response = self._request_key_upload_view()
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
self.assertEqual(Key.objects.count(), 0)
|
self.assertEqual(Key.objects.count(), 0)
|
||||||
|
|
||||||
def test_key_upload_view_with_permission(self):
|
def test_key_upload_view_with_permission(self):
|
||||||
self.login_user()
|
self.grant_permission(permission=permission_key_upload)
|
||||||
|
|
||||||
self.role.permissions.add(permission_key_upload.stored_permission)
|
response = self._request_key_upload_view()
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
response = self.post(
|
|
||||||
viewname='django_gpg:key_upload', data={'key_data': TEST_KEY_DATA},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertContains(response, 'created', status_code=200)
|
|
||||||
|
|
||||||
self.assertEqual(Key.objects.count(), 1)
|
self.assertEqual(Key.objects.count(), 1)
|
||||||
self.assertEqual(Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT)
|
self.assertEqual(Key.objects.first().fingerprint, TEST_KEY_FINGERPRINT)
|
||||||
|
|||||||
@@ -11,39 +11,44 @@ from .views import (
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(
|
url(
|
||||||
r'^(?P<pk>\d+)/$', KeyDetailView.as_view(), name='key_detail'
|
regex=r'^keys/(?P<key_id>\d+)/$', name='key_detail',
|
||||||
|
view=KeyDetailView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<pk>\d+)/delete/$', KeyDeleteView.as_view(), name='key_delete'
|
regex=r'^keys/(?P<key_id>\d+)/delete/$', name='key_delete',
|
||||||
|
view=KeyDeleteView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<pk>\d+)/download/$', KeyDownloadView.as_view(),
|
regex=r'^keys/(?P<key_id>\d+)/download/$', name='key_download',
|
||||||
name='key_download'
|
view=KeyDownloadView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^list/private/$', PrivateKeyListView.as_view(),
|
regex=r'^keys/private/$', name='key_private_list',
|
||||||
name='key_private_list'
|
view=PrivateKeyListView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^list/public/$', PublicKeyListView.as_view(), name='key_public_list'
|
regex=r'^keys/public/$', name='key_public_list',
|
||||||
|
view=PublicKeyListView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^upload/$', KeyUploadView.as_view(), name='key_upload'
|
regex=r'^keys/upload/$', name='key_upload',
|
||||||
|
view=KeyUploadView.as_view()
|
||||||
),
|
),
|
||||||
url(r'^query/$', KeyQueryView.as_view(), name='key_query'),
|
url(regex=r'^keys/query/$', name='key_query', view=KeyQueryView.as_view()),
|
||||||
url(
|
url(
|
||||||
r'^query/results/$', KeyQueryResultView.as_view(),
|
regex=r'^keys/query/results/$', name='key_query_results',
|
||||||
name='key_query_results'
|
view=KeyQueryResultView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^receive/(?P<key_id>.+)/$', KeyReceive.as_view(), name='key_receive'
|
regex=r'^keys/receive/(?P<key_id>.+)/$', name='key_receive',
|
||||||
),
|
view=KeyReceive.as_view()
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
api_urls = [
|
api_urls = [
|
||||||
url(
|
url(
|
||||||
r'^keys/(?P<pk>[0-9]+)/$', APIKeyView.as_view(),
|
regex=r'^keys/(?P<key_id>\d+)/$', name='key-detail',
|
||||||
name='key-detail'
|
view=APIKeyView.as_view()
|
||||||
),
|
),
|
||||||
url(r'^keys/$', APIKeyListView.as_view(), name='key-list'),
|
url(regex=r'^keys/$', name='key-list', view=APIKeyListView.as_view())
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -30,12 +30,13 @@ logger = logging.getLogger(__name__)
|
|||||||
class KeyDeleteView(SingleObjectDeleteView):
|
class KeyDeleteView(SingleObjectDeleteView):
|
||||||
model = Key
|
model = Key
|
||||||
object_permission = permission_key_delete
|
object_permission = permission_key_delete
|
||||||
|
pk_url_kwarg = 'key_id'
|
||||||
|
|
||||||
def get_post_action_redirect(self):
|
def get_post_action_redirect(self):
|
||||||
if self.get_object().key_type == KEY_TYPE_PUBLIC:
|
if self.get_object().key_type == KEY_TYPE_PUBLIC:
|
||||||
return reverse_lazy('django_gpg:key_public_list')
|
return reverse_lazy(viewname='django_gpg:key_public_list')
|
||||||
else:
|
else:
|
||||||
return reverse_lazy('django_gpg:key_private_list')
|
return reverse_lazy(viewname='django_gpg:key_private_list')
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {'title': _('Delete key: %s') % self.get_object()}
|
return {'title': _('Delete key: %s') % self.get_object()}
|
||||||
@@ -45,6 +46,7 @@ class KeyDetailView(SingleObjectDetailView):
|
|||||||
form_class = KeyDetailForm
|
form_class = KeyDetailForm
|
||||||
model = Key
|
model = Key
|
||||||
object_permission = permission_key_view
|
object_permission = permission_key_view
|
||||||
|
pk_url_kwarg = 'key_id'
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
@@ -55,6 +57,7 @@ class KeyDetailView(SingleObjectDetailView):
|
|||||||
class KeyDownloadView(SingleObjectDownloadView):
|
class KeyDownloadView(SingleObjectDownloadView):
|
||||||
model = Key
|
model = Key
|
||||||
object_permission = permission_key_download
|
object_permission = permission_key_download
|
||||||
|
pk_url_kwarg = 'key_id'
|
||||||
|
|
||||||
def get_file(self):
|
def get_file(self):
|
||||||
key = self.get_object()
|
key = self.get_object()
|
||||||
@@ -63,7 +66,7 @@ class KeyDownloadView(SingleObjectDownloadView):
|
|||||||
|
|
||||||
|
|
||||||
class KeyReceive(ConfirmView):
|
class KeyReceive(ConfirmView):
|
||||||
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
|
post_action_redirect = reverse_lazy(viewname='django_gpg:key_public_list')
|
||||||
view_permission = permission_key_receive
|
view_permission = permission_key_receive
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
@@ -105,7 +108,7 @@ class KeyQueryView(SimpleView):
|
|||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
'form': self.get_form(),
|
'form': self.get_form(),
|
||||||
'form_action': reverse('django_gpg:key_query_results'),
|
'form_action': reverse(viewname='django_gpg:key_query_results'),
|
||||||
'submit_icon_class': icon_keyserver_search,
|
'submit_icon_class': icon_keyserver_search,
|
||||||
'submit_label': _('Search'),
|
'submit_label': _('Search'),
|
||||||
'submit_method': 'GET',
|
'submit_method': 'GET',
|
||||||
@@ -144,7 +147,7 @@ class KeyQueryResultView(SingleObjectListView):
|
|||||||
class KeyUploadView(SingleObjectCreateView):
|
class KeyUploadView(SingleObjectCreateView):
|
||||||
fields = ('key_data',)
|
fields = ('key_data',)
|
||||||
model = Key
|
model = Key
|
||||||
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
|
post_action_redirect = reverse_lazy(viewname='django_gpg:key_public_list')
|
||||||
view_permission = permission_key_upload
|
view_permission = permission_key_upload
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user