예제 #1
0
    def TransformOutgoing(self, sender, rcpts, msg, **kwargs):
        matched = False
        keydata = mutual = sender_keyid = key_binary = None

        gnupg = GnuPG(self.config, event=GetThreadEvent())
        profile = self._get_sender_profile(sender, kwargs)
        vcard = profile['vcard']
        if vcard is not None:
            crypto_format = vcard.crypto_format
            sender_keyid = vcard.pgp_key
            if sender_keyid and 'autocrypt' in crypto_format:
                key_binary = gnupg.get_minimal_key(key_id=sender_keyid,
                                                   user_id=sender)

            if key_binary:
                mutual = 'E' in crypto_format.split('+')[0].split(':')[-1]
                msg["Autocrypt"] = make_autocrypt_header(
                    sender, key_binary, prefer_encrypt_mutual=mutual)

                if 'encrypt' in msg.get('Encryption', '').lower():
                    gossip_list = []
                    for rcpt in rcpts:
                        # FIXME: Check if any of the recipients are in the BCC
                        #        header; omit their keys if so?
                        try:
                            # This *should* always succeed: if we are encrypting,
                            # then the key we encrypt to should already be in
                            # the keychain.
                            if '#' in rcpt:
                                rcpt, rcpt_keyid = rcpt.split('#')
                            else:
                                # This happens when composing in the CLI.
                                rcpt_keyid = rcpt
                            if (rcpt != sender) and rcpt_keyid:
                                kb = gnupg.get_minimal_key(key_id=rcpt_keyid,
                                                           user_id=rcpt)
                                if kb:
                                    gossip_list.append(
                                        make_autocrypt_header(
                                            rcpt,
                                            kb,
                                            prefix='Autocrypt-Gossip'))
                        except (ValueError, IndexError):
                            pass
                    if len(gossip_list) > 1:
                        # No point gossiping peoples keys back to them alone.
                        for hdr in gossip_list:
                            msg.add_header('Autocrypt-Gossip', hdr)

                matched = True

        return sender, rcpts, msg, matched, True
예제 #2
0
    def get_vcards(self,
                   selectors=None,
                   public=True,
                   secret=True,
                   vcards=None,
                   event=None):
        if not self.config.active:
            return []

        # Event magic
        event = event or GetThreadEvent()

        # Generate all the nice new cards!
        new_cards = self.gnupg_keys_as_vcards(GnuPG(self.session.config,
                                                    event=event),
                                              selectors=selectors,
                                              public=public,
                                              secret=secret)

        # Generate tombstones for keys which are gone from the keyring.
        if vcards:
            deleted = set()
            deleted_names = {}
            search = ';%s/' % self.config.guid
            for cardid, vcard in (vcards or {}).iteritems():
                for vcl in vcard.get_all('clientpidmap'):
                    if search in vcl.value:
                        key_id = vcl.value.split(';')[1]
                        deleted.add(key_id)
                        deleted_names[key_id] = vcard.fn
            if selectors:
                deleted = set([
                    guid for guid in deleted
                    if guid.split('/')[-1] in selectors
                ])
            deleted -= set([self.get_guid(card) for card in new_cards])
            for guid in deleted:
                mrgid = guid.split('/')[-1]
                fn = deleted_names[guid]
                new_cards.append(
                    MailpileVCard(VCardLine(name='fn', value=fn),
                                  VCardLine(name='x-gpg-mrgid', value=mrgid)))

        return new_cards
예제 #3
0
    def TransformOutgoing(self, sender, rcpts, msg, **kwargs):
        matched = False
        gnupg = None
        sender_keyid = None

        # Prefer to just get everything from the profile VCard, in the
        # common case...
        profile = self.config.vcards.get_vcard(sender)
        if profile:
            sender_keyid = profile.pgp_key
            crypto_format = profile.crypto_format or 'none'
        else:
            crypto_format = 'none'

        # Parse the openpgp_header data from the crypto_format
        openpgp_header = [
            p.split(':')[-1] for p in crypto_format.split('+')
            if p.startswith('openpgp_header:')
        ]
        if not openpgp_header:
            openpgp_header = self.config.prefs.openpgp_header and ['CFG']

        if openpgp_header[0] != 'N' and not sender_keyid:
            # This is a fallback: this shouldn't happen much in normal use
            try:
                gnupg = gnupg or GnuPG(self.config, event=GetThreadEvent())
                seckeys = dict([
                    (uid["email"], fp)
                    for fp, key in gnupg.list_secret_keys().iteritems()
                    if key["capabilities_map"].get("encrypt")
                    and key["capabilities_map"].get("sign")
                    for uid in key["uids"]
                ])
                sender_keyid = seckeys.get(sender)
            except (KeyError, TypeError, IndexError, ValueError):
                traceback.print_exc()

        if sender_keyid and openpgp_header:
            preference = {
                'ES': 'signencrypt',
                'SE': 'signencrypt',
                'E': 'encrypt',
                'S': 'sign',
                'N': 'unprotected',
                'CFG': self.config.prefs.openpgp_header
            }[openpgp_header[0].upper()]
            msg["OpenPGP"] = ("id=%s; preference=%s" %
                              (sender_keyid, preference))

        if ('attach-pgp-pubkey' in msg
                and msg['attach-pgp-pubkey'][:3].lower() in ('yes', 'tru')):
            gnupg = gnupg or GnuPG(self.config, event=GetThreadEvent())
            if sender_keyid:
                keys = gnupg.list_keys(selectors=[sender_keyid])
            else:
                keys = gnupg.address_to_keys(ExtractEmails(sender)[0])

            key_count = 0
            for fp, key in keys.iteritems():
                if not any(key["capabilities_map"].values()):
                    continue
                # We should never really hit this more than once. But if we
                # do, should still be fine.
                keyid = key["keyid"]
                data = gnupg.get_pubkey(keyid)

                try:
                    from_name = key["uids"][0]["name"]
                    filename = _('Encryption key for %s.asc') % from_name
                except:
                    filename = _('My encryption key.asc')
                att = MIMEBase('application', 'pgp-keys')
                att.set_payload(data)
                encoders.encode_base64(att)
                del att['MIME-Version']
                att.add_header('Content-Id', MakeContentID())
                att.add_header('Content-Disposition',
                               'attachment',
                               filename=filename)
                att.signature_info = SignatureInfo(parent=msg.signature_info)
                att.encryption_info = EncryptionInfo(
                    parent=msg.encryption_info)
                msg.attach(att)
                key_count += 1

            if key_count > 0:
                msg['x-mp-internal-pubkeys-attached'] = "Yes"

        return sender, rcpts, msg, matched, True