3 import functools as _functools
4 import xml.etree.ElementTree as _etree
6 from . import LOG as _LOG
7 from . import crypt as _crypt
11 from pyassuan import common as _common
14 @_functools.total_ordering
15 class SubKey (object):
16 """The crypographic key portion of an OpenPGP key.
18 def __init__(self, fingerprint=None):
19 self.fingerprint = fingerprint
22 return '<{} {}>'.format(type(self).__name__, self.fingerprint[-8:])
27 def __eq__(self, other):
28 if self.fingerprint and hasattr(other, 'fingerprint'):
29 return self.fingerprint == other.fingerprint
30 return id(self) == id(other)
32 def __lt__(self, other):
33 if self.fingerprint and hasattr(other, 'fingerprint'):
34 return self.fingerprint < other.fingerprint
35 return id(self) < id(other)
38 return int(self.fingerprint, 16)
41 @_functools.total_ordering
42 class UserID (object):
43 def __init__(self, uid=None, name=None, email=None, comment=None):
47 self.comment = comment
50 return '<{} {}>'.format(type(self).__name__, self.name)
55 def __eq__(self, other):
56 if self.uid and hasattr(other, 'uid'):
57 return self.uid == other.uid
58 return id(self) == id(other)
60 def __lt__(self, other):
61 if self.uid and hasattr(other, 'uid'):
62 return self.uid < other.uid
63 return id(self) < id(other)
69 @_functools.total_ordering
71 def __init__(self, subkeys=None, uids=None):
79 can_authenticate = False
88 self.subkeys = subkeys
94 return '<{} {}>'.format(
95 type(self).__name__, self.subkeys[0].fingerprint[-8:])
100 def __eq__(self, other):
101 other_subkeys = getattr(other, 'subkeys', None)
102 if self.subkeys and other_subkeys:
103 return self.subkeys[0] == other.subkeys[0]
104 return id(self) == id(other)
106 def __lt__(self, other):
107 other_subkeys = getattr(other, 'subkeys', None)
108 if self.subkeys and other_subkeys:
109 return self.subkeys[0] < other.subkeys[0]
110 return id(self) < id(other)
113 return int(self.fingerprint, 16)
116 def lookup_keys(patterns=None):
117 """Lookup keys matching any patterns listed in ``patterns``.
121 >>> key = list(lookup_keys(['pgp-mime-test']))[0]
125 [<SubKey 4332B6E3>, <SubKey 2F73DE2E>]
127 [<UserID pgp-mime-test>]
133 >>> print(list(lookup_keys(['pgp-mime-test'])))
135 >>> print(list(lookup_keys(['pgp-mime@invalid.com'])))
137 >>> print(list(lookup_keys(['4332B6E3'])))
139 >>> print(list(lookup_keys(['0x2F73DE2E'])))
141 >>> print(list(lookup_keys())) # doctest: +ELLIPSIS
142 [..., <Key 4332B6E3>, ...]
144 _LOG.debug('lookup key: {}'.format(patterns))
145 client,socket = _crypt.get_client()
148 args = [' '.join(patterns)]
153 rs,result = client.make_request(_common.Request('KEYLIST', *args))
155 _crypt.disconnect(client, socket)
158 tree = _etree.fromstring(result.replace(b'\x00', b''))
159 for key in tree.findall('.//key'):
162 attribute = tag_mapping.get(
163 child.tag, child.tag.replace('-', '_'))
165 'revoked', 'expired', 'disabled', 'invalid', 'can-encrypt',
166 'can-sign', 'can-certify', 'can-authenticate', 'is-qualified',
167 'secret', 'revoked']:
169 value = child.get('value')
170 if not value.startswith('0x'):
171 raise NotImplementedError('{} value {}'.format(
173 value = int(value, 16)
176 'protocol', 'owner-trust']:
178 elif child.tag in ['issuer', 'chain-id']:
181 elif child.tag in ['subkeys', 'uids']:
182 parser = globals()['_parse_{}'.format(attribute)]
183 value = parser(child)
185 raise NotImplementedError(child.tag)
186 setattr(k, attribute, value)
189 def _parse_subkeys(element):
191 'fpr': 'fingerprint',
194 for subkey in element:
196 for child in subkey.iter():
197 if child == subkey: # iter() includes the root element
199 attribute = tag_mapping.get(
200 child.tag, child.tag.replace('-', '_'))
205 raise NotImplementedError(child.tag)
206 setattr(s, attribute, value)
210 def _parse_uids(element):
216 for child in uid.iter():
217 if child == uid: # iter() includes the root element
219 attribute = tag_mapping.get(
220 child.tag, child.tag.replace('-', '_'))
222 'uid', 'name', 'email', 'comment']:
225 raise NotImplementedError(child.tag)
226 setattr(u, attribute, value)