summaryrefslogtreecommitdiff
path: root/alot/commands/utils.py
blob: 8f76d7566263c225d5df8759c3da680b8fb6c02f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# Copyright (C) 2015  Patrick Totzke <patricktotzke@gmail.com>
# 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