[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Implementing a get_key_certificates() method
commit 4d122b1a417fe318f0bb3d169688d25f3e749754
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Sun Jul 21 17:10:26 2013 -0700
Implementing a get_key_certificates() method
Method for fetching key certificates for the authorities. This included a
little work so parse_file() could return multiple certificates when they're
concatenated together.
---
stem/descriptor/__init__.py | 3 ++-
stem/descriptor/networkstatus.py | 31 +++++++++++++++++++++++++++++++
stem/descriptor/remote.py | 36 ++++++++++++++++++++++++++++++++++++
test/integ/descriptor/remote.py | 30 ++++++++++++++++++++++++++++++
4 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index e3b5a8b..14b29d1 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -237,7 +237,8 @@ def _parse_metrics_file(descriptor_type, major_version, minor_version, descripto
for desc in stem.descriptor.networkstatus._parse_file(descriptor_file, document_type, validate = validate, document_handler = document_handler):
yield desc
elif descriptor_type == "dir-key-certificate-3" and major_version == 1:
- yield stem.descriptor.networkstatus.KeyCertificate(descriptor_file.read(), validate = validate)
+ for desc in stem.descriptor.networkstatus._parse_file_key_certs(descriptor_file, validate = validate):
+ yield desc
elif descriptor_type in ("network-status-consensus-3", "network-status-vote-3") and major_version == 1:
document_type = stem.descriptor.networkstatus.NetworkStatusDocumentV3
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index baf7f0a..ec21304 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -55,6 +55,7 @@ import stem.util.tor_tools
import stem.version
from stem.descriptor import (
+ PGP_BLOCK_END,
Descriptor,
DocumentHandler,
_get_descriptor_components,
@@ -220,6 +221,36 @@ def _parse_file(document_file, document_type = None, validate = True, is_microde
raise ValueError("Unrecognized document_handler: %s" % document_handler)
+def _parse_file_key_certs(certificate_file, validate = True):
+ """
+ Parses a file containing one or more authority key certificates.
+
+ :param file certificate_file: file with key certificates
+ :param bool validate: checks the validity of the certificate's contents if
+ **True**, skips these checks otherwise
+
+ :returns: iterator for :class:`stem.descriptor.networkstatus.KeyCertificate`
+ instance in the file
+
+ :raises:
+ * **ValueError** if the key certificate content is invalid and validate is
+ **True**
+ * **IOError** if the file can't be read
+ """
+
+ while True:
+ keycert_content = _read_until_keywords("dir-key-certification", certificate_file)
+
+ # we've reached the 'router-signature', now include the pgp style block
+ block_end_prefix = PGP_BLOCK_END.split(' ', 1)[0]
+ keycert_content += _read_until_keywords(block_end_prefix, certificate_file, True)
+
+ if keycert_content:
+ yield stem.descriptor.networkstatus.KeyCertificate(bytes.join(b"", keycert_content), validate = validate)
+ else:
+ break # done parsing file
+
+
class NetworkStatusDocument(Descriptor):
"""
Common parent for network status documents.
diff --git a/stem/descriptor/remote.py b/stem/descriptor/remote.py
index a009078..0aabd74 100644
--- a/stem/descriptor/remote.py
+++ b/stem/descriptor/remote.py
@@ -52,6 +52,7 @@ itself...
|- get_extrainfo_descriptors - provides present :class:`~stem.descriptor.extrainfo_descriptor.ExtraInfoDescriptor`
|- get_microdescriptors - provides present :class:`~stem.descriptor.microdescriptor.Microdescriptor`
|- get_consensus - provides present :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`
+ |- get_key_certificates - provides present :class:`~stem.descriptor.networkstatus.KeyCertificate`
+- query - request an arbitrary descriptor resource
.. data:: MAX_DESCRIPTOR_BATCH_SIZE
@@ -118,6 +119,8 @@ def _guess_descriptor_type(resource):
return 'microdescriptor 1.0'
elif resource.startswith('/tor/status-vote/'):
return 'network-status-consensus-3 1.0'
+ elif resource.startswith('/tor/keys/'):
+ return 'dir-key-certificate-3 1.0'
else:
raise ValueError("Unable to determine the descriptor type for '%s'" % resource)
@@ -517,6 +520,39 @@ class DescriptorDownloader(object):
return self.query(resource + '.z', document_handler = document_handler, **query_args)
+ def get_key_certificates(self, authority_v3idents = None, **query_args):
+ """
+ Provides the key certificates for authorities with the given fingerprints.
+ If no fingerprints are provided then this returns all present key
+ certificates.
+
+ :param str authority_v3idents: fingerprint or list of fingerprints of the
+ authority keys, see `'v3ident' in tor's config.c
+ <https://gitweb.torproject.org/tor.git/blob/f631b73:/src/or/config.c#l816>`_
+ for the values.
+ :param query_args: additional arguments for the
+ :class:`~stem.descriptor.remote.Query` constructor
+
+ :returns: :class:`~stem.descriptor.remote.Query` for the key certificates
+
+ :raises: **ValueError** if we request more than 96 key certificates by
+ their identity fingerprints (this is due to a limit on the url length by
+ squid proxies).
+ """
+
+ resource = '/tor/keys/all.z'
+
+ if isinstance(authority_v3idents, str):
+ authority_v3idents = [authority_v3idents]
+
+ if authority_v3idents:
+ if len(authority_v3idents) > MAX_DESCRIPTOR_BATCH_SIZE:
+ raise ValueError("Unable to request more than %i key certificates at a time by their identity fingerprints" % MAX_DESCRIPTOR_BATCH_SIZE)
+
+ resource = '/tor/keys/fp/%s.z' % '+'.join(authority_v3idents)
+
+ return self.query(resource, **query_args)
+
def query(self, resource, **query_args):
"""
Issues a request for the given resource.
diff --git a/test/integ/descriptor/remote.py b/test/integ/descriptor/remote.py
index b3c549d..d11a4ae 100644
--- a/test/integ/descriptor/remote.py
+++ b/test/integ/descriptor/remote.py
@@ -6,6 +6,7 @@ import unittest
import stem.descriptor.extrainfo_descriptor
import stem.descriptor.microdescriptor
+import stem.descriptor.networkstatus
import stem.descriptor.remote
import stem.descriptor.router_status_entry
import stem.descriptor.server_descriptor
@@ -178,3 +179,32 @@ class TestDescriptorDownloader(unittest.TestCase):
consensus = list(consensus_query)
self.assertTrue(len(consensus) > 50)
self.assertTrue(isinstance(consensus[0], stem.descriptor.router_status_entry.RouterStatusEntryV3))
+
+ def test_get_key_certificates(self):
+ """
+ Exercises the downloader's get_key_certificates() method.
+ """
+
+ if test.runner.require_online(self):
+ return
+ elif test.runner.only_run_once(self, "test_get_key_certificates"):
+ return
+
+ downloader = stem.descriptor.remote.DescriptorDownloader()
+
+ single_query = downloader.get_key_certificates('D586D18309DED4CD6D57C18FDB97EFA96D330566')
+
+ multiple_query = downloader.get_key_certificates([
+ 'D586D18309DED4CD6D57C18FDB97EFA96D330566',
+ '14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4',
+ ])
+
+ single_query.run()
+ multiple_query.run()
+
+ single_query_results = list(single_query)
+ self.assertEqual(1, len(single_query_results))
+ self.assertEqual('D586D18309DED4CD6D57C18FDB97EFA96D330566', single_query_results[0].fingerprint)
+ self.assertTrue(isinstance(single_query_results[0], stem.descriptor.networkstatus.KeyCertificate))
+
+ self.assertEqual(2, len(list(multiple_query)))
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits