# Copyright (C) 2015 Patrick Totzke # This file is released under the GNU GPL, version 3 or a later revision. # For further details see the COPYING file import logging import re from .. import crypto from ..errors import GPGProblem, GPGCode from ..settings.const import settings from ..settings.errors import NoMatchingAccount async def update_keys(ui, envelope, block_error=False, signed_only=False): """Find and set the encryption keys in an envolope. :param ui: the main user interface object :type ui: alot.ui.UI :param envolope: the envolope buffer object :type envolope: alot.buffers.EnvelopeBuffer :param block_error: wether error messages for the user should expire automatically or block the ui :type block_error: bool :param signed_only: only use keys whose uid is signed (trusted to belong to the key) :type signed_only: bool """ encrypt_keys = [] for header in ('To', 'Cc'): if header not in envelope.headers: continue for recipient in envelope.headers[header][0].split(','): if not recipient: continue match = re.search("<(.*@.*)>", recipient) if match: recipient = match.group(1) encrypt_keys.append(recipient) logging.debug("encryption keys: " + str(encrypt_keys)) keys = await _get_keys(ui, encrypt_keys, block_error=block_error, signed_only=signed_only) if keys: envelope.encrypt_keys = keys envelope.encrypt = True if 'From' in envelope.headers: try: if envelope.account is None: envelope.account = settings.account_matching_address( envelope['From']) acc = envelope.account if acc.encrypt_to_self: if acc.gpg_key: logging.debug('encrypt to self: %s', acc.gpg_key.fpr) envelope.encrypt_keys[acc.gpg_key.fpr] = acc.gpg_key else: logging.debug('encrypt to self: no gpg_key in account') except NoMatchingAccount: logging.debug('encrypt to self: no account found') else: envelope.encrypt = False async def _get_keys(ui, encrypt_keyids, block_error=False, signed_only=False): """Get several keys from the GPG keyring. The keys are selected by keyid and are checked if they can be used for encryption. :param ui: the main user interface object :type ui: alot.ui.UI :param encrypt_keyids: the key ids of the keys to get :type encrypt_keyids: list(str) :param block_error: wether error messages for the user should expire automatically or block the ui :type block_error: bool :param signed_only: only return keys whose uid is signed (trusted to belong to the key) :type signed_only: bool :returns: the available keys indexed by their OpenPGP fingerprint :rtype: dict(str->gpg key object) """ keys = {} for keyid in encrypt_keyids: try: key = crypto.get_key(keyid, validate=True, encrypt=True, signed_only=signed_only) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: tmp_choices = ['{} ({})'.format(k.uids[0].uid, k.fpr) for k in crypto.list_keys(hint=keyid)] choices = {str(i): t for i, t in enumerate(tmp_choices, 1)} keys_to_return = {str(i): t for i, t in enumerate([k for k in crypto.list_keys(hint=keyid)], 1)} choosen_key = await ui.choice("ambiguous keyid! Which " + "key do you want to use?", choices=choices, choices_to_return=keys_to_return) if choosen_key: keys[choosen_key.fpr] = choosen_key continue else: ui.notify(str(e), priority='error', block=block_error) continue keys[key.fpr] = key return keys