Instead of inserting the path of the apps into the Python app, the apps are now referenced by their full import path. This solves name clashes with external or native Python libraries. Example: Mayan statistics app vs. Python new statistics library. Every app reference is now prepended with 'mayan.apps'. Existing config.yml files need to be updated manually. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
199 lines
6.5 KiB
Python
199 lines
6.5 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import io
|
|
|
|
import gnupg
|
|
import mock
|
|
|
|
from django.utils.encoding import force_bytes
|
|
|
|
from mayan.apps.common.tests import BaseTestCase
|
|
from mayan.apps.common.utils import TemporaryFile
|
|
|
|
from ..exceptions import (
|
|
DecryptionError, KeyDoesNotExist, NeedPassphrase, PassphraseError,
|
|
VerificationError
|
|
)
|
|
from ..models import Key
|
|
|
|
from .literals import (
|
|
TEST_DETACHED_SIGNATURE, TEST_FILE, TEST_KEY_DATA, TEST_KEY_FINGERPRINT,
|
|
TEST_KEY_PASSPHRASE, TEST_RECEIVE_KEY, TEST_SEARCH_FINGERPRINT,
|
|
TEST_SEARCH_UID, TEST_SIGNED_FILE, TEST_SIGNED_FILE_CONTENT
|
|
)
|
|
|
|
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):
|
|
class ImportResult(object):
|
|
count = 1
|
|
fingerprints = [TEST_SEARCH_FINGERPRINT]
|
|
|
|
self.import_keys(TEST_RECEIVE_KEY)
|
|
|
|
return ImportResult()
|
|
|
|
|
|
class KeyTestCase(BaseTestCase):
|
|
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)
|
|
|
|
self.assertEqual(key.fingerprint, TEST_KEY_FINGERPRINT)
|
|
|
|
@mock.patch.object(gnupg.GPG, 'search_keys', autospec=True)
|
|
def test_key_search(self, search_keys):
|
|
search_keys.return_value = MOCK_SEARCH_KEYS_RESPONSE
|
|
|
|
search_results = Key.objects.search(query=TEST_SEARCH_UID)
|
|
|
|
self.assertTrue(
|
|
TEST_SEARCH_FINGERPRINT in [
|
|
key_stub.fingerprint for key_stub in search_results
|
|
]
|
|
)
|
|
|
|
@mock.patch.object(gnupg.GPG, 'recv_keys', autospec=True)
|
|
def test_key_receive(self, recv_keys):
|
|
recv_keys.side_effect = mock_recv_keys
|
|
|
|
Key.objects.receive_key(key_id=TEST_SEARCH_FINGERPRINT)
|
|
|
|
self.assertEqual(Key.objects.all().count(), 1)
|
|
self.assertEqual(
|
|
Key.objects.first().fingerprint, TEST_SEARCH_FINGERPRINT
|
|
)
|
|
|
|
def test_cleartext_file_verification(self):
|
|
cleartext_file = TemporaryFile()
|
|
cleartext_file.write(b'test')
|
|
cleartext_file.seek(0)
|
|
|
|
with self.assertRaises(VerificationError):
|
|
Key.objects.verify_file(file_object=cleartext_file)
|
|
|
|
cleartext_file.close()
|
|
|
|
def test_embedded_verification_no_key(self):
|
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
|
result = Key.objects.verify_file(signed_file)
|
|
|
|
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
|
|
|
def test_embedded_verification_with_key(self):
|
|
Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
|
result = Key.objects.verify_file(signed_file)
|
|
|
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
|
|
|
def test_embedded_verification_with_correct_fingerprint(self):
|
|
Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
|
result = Key.objects.verify_file(
|
|
signed_file, key_fingerprint=TEST_KEY_FINGERPRINT
|
|
)
|
|
|
|
self.assertTrue(result.valid)
|
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
|
|
|
def test_embedded_verification_with_incorrect_fingerprint(self):
|
|
Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
|
with self.assertRaises(KeyDoesNotExist):
|
|
Key.objects.verify_file(signed_file, key_fingerprint='999')
|
|
|
|
def test_signed_file_decryption(self):
|
|
Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_SIGNED_FILE, mode='rb') as signed_file:
|
|
result = Key.objects.decrypt_file(file_object=signed_file)
|
|
|
|
self.assertEqual(result.read(), TEST_SIGNED_FILE_CONTENT)
|
|
|
|
def test_cleartext_file_decryption(self):
|
|
cleartext_file = TemporaryFile()
|
|
cleartext_file.write(b'test')
|
|
cleartext_file.seek(0)
|
|
|
|
with self.assertRaises(DecryptionError):
|
|
Key.objects.decrypt_file(file_object=cleartext_file)
|
|
|
|
cleartext_file.close()
|
|
|
|
def test_detached_verification_no_key(self):
|
|
with open(TEST_DETACHED_SIGNATURE, mode='rb') as signature_file:
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
result = Key.objects.verify_file(
|
|
file_object=test_file, signature_file=signature_file
|
|
)
|
|
|
|
self.assertTrue(result.key_id in TEST_KEY_FINGERPRINT)
|
|
|
|
def test_detached_verification_with_key(self):
|
|
Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_DETACHED_SIGNATURE, mode='rb') as signature_file:
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
result = Key.objects.verify_file(
|
|
file_object=test_file, signature_file=signature_file
|
|
)
|
|
|
|
self.assertTrue(result)
|
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|
|
|
|
def test_detached_signing_no_passphrase(self):
|
|
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with self.assertRaises(NeedPassphrase):
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
key.sign_file(
|
|
file_object=test_file, detached=True,
|
|
)
|
|
|
|
def test_detached_signing_bad_passphrase(self):
|
|
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with self.assertRaises(PassphraseError):
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
key.sign_file(
|
|
file_object=test_file, detached=True,
|
|
passphrase='bad passphrase'
|
|
)
|
|
|
|
def test_detached_signing_with_passphrase(self):
|
|
key = Key.objects.create(key_data=TEST_KEY_DATA)
|
|
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
detached_signature = key.sign_file(
|
|
file_object=test_file, detached=True,
|
|
passphrase=TEST_KEY_PASSPHRASE
|
|
)
|
|
|
|
signature_file = io.BytesIO()
|
|
signature_file.write(force_bytes(detached_signature))
|
|
signature_file.seek(0)
|
|
|
|
with open(TEST_FILE, mode='rb') as test_file:
|
|
result = Key.objects.verify_file(
|
|
file_object=test_file, signature_file=signature_file
|
|
)
|
|
|
|
signature_file.close()
|
|
self.assertTrue(result)
|
|
self.assertEqual(result.fingerprint, TEST_KEY_FINGERPRINT)
|