Update the django_gpg app to support organizations.
This commit is contained in:
@@ -10,6 +10,7 @@ import gnupg
|
||||
from django.db import models
|
||||
|
||||
from common.utils import mkdtemp, mkstemp
|
||||
from organizations.managers import CurrentOrganizationManager
|
||||
|
||||
from .classes import KeyStub, SignatureVerification
|
||||
from .exceptions import (
|
||||
@@ -193,3 +194,7 @@ class KeyManager(models.Manager):
|
||||
else:
|
||||
logger.debug('file not signed')
|
||||
raise VerificationError('File not signed')
|
||||
|
||||
|
||||
class OrganizationKeyManager(KeyManager, CurrentOrganizationManager):
|
||||
pass
|
||||
|
||||
@@ -14,6 +14,9 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='key',
|
||||
name='key_data',
|
||||
field=models.TextField(help_text='ASCII armored version of the key.', verbose_name='Key data'),
|
||||
field=models.TextField(
|
||||
help_text='ASCII armored version of the key.',
|
||||
verbose_name='Key data'
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
21
mayan/apps/django_gpg/migrations/0007_key_organization.py
Normal file
21
mayan/apps/django_gpg/migrations/0007_key_organization.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import organizations.shortcuts
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('organizations', '0002_add_data_default_organization'),
|
||||
('django_gpg', '0006_auto_20160510_0025'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='key',
|
||||
name='organization',
|
||||
field=models.ForeignKey(default=organizations.shortcuts.get_current_organization, to='organizations.Organization'),
|
||||
),
|
||||
]
|
||||
@@ -14,6 +14,8 @@ from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import mkdtemp
|
||||
from organizations.models import Organization
|
||||
from organizations.shortcuts import get_current_organization
|
||||
|
||||
from .exceptions import NeedPassphrase, PassphraseError
|
||||
from .literals import (
|
||||
@@ -21,7 +23,7 @@ from .literals import (
|
||||
ERROR_MSG_GOOD_PASSPHRASE, KEY_TYPE_CHOICES, KEY_TYPE_SECRET,
|
||||
OUTPUT_MESSAGE_CONTAINS_PRIVATE_KEY
|
||||
)
|
||||
from .managers import KeyManager
|
||||
from .managers import KeyManager, OrganizationKeyManager
|
||||
from .settings import setting_gpg_path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -44,6 +46,9 @@ def gpg_command(function):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Key(models.Model):
|
||||
organization = models.ForeignKey(
|
||||
Organization, default=get_current_organization
|
||||
)
|
||||
key_data = models.TextField(
|
||||
help_text=_('ASCII armored version of the key.'),
|
||||
verbose_name=_('Key data')
|
||||
@@ -72,11 +77,15 @@ class Key(models.Model):
|
||||
)
|
||||
|
||||
objects = KeyManager()
|
||||
on_organization = OrganizationKeyManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Key')
|
||||
verbose_name_plural = _('Keys')
|
||||
|
||||
def __str__(self):
|
||||
return '{} - {}'.format(self.key_id, self.user_id)
|
||||
|
||||
def clean(self):
|
||||
def import_key(gpg):
|
||||
return gpg.import_keys(key_data=self.key_data)
|
||||
@@ -86,7 +95,7 @@ class Key(models.Model):
|
||||
if not import_results.count:
|
||||
raise ValidationError(_('Invalid key data'))
|
||||
|
||||
if Key.objects.filter(fingerprint=import_results.fingerprints[0]).exists():
|
||||
if Key.on_organization.filter(fingerprint=import_results.fingerprints[0]).exists():
|
||||
raise ValidationError(_('Key already exists.'))
|
||||
|
||||
def get_absolute_url(self):
|
||||
@@ -123,9 +132,6 @@ class Key(models.Model):
|
||||
|
||||
super(Key, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return '{} - {}'.format(self.key_id, self.user_id)
|
||||
|
||||
def sign_file(self, file_object, passphrase=None, clearsign=False, detached=False, binary=False, output=None):
|
||||
# WARNING: using clearsign=True and subsequent decryption corrupts the
|
||||
# file. Appears to be a problem in python-gnupg or gpg itself.
|
||||
|
||||
@@ -5,9 +5,8 @@ import StringIO
|
||||
import gnupg
|
||||
import mock
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from common.utils import TemporaryFile
|
||||
from organizations.tests import OrganizationTestCase
|
||||
|
||||
from ..exceptions import (
|
||||
DecryptionError, KeyDoesNotExist, NeedPassphrase, PassphraseError,
|
||||
@@ -44,7 +43,7 @@ def mock_recv_keys(self, keyserver, *keyids):
|
||||
return ImportResult()
|
||||
|
||||
|
||||
class KeyTestCase(TestCase):
|
||||
class KeyTestCase(OrganizationTestCase):
|
||||
def test_key_instance_creation(self):
|
||||
# Creating a Key instance is analogous to importing a key
|
||||
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
||||
|
||||
83
mayan/apps/django_gpg/tests/test_organization_views.py
Normal file
83
mayan/apps/django_gpg/tests/test_organization_views.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import override_settings
|
||||
|
||||
from django_downloadview.test import assert_download_response
|
||||
|
||||
from organizations.tests.test_organization_views import OrganizationViewTestCase
|
||||
|
||||
from ..models import Key
|
||||
|
||||
from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
|
||||
|
||||
|
||||
@override_settings(OCR_AUTO_OCR=False)
|
||||
class OrganizationKeyViewsTestCase(OrganizationViewTestCase):
|
||||
def create_key(self):
|
||||
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||
self.key = Key.on_organization.create(key_data=TEST_KEY_DATA)
|
||||
|
||||
def test_key_delete_view(self):
|
||||
self.create_key()
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||
response = self.post(
|
||||
'django_gpg:key_delete',
|
||||
args=(self.key.pk,), follow=True
|
||||
)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_key_download_view(self):
|
||||
self.create_key()
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||
response = self.get(
|
||||
viewname='django_gpg:key_download', args=(self.key.pk,)
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||
response = self.get(
|
||||
viewname='django_gpg:key_download', args=(self.key.pk,)
|
||||
)
|
||||
|
||||
assert_download_response(
|
||||
self, response=response, content=self.key.key_data,
|
||||
basename=self.key.key_id,
|
||||
)
|
||||
|
||||
def test_key_upload_view(self):
|
||||
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||
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.on_organization.count(), 1)
|
||||
self.assertEqual(
|
||||
Key.on_organization.first().fingerprint, TEST_KEY_FINGERPRINT
|
||||
)
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||
self.assertEqual(Key.on_organization.count(), 0)
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||
self.assertEqual(Key.on_organization.count(), 1)
|
||||
|
||||
def test_key_private_list_view(self):
|
||||
self.create_key()
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||
response = self.get(viewname='django_gpg:key_private_list')
|
||||
|
||||
self.assertNotContains(
|
||||
response, text=self.key.key_id, status_code=200
|
||||
)
|
||||
|
||||
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||
response = self.get(viewname='django_gpg:key_private_list')
|
||||
|
||||
self.assertContains(
|
||||
response, text=self.key.key_id, status_code=200
|
||||
)
|
||||
@@ -3,9 +3,7 @@ from __future__ import absolute_import, unicode_literals
|
||||
from django_downloadview.test import assert_download_response
|
||||
|
||||
from common.tests.test_views import GenericViewTestCase
|
||||
from user_management.tests import (
|
||||
TEST_USER_USERNAME, TEST_USER_PASSWORD
|
||||
)
|
||||
from user_management.tests import TEST_USER_USERNAME, TEST_USER_PASSWORD
|
||||
|
||||
from ..models import Key
|
||||
from ..permissions import permission_key_download, permission_key_upload
|
||||
|
||||
@@ -25,7 +25,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class KeyDeleteView(SingleObjectDeleteView):
|
||||
model = Key
|
||||
object_permission = permission_key_delete
|
||||
|
||||
def get_post_action_redirect(self):
|
||||
@@ -37,10 +36,12 @@ class KeyDeleteView(SingleObjectDeleteView):
|
||||
def get_extra_context(self):
|
||||
return {'title': _('Delete key: %s') % self.get_object()}
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.all()
|
||||
|
||||
|
||||
class KeyDetailView(SingleObjectDetailView):
|
||||
form_class = KeyDetailForm
|
||||
model = Key
|
||||
object_permission = permission_key_view
|
||||
|
||||
def get_extra_context(self):
|
||||
@@ -48,9 +49,11 @@ class KeyDetailView(SingleObjectDetailView):
|
||||
'title': _('Details for key: %s') % self.get_object(),
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.all()
|
||||
|
||||
|
||||
class KeyDownloadView(SingleObjectDownloadView):
|
||||
model = Key
|
||||
object_permission = permission_key_download
|
||||
|
||||
def get_file(self):
|
||||
@@ -58,6 +61,9 @@ class KeyDownloadView(SingleObjectDownloadView):
|
||||
|
||||
return ContentFile(key.key_data, name=key.key_id)
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.all()
|
||||
|
||||
|
||||
class KeyReceive(ConfirmView):
|
||||
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
|
||||
@@ -71,7 +77,7 @@ class KeyReceive(ConfirmView):
|
||||
|
||||
def view_action(self):
|
||||
try:
|
||||
Key.objects.receive_key(key_id=self.kwargs['key_id'])
|
||||
Key.on_organization.receive_key(key_id=self.kwargs['key_id'])
|
||||
except Exception as exception:
|
||||
messages.error(
|
||||
self.request,
|
||||
@@ -122,14 +128,13 @@ class KeyQueryResultView(SingleObjectListView):
|
||||
def get_queryset(self):
|
||||
term = self.request.GET.get('term')
|
||||
if term:
|
||||
return Key.objects.search(query=term)
|
||||
return Key.on_organization.search(query=term)
|
||||
else:
|
||||
return ()
|
||||
|
||||
|
||||
class KeyUploadView(SingleObjectCreateView):
|
||||
fields = ('key_data',)
|
||||
model = Key
|
||||
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
|
||||
view_permission = permission_key_upload
|
||||
|
||||
@@ -138,10 +143,12 @@ class KeyUploadView(SingleObjectCreateView):
|
||||
'title': _('Upload new key'),
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.all()
|
||||
|
||||
|
||||
class PublicKeyListView(SingleObjectListView):
|
||||
object_permission = permission_key_view
|
||||
queryset = Key.objects.public_keys()
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
@@ -149,13 +156,18 @@ class PublicKeyListView(SingleObjectListView):
|
||||
'title': _('Public keys')
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.public_keys()
|
||||
|
||||
|
||||
class PrivateKeyListView(SingleObjectListView):
|
||||
object_permission = permission_key_view
|
||||
queryset = Key.objects.private_keys()
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'hide_object': True,
|
||||
'title': _('Private keys')
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
return Key.on_organization.private_keys()
|
||||
|
||||
Reference in New Issue
Block a user