Skip to content
Snippets Groups Projects
Commit 77e4e1d0 authored by Tomás Touceda's avatar Tomás Touceda
Browse files

Merge branch 'release-0.3.7'

parents ae80ea1f 48751fa1
No related branches found
Tags 0.3.7
No related merge requests found
0.3.7 Dec 6:
o Fix error return values on openpgp backend.
o Remove address check when sending email and rely in the email
client to verify that is correct. Closes #4491.
o Support sending encrypted mails to addresses using the '+' sign.
o Improve exception names and handling.
0.3.6 Nov 15:
o Default encoding to 'utf-8' in case of system encodings not
set. Closes #4427.
......
......@@ -425,6 +425,9 @@ class KeyManager(object):
:type data: str
:param privkey: The key used to decrypt.
:type privkey: OpenPGPKey
:param passphrase: The passphrase for the secret key used for
decryption.
:type passphrase: str
:param verify: The key used to verify a signature.
:type verify: OpenPGPKey
......
......@@ -58,21 +58,21 @@ class InvalidSignature(Exception):
pass
class EncryptionFailed(Exception):
class EncryptError(Exception):
"""
Raised upon failures of encryption.
"""
pass
class DecryptionFailed(Exception):
class DecryptError(Exception):
"""
Raised upon failures of decryption.
"""
pass
class EncryptionDecryptionFailed(Exception):
class GPGError(Exception):
"""
Raised upon failures of encryption/decryption.
"""
......
......@@ -297,7 +297,11 @@ class OpenPGPScheme(EncryptionScheme):
:rtype: OpenPGPKey
@raise KeyNotFound: If the key was not found on local storage.
"""
leap_assert(is_address(address), 'Not an user address: %s' % address)
# Remove the identity suffix after the '+' until the '@'
# e.g.: test_user+something@provider.com becomes test_user@probider.com
# since the key belongs to the identity without the '+' suffix.
address = re.sub(r'\+.*\@', '@', address)
doc = self._get_key_doc(address, private)
if doc is None:
raise errors.KeyNotFound(address)
......@@ -337,6 +341,7 @@ class OpenPGPScheme(EncryptionScheme):
leap_assert(match is not None, 'No user address in key data.')
address = match.group(1)
openpgp_privkey = None
if privkey is not None:
match = re.match(mail_regex, privkey['uids'].pop())
leap_assert(match is not None, 'No user address in key data.')
......@@ -370,6 +375,7 @@ class OpenPGPScheme(EncryptionScheme):
"""
leap_assert_type(key_data, (str, unicode))
openpgp_privkey = None
try:
openpgp_pubkey, openpgp_privkey = self.parse_ascii_key(key_data)
except (errors.KeyAddressMismatch, errors.KeyFingerprintMismatch) as e:
......@@ -465,14 +471,18 @@ class OpenPGPScheme(EncryptionScheme):
def _assert_gpg_result_ok(result):
"""
Check if GPG result is 'ok' and log stderr outputs.
:param result: The GPG results
:type result:
:param result: GPG results, which have a field calld 'ok' that states
whether the gpg operation was successful or not.
:type result: object
:raise GPGError: Raised when the gpg operation was not successful.
"""
stderr = getattr(result, 'stderr', None)
if stderr:
logger.debug("%s" % (stderr,))
if getattr(result, 'ok', None) is not True:
raise errors.EncryptionDecryptionFailed(
raise errors.GPGError(
'Failed to encrypt/decrypt: %s' % stderr)
def encrypt(self, data, pubkey, passphrase=None, sign=None,
......@@ -491,6 +501,8 @@ class OpenPGPScheme(EncryptionScheme):
:return: The encrypted data.
:rtype: str
:raise EncryptError: Raised if failed encrypting for some reason.
"""
leap_assert_type(pubkey, OpenPGPKey)
leap_assert(pubkey.private is False, 'Key is not public.')
......@@ -509,8 +521,12 @@ class OpenPGPScheme(EncryptionScheme):
# in the ciphertext.
# result.ok - (bool) indicates if the operation succeeded
# result.data - (bool) contains the result of the operation
try:
self._assert_gpg_result_ok(result)
return result.data
except errors.GPGError as e:
logger.error('Failed to decrypt: %s.' % str(e))
raise error.EncryptError()
def decrypt(self, data, privkey, passphrase=None, verify=None):
"""
......@@ -520,13 +536,17 @@ class OpenPGPScheme(EncryptionScheme):
:type data: str
:param privkey: The key used to decrypt.
:type privkey: OpenPGPKey
:param passphrase: The passphrase for the secret key used for
decryption.
:type passphrase: str
:param verify: The key used to verify a signature.
:type verify: OpenPGPKey
:return: The decrypted data.
:rtype: unicode
@raise InvalidSignature: Raised if unable to verify the signature with
:raise DecryptError: Raised if failed decrypting for some reason.
:raise InvalidSignature: Raised if unable to verify the signature with
C{verify} key.
"""
leap_assert(privkey.private is True, 'Key is not private.')
......@@ -536,6 +556,7 @@ class OpenPGPScheme(EncryptionScheme):
leap_assert(verify.private is False)
keys.append(verify)
with self._temporary_gpgwrapper(keys) as gpg:
try:
result = gpg.decrypt(
data, passphrase=passphrase, always_trust=True)
self._assert_gpg_result_ok(result)
......@@ -545,7 +566,7 @@ class OpenPGPScheme(EncryptionScheme):
verify.fingerprint != result.pubkey_fingerprint:
raise errors.InvalidSignature(
'Failed to verify signature with key %s: %s' %
(verify.key_id, stderr))
(verify.key_id, result.stderr))
# XXX: this is the encoding used by gpg module
# https://github.com/isislovecruft/python-gnupg/\
......@@ -556,6 +577,10 @@ class OpenPGPScheme(EncryptionScheme):
if encoding is None:
encoding = 'utf-8'
return result.data.decode(encoding, 'replace')
except errors.GPGError as e:
logger.error('Failed to decrypt: %s.' % str(e))
raise errors.DecryptError(str(e))
def is_encrypted(self, data):
"""
......@@ -608,7 +633,7 @@ class OpenPGPScheme(EncryptionScheme):
if result.fingerprint is None:
raise errors.SignFailed(
'Failed to sign with key %s: %s' %
(privkey['keyid'], stderr))
(privkey['keyid'], result.stderr))
leap_assert(
result.fingerprint == kfprint,
'Signature and private key fingerprints mismatch: '
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment