key: add pgp_mime.key wrapping gpgme-tool's KEYLIST command.
authorW. Trevor King <wking@tremily.us>
Thu, 20 Sep 2012 16:24:27 +0000 (12:24 -0400)
committerW. Trevor King <wking@tremily.us>
Thu, 20 Sep 2012 16:28:46 +0000 (12:28 -0400)
This lets you lookup key information.  Eventually, you'll be able to
look up user IDs, email addresses, subkeys, etc.  However,
gpgme-tool's XML output for KEYLIST (result_keylist_to_xml) is a stub
as of:

  commit 83e74202cd7c4c975d149c49e2507fdb0e60ef32
  Commit:     Marcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
  CommitDate: Sat Jul 28 22:11:31 2012 +0200

    Add two recent contributors.

pgp_mime/crypt.py
pgp_mime/key.py [new file with mode: 0644]

index 883a8a1671a6823bf70ffd3e001698748679f066..8bc4519d654bea6ba68f1181833bc65f04c18fec 100644 (file)
@@ -317,7 +317,9 @@ def verify_bytes(data, signature=None, always_trust=False):
       public key algorithm: RSA
       hash algorithm: SHA1
 
-    Data signed by a subkey returns the subkey fingerprint.
+    Data signed by a subkey returns the subkey fingerprint.  To find
+    the primary key for a given subkey, use
+    ``pgp_mime.key.lookup_keys()``.
 
     >>> b = '\n'.join([
     ...     '-----BEGIN PGP MESSAGE-----',
diff --git a/pgp_mime/key.py b/pgp_mime/key.py
new file mode 100644 (file)
index 0000000..0b5812d
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright
+
+import xml.etree.ElementTree as _etree
+
+from . import LOG as _LOG
+from . import crypt as _crypt
+
+import pyassuan
+import logging
+from pyassuan import common as _common
+
+
+class Key (object):
+    def __init__(self, fingerprint=None):
+        self.fingerprint = fingerprint
+        # more data to come once gpgme-tool gets keylist XML support
+
+    def __str__(self):
+        return '<{} {}>'.format(self.__class__.__name__, self.fingerprint[-8:])
+
+    def __repr__(self):
+        return str(self)
+
+
+def lookup_keys(patterns=None, load=False):
+    """Lookup keys matching any patterns listed in ``patterns``.
+
+    >>> print(list(lookup_keys(['pgp-mime-test'])))
+    [<Key 4332B6E3>]
+    >>> print(list(lookup_keys(['pgp-mime@invalid.com'])))
+    [<Key 4332B6E3>]
+    >>> print(list(lookup_keys(['4332B6E3'])))
+    [<Key 4332B6E3>]
+    >>> print(list(lookup_keys(['0x2F73DE2E'])))
+    [<Key 4332B6E3>]
+    >>> print(list(lookup_keys()))  # doctest: +ELLIPSIS
+    [..., <Key 4332B6E3>, ...]
+
+    >>> key = lookup_keys(['2F73DE2E'], load=True)
+    >>> print(list(key)[0])
+    Traceback (most recent call last):
+      ...
+    NotImplementedError: gpgme-tool doesn't return keylist data
+    """
+    _LOG.debug('lookup key: {}'.format(patterns))
+    pyassuan.LOG.setLevel(logging.DEBUG)
+    client,socket = _crypt.get_client()
+    parameters = []
+    if patterns:
+        args = [' '.join(patterns)]
+    else:
+        args = []
+    try:
+        _crypt.hello(client)
+        if load:
+            client.make_request(_common.Request('KEYLIST', *args))
+            rs,result = client.make_request(_common.Request('RESULT', *args))
+        else:
+            rs,result = client.make_request(_common.Request('KEYLIST', *args))
+    finally:
+        _crypt.disconnect(client, socket)
+    if load:
+        tag_mapping = {
+            'fpr': 'fingerprint',
+            }
+        tree = _etree.fromstring(result.replace(b'\x00', b''))
+        if list(tree.findall('.//truncated')):
+            raise NotImplementedError("gpgme-tool doesn't return keylist data")
+        for signature in tree.findall('.//key'):
+            key = Key()
+            for child in signature.iter():
+                if child == signature:  # iter() includes the root element
+                    continue
+                attribute = tag_mapping.get(
+                    child.tag, child.tag.replace('-', '_'))
+                if child.tag in ['fpr']:
+                    value = child.text
+                else:
+                    raise NotImplementedError(child.tag)
+                setattr(s, attribute, value)
+            yield key
+    else:
+        for line in result.splitlines():
+            line = str(line, 'ascii')
+            assert line.startswith('key:'), result
+            fingerprint = line.split(':', 1)[1]
+            yield Key(fingerprint=fingerprint)