Esempio n. 1
0
    def command(self):
        signingkey = None
        keyid = None
        args = list(self.args)
        try:
            keyid = args.pop(0)
        except:
            keyid = self.data.get("keyid", None)
        try:
            signingkey = args.pop(0)
        except:
            signingkey = self.data.get("signingkey", None)

        print keyid
        if not keyid:
            return self._error("You must supply a keyid", None)

        g = GnuPG()
        return g.sign_key(keyid, signingkey)
Esempio n. 2
0
def VerifyAndStorePassphrase(config, passphrase=None, sps=None, key=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert (sps is not None)

    # Note: Must use GnuPG without a config, otherwise bad things happen.
    gpg = GnuPG(None, use_agent=False, debug=('gnupg' in config.sys.debug))
    if gpg.is_available():
        gpg.passphrase = sps.get_reader()
        gpgr = config.prefs.gpg_recipient
        gpgr = key or (gpgr if (gpgr not in (None, '', '!CREATE')) else None)
        assert (gpg.sign('Sign This!', fromkey=gpgr)[0] == 0)

    # Fun side effect: changing the passphrase invalidates the message cache
    import mailpile.mailutils
    mailpile.mailutils.ClearParseCache(full=True)

    return sps
Esempio n. 3
0
    def command(self):
        if self.session.config.sys.lockdown:
            return self._error(_('In lockdown, doing nothing.'))

        signingkey = None
        keyid = None
        args = list(self.args)
        try:
            keyid = args.pop(0)
        except:
            keyid = self.data.get("keyid", None)
        try:
            signingkey = args.pop(0)
        except:
            signingkey = self.data.get("signingkey", None)

        print keyid
        if not keyid:
            return self._error("You must supply a keyid", None)

        g = GnuPG()
        return g.sign_key(keyid, signingkey)
Esempio n. 4
0
    def get_vcards(self,
                   selectors=None,
                   public=True,
                   secret=True,
                   vcards=None):
        if not self.config.active:
            return []

        # Generate all the nice new cards!
        new_cards = self.gnupg_keys_as_vcards(GnuPG(self.session.config),
                                              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
Esempio n. 5
0
    def command(self):
        session, config, idx = self.session, self.session.config, self._idx()
        args = list(self.args)
        if args and args[-1][0] == "#":
            attid = args.pop()
        else:
            attid = self.data.get("att", 'application/pgp-keys')
        args.extend(["=%s" % x for x in self.data.get("mid", [])])
        eids = self._choose_messages(args)
        if len(eids) < 0:
            return self._error("No messages selected", None)
        elif len(eids) > 1:
            return self._error("One message at a time, please", None)

        email = Email(idx, list(eids)[0])
        fn, attr = email.extract_attachment(session, attid, mode='inline')
        if attr and attr["data"]:
            g = GnuPG()
            res = g.import_keys(attr["data"])
            return self._success("Imported key", res)

        return self._error("No results found", None)
Esempio n. 6
0
    def get_vcards(self):
        if not self.config.active:
            return []

        gnupg = GnuPG(self.session.config)
        keys = gnupg.list_keys()

        results = []
        vcards = {}
        for key_id, key in keys.iteritems():
            if (key.get("disabled") or key.get("revoked")
                    or not key["capabilities_map"].get("encrypt")
                    or not key["capabilities_map"].get("sign")):
                continue
            vcls = [VCardLine(name='KEY', value=self.VCL_KEY_FMT % key_id)]
            card = None
            emails = []
            for uid in key.get('uids', []):
                if uid.get('email'):
                    vcls.append(VCardLine(name='email', value=uid['email']))
                    card = card or vcards.get(uid['email'])
                    emails.append(uid['email'])
                if uid.get('name'):
                    name = uid['name']
                    vcls.append(VCardLine(name='fn', value=name))
            if card and emails:
                card.add(*vcls)
            elif emails:
                # This is us taking care to only create one card for each
                # set of e-mail addresses.
                card = MailpileVCard(*vcls)
                for email in emails:
                    vcards[email] = card
                results.append(card)

        return results
Esempio n. 7
0
def PrepareMessage(config, msg, sender=None, rcpts=None, events=None):
    msg = copy.deepcopy(msg)

    # Short circuit if this message has already been prepared.
    if 'x-mp-internal-sender' in msg and 'x-mp-internal-rcpts' in msg:
        return (sender or msg['x-mp-internal-sender'], rcpts
                or [r.strip() for r in msg['x-mp-internal-rcpts'].split(',')],
                msg, events)

    crypto_policy = config.prefs.crypto_policy.lower()
    rcpts = rcpts or []

    # Iterate through headers to figure out what we want to do...
    need_rcpts = not rcpts
    for hdr, val in msg.items():
        lhdr = hdr.lower()
        if lhdr == 'from':
            sender = sender or val
        elif lhdr == 'encryption':
            crypto_policy = val.lower()
        elif need_rcpts and lhdr in ('to', 'cc', 'bcc'):
            rcpts += ExtractEmails(val, strip_keys=False)

    # Are we sane?
    if not sender:
        raise NoFromAddressError()
    if not rcpts:
        raise NoRecipientError()

    # Are we encrypting? Signing?
    if crypto_policy == 'default':
        crypto_policy = config.prefs.crypto_policy

    # This is the BCC hack that Brennan hates!
    rcpts += [sender]

    sender = ExtractEmails(sender, strip_keys=False)[0]
    sender_keyid = None
    if config.prefs.openpgp_header:
        try:
            gnupg = GnuPG()
            seckeys = dict([(x["email"], y["fingerprint"])
                            for y in gnupg.list_secret_keys().values()
                            for x in y["uids"]])
            sender_keyid = seckeys[sender]
        except:
            pass

    rcpts, rr = [sender], rcpts
    for r in rr:
        for e in ExtractEmails(r, strip_keys=False):
            if e not in rcpts:
                rcpts.append(e)

    # Add headers we require
    if 'date' not in msg:
        msg['Date'] = email.utils.formatdate()

    if sender_keyid and config.prefs.openpgp_header:
        msg["OpenPGP"] = "id=%s; preference=%s" % (sender_keyid,
                                                   config.prefs.openpgp_header)

    if 'openpgp' in crypto_policy:

        # FIXME: Make a more efficient sign+encrypt wrapper

        cleaner = lambda m: CleanMessage(config, m)
        if 'sign' in crypto_policy:
            msg = OpenPGPMimeSigningWrapper(config,
                                            sender=sender,
                                            cleaner=cleaner,
                                            recipients=rcpts).wrap(msg)
        if 'encrypt' in crypto_policy:
            msg = OpenPGPMimeEncryptingWrapper(config,
                                               sender=sender,
                                               cleaner=cleaner,
                                               recipients=rcpts).wrap(msg)

    rcpts = set([r.rsplit('#', 1)[0] for r in rcpts])
    msg['x-mp-internal-readonly'] = str(int(time.time()))
    msg['x-mp-internal-sender'] = sender
    msg['x-mp-internal-rcpts'] = ', '.join(rcpts)
    return (sender, rcpts, msg, events)
Esempio n. 8
0
    def evaluate_pgp(self, tree, check_sigs=True, decrypt=False):
        if 'text_parts' not in tree:
            return tree

        pgpdata = []
        for part in tree['text_parts']:
            if 'crypto' not in part:
                part['crypto'] = {}

            ei = si = None
            if check_sigs:
                if part['type'] == 'pgpbeginsigned':
                    pgpdata = [part]
                elif part['type'] == 'pgpsignedtext':
                    pgpdata.append(part)
                elif part['type'] == 'pgpsignature':
                    pgpdata.append(part)
                    try:
                        gpg = GnuPG()
                        message = ''.join(
                            [p['data'].encode(p['charset']) for p in pgpdata])
                        si = pgpdata[1]['crypto']['signature'] = gpg.verify(
                            message)
                        pgpdata[0]['data'] = ''
                        pgpdata[2]['data'] = ''

                    except Exception, e:
                        print e

            if decrypt:
                if part['type'] in ('pgpbegin', 'pgptext'):
                    pgpdata.append(part)
                elif part['type'] == 'pgpend':
                    pgpdata.append(part)

                    gpg = GnuPG()
                    (signature_info, encryption_info,
                     text) = gpg.decrypt(''.join([p['data'] for p in pgpdata]))

                    # FIXME: If the data is binary, we should provide some
                    #        sort of download link or maybe leave the PGP
                    #        blob entirely intact, undecoded.
                    text, charset = self.decode_text(text, binary=False)

                    ei = pgpdata[1]['crypto']['encryption'] = encryption_info
                    si = pgpdata[1]['crypto']['signature'] = signature_info
                    if encryption_info["status"] == "decrypted":
                        pgpdata[1]['data'] = text
                        pgpdata[0]['data'] = ""
                        pgpdata[2]['data'] = ""

            # Bubbling up!
            if (si or ei) and 'crypto' not in tree:
                tree['crypto'] = {
                    'signature': SignatureInfo(),
                    'encryption': EncryptionInfo()
                }
            if si:
                tree['crypto']['signature'].mix(si)
            if ei:
                tree['crypto']['encryption'].mix(ei)
Esempio n. 9
0
    def setup_command(self, session, do_gpg_stuff=False):
        do_gpg_stuff = do_gpg_stuff or ('do_gpg_stuff' in self.args)

        # Stop the workers...
        want_daemons = session.config.cron_worker is not None
        session.config.stop_workers()

        # Perform any required migrations
        Migrate(session).run(before_setup=True, after_setup=False)

        # Basic app config, tags, plugins, etc.
        self.basic_app_config(session,
                              save_and_update_workers=False,
                              want_daemons=want_daemons)

        # Assumption: If you already have secret keys, you want to
        #             use the associated addresses for your e-mail.
        #             If you don't already have secret keys, you should have
        #             one made for you, if GnuPG is available.
        #             If GnuPG is not available, you should be warned.
        if do_gpg_stuff:
            gnupg = GnuPG(None)
            accepted_keys = []
            if gnupg.is_available():
                keys = gnupg.list_secret_keys()
                for key, details in keys.iteritems():
                    # Ignore revoked/expired keys.
                    if ("revocation-date" in details and
                        details["revocation-date"] <=
                            date.today().strftime("%Y-%m-%d")):
                        continue

                    accepted_keys.append(key)
                    for uid in details["uids"]:
                        if "email" not in uid or uid["email"] == "":
                            continue

                        if uid["email"] in [x["email"]
                                            for x in session.config.profiles]:
                            # Don't set up the same e-mail address twice.
                            continue

                        # FIXME: Add route discovery mechanism.
                        profile = {
                            "email": uid["email"],
                            "name": uid["name"],
                        }
                        session.config.profiles.append(profile)
                    if (session.config.prefs.gpg_recipient in (None, '', '!CREATE')
                           and details["capabilities_map"][0]["encrypt"]):
                        session.config.prefs.gpg_recipient = key
                        session.ui.notify(_('Encrypting config to %s') % key)
                    if session.config.prefs.crypto_policy == 'none':
                        session.config.prefs.crypto_policy = 'openpgp-sign'

                if len(accepted_keys) == 0:
                    # FIXME: Start background process generating a key once a user
                    #        has supplied a name and e-mail address.
                    pass

            else:
                session.ui.warning(_('Oh no, PGP/GPG support is unavailable!'))

        # If we have a GPG key, but no master key, create it
        self.make_master_key()

        # Perform any required migrations
        Migrate(session).run(before_setup=False, after_setup=True)

        session.config.save()
        session.config.prepare_workers(session, daemons=want_daemons)

        return self._success(_('Performed initial Mailpile setup'))
Esempio n. 10
0
 def _gnupg(self):
     return GnuPG(self.session and self.session.config or None)
Esempio n. 11
0
 def _gnupg(self):
     return GnuPG(self.session.config, event=self.event)
Esempio n. 12
0
 def command(self):
     keyid = self.data.get("keyid", self.args[0])
     g = GnuPG()
     return g.recv_key(keyid)
Esempio n. 13
0
def lookup_crypto_keys(session,
                       address,
                       event=None,
                       strict_email_match=False,
                       allowremote=True,
                       origins=None,
                       get=None):
    known_keys_list = GnuPG(session and session.config or None).list_keys()
    found_keys = {}
    ordered_keys = []

    if origins:
        handlers = [
            h for h in KEY_LOOKUP_HANDLERS
            if (h.NAME in origins) or (h.NAME.lower() in origins)
        ]
    else:
        handlers = KEY_LOOKUP_HANDLERS

    ungotten = get and get[:] or []
    progress = []

    for handler in handlers:
        if get and not ungotten:
            # We have all the keys!
            break

        try:
            h = handler(session, known_keys_list)
            if not allowremote and not h.LOCAL:
                continue

            if found_keys and (not h.PRIVACY_FRIENDLY) and (not origins):
                # We only try the privacy-hostile methods if we haven't
                # found any keys (unless origins were specified).
                if not ungotten:
                    continue

            progress.append(h.NAME)
            if event:
                ordered_keys.sort(key=lambda k: -k["score"])
                event.message = _('Searching for encryption keys in: %s') % _(
                    h.NAME)
                event.private_data = {
                    "result": ordered_keys,
                    "progress": progress,
                    "runningsearch": h.NAME
                }
                session.config.event_log.log_event(event)

            # We allow for more time when importing keys
            timeout = h.TIMEOUT
            if ungotten:
                timeout *= 4

            # h.lookup will remove found keys from the wanted list,
            # but we have to watch out for the effects of timeouts.
            wanted = ungotten[:]
            results = RunTimed(timeout,
                               h.lookup,
                               address,
                               strict_email_match=strict_email_match,
                               get=(wanted if (get is not None) else None))
            ungotten[:] = wanted
        except KeyboardInterrupt:
            raise
        except:
            if session.config.sys.debug:
                traceback.print_exc()
            results = {}

        for key_id, key_info in results.iteritems():
            if key_id in found_keys:
                old_scores = found_keys[key_id].get('scores', {})
                old_uids = found_keys[key_id].get('uids', [])[:]
                found_keys[key_id].update(key_info)
                if 'scores' in found_keys[key_id]:
                    found_keys[key_id]['scores'].update(old_scores)
                    # No need for an else, as old_scores will be empty

                # Merge in the old UIDs
                uid_emails = [u['email'] for u in key_info.get('uids', [])]
                if 'uids' not in found_keys[key_id]:
                    found_keys[key_id]['uids'] = []
                for uid in old_uids:
                    email = uid.get('email')
                    if email and email not in uid_emails:
                        found_keys[key_id]['uids'].append(uid)
            else:
                found_keys[key_id] = key_info
                found_keys[key_id]["origins"] = []
            found_keys[key_id]["origins"].append(h.NAME)

            _normalize_key(session, found_keys[key_id])

            _update_scores(session, key_id, found_keys[key_id],
                           known_keys_list)

            # If the key_id was listed in get and is in found_keys then the key
            # has been successfully imported to the keychain.
            if key_id in known_keys_list or get and key_id in get:
                found_keys[key_id]['on_keychain'] = True

            # Check if key is already in the VCard for the specified address.
            if address in found_keys[key_id]['vcards']:
                vcard = found_keys[key_id]['vcards'][address]
                if 'keys' in vcard:
                    for k in vcard['keys']:
                        if k['fingerprint'] == key_id:
                            found_keys[key_id]['in_vcards'] = True

        # This updates and sorts ordered_keys in place. This will magically
        # also update the data on the viewable event, because Python.
        ordered_keys[:] = found_keys.values()
        ordered_keys.sort(key=lambda k: -k["score"])

    if event:
        event.private_data = {"result": ordered_keys, "runningsearch": False}
        session.config.event_log.log_event(event)
    return ordered_keys
Esempio n. 14
0
 def _gnupg(self, **kwargs):
     return GnuPG(self.session.config, event=self.event, **kwargs)
Esempio n. 15
0
    def TransformOutgoing(self, sender, rcpts, msg, **kwargs):
        matched = False
        gnupg = None

        sender_keyid = None
        if self.config.prefs.openpgp_header:
            try:
                gnupg = gnupg or GnuPG(self.config)
                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 self.config.prefs.openpgp_header:
            msg["OpenPGP"] = ("id=%s; preference=%s" %
                              (sender_keyid, self.config.prefs.openpgp_header))

        if ('attach-pgp-pubkey' in msg
                and msg['attach-pgp-pubkey'][:3].lower() in ('yes', 'tru')):
            # FIXME: Check attach_pgp_pubkey for instructions on which key(s)
            #        to attach. Attaching all of them may be a bit lame.
            gnupg = gnupg or GnuPG(self.config)
            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
Esempio n. 16
0
 def _lookup(self, address):
     g = GnuPG()
     return g.search_key(address)
Esempio n. 17
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
Esempio n. 18
0
def _GnuPG(session):
    gpg = GnuPG()
    if session and session.config:
        gpg.passphrase = session.config.gnupg_passphrase.get_reader()
    return gpg
Esempio n. 19
0
def lookup_crypto_keys(session, address,
                       event=None, strict_email_match=False, allowremote=True,
                       origins=None, get=None):
    known_keys_list = GnuPG(session and session.config or None).list_keys()
    found_keys = {}
    ordered_keys = []

    if origins:
        handlers = [h for h in KEY_LOOKUP_HANDLERS
                    if (h.NAME in origins) or (h.NAME.lower() in origins)]
    else:
        handlers = KEY_LOOKUP_HANDLERS

    ungotten = get and get[:] or []

    for handler in handlers:
        if get and not ungotten:
            # We have all the keys!
            break

        try:
            h = handler(session, known_keys_list)
            if not allowremote and not h.LOCAL:
                continue

            if event:
                ordered_keys.sort(key=lambda k: -k["score"])
                event.message = _('Searching for encryption keys in: %s'
                                  ) % _(h.NAME)
                event.private_data = {"result": ordered_keys,
                                      "runningsearch": h.NAME}
                session.config.event_log.log_event(event)

            # We allow for more time when importing keys
            timeout = h.TIMEOUT
            if ungotten:
                timeout *= 4

            # h.lookup will remove found keys from the wanted list,
            # but we have to watch out for the effects of timeouts.
            wanted = ungotten[:]
            results = RunTimed(timeout, h.lookup, address,
                               strict_email_match=strict_email_match,
                               get=(wanted if (get is not None) else None))
            ungotten[:] = wanted
        except (TimedOut, IOError, KeyError, ValueError, TypeError,
                AttributeError):
            if session.config.sys.debug:
                traceback.print_exc()
            results = {}

        for key_id, key_info in results.iteritems():
            if key_id in found_keys:
                old_scores = found_keys[key_id].get('scores', {})
                old_uids = found_keys[key_id].get('uids', [])[:]
                found_keys[key_id].update(key_info)
                if 'scores' in found_keys[key_id]:
                    found_keys[key_id]['scores'].update(old_scores)
                    # No need for an else, as old_scores will be empty

                # Merge in the old UIDs
                uid_emails = [u['email'] for u in key_info.get('uids', [])]
                if 'uids' not in found_keys[key_id]:
                    found_keys[key_id]['uids'] = []
                for uid in old_uids:
                    email = uid.get('email')
                    if email and email not in uid_emails:
                        found_keys[key_id]['uids'].append(uid)
            else:
                found_keys[key_id] = key_info
                found_keys[key_id]["origins"] = []
            found_keys[key_id]["origins"].append(h.NAME)
            _update_scores(session, key_id, found_keys[key_id], known_keys_list)
            _normalize_key(session, found_keys[key_id])

        # This updates and sorts ordered_keys in place. This will magically
        # also update the data on the viewable event, because Python.
        ordered_keys[:] = found_keys.values()
        ordered_keys.sort(key=lambda k: -k["score"])

    if event:
        event.private_data = {"result": ordered_keys, "runningsearch": False}
        session.config.event_log.log_event(event)
    return ordered_keys
Esempio n. 20
0
 def command(self):
     g = GnuPG()
     res = g.list_secret_keys()
     return self._success("Searched for secret keys", res)
Esempio n. 21
0
    def command(self):
        session = self.session

        if session.config.sys.lockdown:
            return self._error(_('In lockdown, doing nothing.'))

        # Perform any required migrations
        Migrate(session).run(before_setup=True, after_setup=False)

        # Create local mailboxes
        session.config.open_local_mailbox(session)

        # Create standard tags and filters
        created = []
        for t in self.TAGS:
            if not session.config.get_tag_id(t):
                AddTag(session, arg=[t]).run(save=False)
                created.append(t)
            session.config.get_tag(t).update(self.TAGS[t])
        for stype, statuses in (('sig', SignatureInfo.STATUSES),
                                ('enc', EncryptionInfo.STATUSES)):
            for status in statuses:
                tagname = 'mp_%s-%s' % (stype, status)
                if not session.config.get_tag_id(tagname):
                    AddTag(session, arg=[tagname]).run(save=False)
                    created.append(tagname)
                session.config.get_tag(tagname).update({
                    'type': 'attribute',
                    'display': 'invisible',
                    'label': False,
                })

        if 'New' in created:
            session.ui.notify(_('Created default tags'))

        # Import all the basic plugins
        for plugin in PLUGINS:
            if plugin not in session.config.sys.plugins:
                session.config.sys.plugins.append(plugin)
        try:
            # If spambayes is not installed, this will fail
            import mailpile.plugins.autotag_sb
            if 'autotag_sb' not in session.config.sys.plugins:
                session.config.sys.plugins.append('autotag_sb')
                session.ui.notify(_('Enabling spambayes autotagger'))
        except ImportError:
            session.ui.warning(
                _('Please install spambayes '
                  'for super awesome spam filtering'))
        session.config.save()
        session.config.load(session)

        vcard_importers = session.config.prefs.vcard.importers
        if not vcard_importers.gravatar:
            vcard_importers.gravatar.append({'active': True})
            session.ui.notify(_('Enabling gravatar image importer'))

        gpg_home = os.path.expanduser('~/.gnupg')
        if os.path.exists(gpg_home) and not vcard_importers.gpg:
            vcard_importers.gpg.append({'active': True, 'gpg_home': gpg_home})
            session.ui.notify(_('Importing contacts from GPG keyring'))

        if ('autotag_sb' in session.config.sys.plugins
                and len(session.config.prefs.autotag) == 0):
            session.config.prefs.autotag.append({
                'match_tag': 'spam',
                'unsure_tag': 'maybespam',
                'tagger': 'spambayes',
                'trainer': 'spambayes'
            })
            session.config.prefs.autotag[0].exclude_tags[0] = 'ham'

        # Assumption: If you already have secret keys, you want to
        #             use the associated addresses for your e-mail.
        #             If you don't already have secret keys, you should have
        #             one made for you, if GnuPG is available.
        #             If GnuPG is not available, you should be warned.
        gnupg = GnuPG()
        accepted_keys = []
        if gnupg.is_available():
            keys = gnupg.list_secret_keys()
            for key, details in keys.iteritems():
                # Ignore revoked/expired keys.
                if ("revocation-date" in details and details["revocation-date"]
                        <= date.today().strftime("%Y-%m-%d")):
                    continue

                accepted_keys.append(key)
                for uid in details["uids"]:
                    if "email" not in uid or uid["email"] == "":
                        continue

                    if uid["email"] in [
                            x["email"] for x in session.config.profiles
                    ]:
                        # Don't set up the same e-mail address twice.
                        continue

                    # FIXME: Add route discovery mechanism.
                    profile = {
                        "email": uid["email"],
                        "name": uid["name"],
                    }
                    session.config.profiles.append(profile)
                if (not session.config.prefs.gpg_recipient
                        and details["capabilities_map"][0]["encrypt"]):
                    session.config.prefs.gpg_recipient = key
                    session.ui.notify(_('Encrypting config to %s') % key)
                if session.config.prefs.crypto_policy == 'none':
                    session.config.prefs.crypto_policy = 'openpgp-sign'

            if len(accepted_keys) == 0:
                # FIXME: Start background process generating a key once a user
                #        has supplied a name and e-mail address.
                pass

        else:
            session.ui.warning(_('Oh no, PGP/GPG support is unavailable!'))

        if (session.config.prefs.gpg_recipient
                and not (self._idx() and self._idx().INDEX)
                and not session.config.prefs.obfuscate_index):
            randcrap = sha512b64(
                open('/dev/urandom').read(1024),
                session.config.prefs.gpg_recipient, '%s' % time.time())
            session.config.prefs.obfuscate_index = randcrap
            session.config.prefs.index_encrypted = True
            session.ui.notify(
                _('Obfuscating search index and enabling '
                  'indexing of encrypted e-mail. '))

        # Perform any required migrations
        Migrate(session).run(before_setup=False, after_setup=True)

        session.config.save()
        return self._success(_('Performed initial Mailpile setup'))
Esempio n. 22
0
def lookup_crypto_keys(session,
                       address,
                       event=None,
                       strict_email_match=False,
                       allowremote=True,
                       origins=None,
                       get=None,
                       vcard=None,
                       only_good=False,
                       pin_key=False,
                       known_keys_list=None):
    config = (session and session.config)
    found_keys = {}
    ordered_keys = []
    known_keys_list = known_keys_list or _mailpile_key_list(
        GnuPG(config or None).list_keys())

    if origins:
        handlers = [
            h for h in KEY_LOOKUP_HANDLERS if (h.NAME in origins) or (
                h.NAME.lower() in origins) or (h.SHORTNAME in origins)
        ]
    else:
        handlers = KEY_LOOKUP_HANDLERS

    ungotten = get and get[:] or []
    progress = []

    # If the user has disabled "web content", only allow local requests
    if config and allowremote and config.prefs.web_content == 'off':
        if ('keylookup' in config.sys.debug or 'keytofu' in config.sys.debug):
            session.ui.debug(
                "Remote key lookups disabled by prefs.web_content.")
        allowremote = False

    for handler in handlers:
        if get and not ungotten:
            # We have all the keys!
            break

        try:
            h = handler(session, known_keys_list)
            if not allowremote and not h.LOCAL:
                continue

            if allowremote and config and config.prefs.web_content == 'anon':
                if (config.sys.proxy.protocol not in ('tor', 'tor-risky')
                        or not h.PRIVACY_FRIENDLY):
                    if ('keylookup' in config.sys.debug
                            or 'keytofu' in config.sys.debug):
                        session.ui.debug(
                            "Origin %s disabled by prefs.web_content" % h.NAME)
                    continue

            if found_keys and (not h.PRIVACY_FRIENDLY) and (not origins):
                # We only try the privacy-hostile methods if we haven't
                # found any keys (unless origins were specified).
                if not ungotten:
                    continue

            progress.append(h.NAME)
            if event and config:
                ordered_keys.sort(key=lambda k: -k["score"])
                event.message = _('Searching for encryption keys in: %s') % _(
                    h.NAME)
                event.private_data = {
                    "result": ordered_keys,
                    "progress": progress,
                    "runningsearch": h.NAME
                }
                config.event_log.log_event(event)

            # We allow for more time when importing keys
            timeout = h.TIMEOUT
            if ungotten:
                timeout *= 4

            # h.lookup will remove found keys from the wanted list,
            # but we have to watch out for the effects of timeouts.
            wanted = ungotten[:]
            results = RunTimed(timeout,
                               h.lookup,
                               address,
                               strict_email_match=strict_email_match,
                               get=(wanted if (get is not None) else None))
            ungotten[:] = wanted
        except KeyboardInterrupt:
            raise
        except:
            if config and config.sys.debug:
                traceback.print_exc()
            results = {}

        # FIXME: This merging of info about keys is probably misguided.
        for key_id, key_info in results.iteritems():
            if key_id in found_keys:
                old_scores = found_keys[key_id].scores
                old_uids = found_keys[key_id].uids
                found_keys[key_id].update(key_info)
                found_keys[key_id].scores.update(old_scores)

                # Merge in the old UIDs
                uid_emails = [u.email for u in key_info.uids]
                for uid in old_uids:
                    email = uid.email
                    if email and email not in uid_emails:
                        found_keys[key_id].uids.append(uid)
            else:
                found_keys[key_id] = key_info
            found_keys[key_id].origins.append(h.NAME)

        for key_id in found_keys.keys():
            _normalize_key(session, found_keys[key_id])
            _update_scores(session, key_id, found_keys[key_id],
                           known_keys_list)

        # This updates and sorts ordered_keys in place. This will magically
        # also update the data on the viewable event, because Python.
        ordered_keys[:] = found_keys.values()
        ordered_keys.sort(key=lambda k: -k.score)

    if only_good:
        ordered_keys = [k for k in ordered_keys if k.score > 0]

    if get and vcard and ordered_keys:
        with vcard:
            vcard.pgp_key = ordered_keys[0].fingerprint
            vcard.pgp_key_pinned = 'true' if pin_key else 'false'
            vcard.save()
        ordered_keys[0].is_preferred = True
        ordered_keys[0].is_pinned = pin_key
        for k in ordered_keys[1:]:
            k.is_preferred = k.is_pinned = False

    if event and config:
        event.private_data = {"result": ordered_keys, "runningsearch": False}
        config.event_log.log_event(event)
    return ordered_keys