Files
mayan-edms/mayan/apps/django_gpg/managers.py
2016-06-24 04:22:49 -04:00

201 lines
6.9 KiB
Python

from __future__ import absolute_import, unicode_literals
import io
import logging
import os
import shutil
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 (
DecryptionError, KeyDoesNotExist, KeyFetchingError, VerificationError
)
from .literals import KEY_TYPE_PUBLIC, KEY_TYPE_SECRET
from .settings import setting_gpg_path, setting_keyserver
logger = logging.getLogger(__name__)
class KeyManager(models.Manager):
def decrypt_file(self, file_object, all_keys=False, key_fingerprint=None, key_id=None):
temporary_directory = mkdtemp()
os.chmod(temporary_directory, 0x1C0)
gpg = gnupg.GPG(
gnupghome=temporary_directory, gpgbinary=setting_gpg_path.value
)
# Preload keys
if all_keys:
logger.debug('preloading all keys')
for key in self.all():
gpg.import_keys(key_data=key.key_data)
elif key_fingerprint:
logger.debug('preloading key fingerprint: %s', key_fingerprint)
try:
key = self.get(fingerprint=key_fingerprint)
except self.model.DoesNotExist:
logger.debug('key fingerprint %s not found', key_fingerprint)
shutil.rmtree(temporary_directory)
raise KeyDoesNotExist(
'Specified key for verification not found'
)
else:
gpg.import_keys(key_data=key.key_data)
elif key_id:
logger.debug('preloading key id: %s', key_id)
try:
key = self.get(fingerprint__endswith=key_id)
except self.model.DoesNotExist:
logger.debug('key id %s not found', key_id)
else:
gpg.import_keys(key_data=key.key_data)
logger.debug('key id %s impored', key_id)
decrypt_result = gpg.decrypt_file(file=file_object)
shutil.rmtree(temporary_directory)
logger.debug('decrypt_result.status: %s', decrypt_result.status)
if not decrypt_result.status or decrypt_result.status == 'no data was provided':
raise DecryptionError('Unable to decrypt file')
file_object.close()
return io.BytesIO(decrypt_result.data)
def receive_key(self, key_id):
temporary_directory = mkdtemp()
os.chmod(temporary_directory, 0x1C0)
gpg = gnupg.GPG(
gnupghome=temporary_directory, gpgbinary=setting_gpg_path.value
)
import_results = gpg.recv_keys(setting_keyserver.value, key_id)
if not import_results.count:
shutil.rmtree(temporary_directory)
raise KeyFetchingError('No key found')
else:
key_data = gpg.export_keys(import_results.fingerprints[0])
shutil.rmtree(temporary_directory)
return self.create(key_data=key_data)
def search(self, query):
temporary_directory = mkdtemp()
os.chmod(temporary_directory, 0x1C0)
gpg = gnupg.GPG(
gnupghome=temporary_directory, gpgbinary=setting_gpg_path.value
)
key_data_list = gpg.search_keys(
query=query, keyserver=setting_keyserver.value
)
shutil.rmtree(temporary_directory)
result = []
for key_data in key_data_list:
result.append(KeyStub(raw=key_data))
return result
def public_keys(self):
return self.filter(key_type=KEY_TYPE_PUBLIC)
def private_keys(self):
return self.filter(key_type=KEY_TYPE_SECRET)
def verify_file(self, file_object, signature_file=None, all_keys=False, key_fingerprint=None, key_id=None):
temporary_directory = mkdtemp()
os.chmod(temporary_directory, 0x1C0)
gpg = gnupg.GPG(
gnupghome=temporary_directory, gpgbinary=setting_gpg_path.value
)
# Preload keys
if all_keys:
logger.debug('preloading all keys')
for key in self.all():
gpg.import_keys(key_data=key.key_data)
elif key_fingerprint:
logger.debug('preloading key fingerprint: %s', key_fingerprint)
try:
key = self.get(fingerprint=key_fingerprint)
except self.model.DoesNotExist:
logger.debug('key fingerprint %s not found', key_fingerprint)
shutil.rmtree(temporary_directory)
raise KeyDoesNotExist(
'Specified key for verification not found'
)
else:
gpg.import_keys(key_data=key.key_data)
elif key_id:
logger.debug('preloading key id: %s', key_id)
try:
key = self.get(fingerprint__endswith=key_id)
except self.model.DoesNotExist:
logger.debug('key id %s not found', key_id)
else:
gpg.import_keys(key_data=key.key_data)
logger.debug('key id %s impored', key_id)
if signature_file:
# Save the original data and invert the argument order
# Signature first, file second
temporary_file_object, temporary_filename = mkstemp()
os.write(temporary_file_object, file_object.read())
os.close(temporary_file_object)
signature_file_buffer = io.BytesIO()
signature_file_buffer.write(signature_file.read())
signature_file_buffer.seek(0)
signature_file.seek(0)
verify_result = gpg.verify_file(
file=signature_file_buffer, data_filename=temporary_filename
)
signature_file_buffer.close()
os.unlink(temporary_filename)
else:
verify_result = gpg.verify_file(file=file_object)
logger.debug('verify_result.status: %s', verify_result.status)
shutil.rmtree(temporary_directory)
if verify_result:
# Signed and key present
logger.debug('signed and key present')
return SignatureVerification(verify_result.__dict__)
elif verify_result.status == 'no public key' and not (key_fingerprint or all_keys or key_id):
# Signed but key not present, retry with key fetch
logger.debug('no public key')
file_object.seek(0)
return self.verify_file(file_object=file_object, signature_file=signature_file, key_id=verify_result.key_id)
elif verify_result.key_id:
# Signed, retried and key still not found
logger.debug('signed, retried and key still not found')
return SignatureVerification(verify_result.__dict__)
else:
logger.debug('file not signed')
raise VerificationError('File not signed')
class OrganizationKeyManager(KeyManager, CurrentOrganizationManager):
pass