commit a73e50f2b2e3345934731c4c1e6a6e67b5251d0e Author: juga0 juga@riseup.net Date: Mon May 28 10:41:59 2018 +0000
Store relays' ed25519 master key
* RelayList is now a list of RelayNS instead of RouterStatusEntryV3 to have master_key_ed25519 as an attribute * create pytest fixture to start Tor with tests * create test to check master_key_ed25519 --- sbws/lib/relaylist.py | 57 +++++++++++++++++++++++++++++++++++++++- tests/unit/conftest.py | 16 ++++++++++- tests/unit/lib/test_relaylist.py | 13 +++++++++ 3 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/sbws/lib/relaylist.py b/sbws/lib/relaylist.py index aeae3eb..6d0743d 100644 --- a/sbws/lib/relaylist.py +++ b/sbws/lib/relaylist.py @@ -1,3 +1,5 @@ +from stem.descriptor.router_status_entry import RouterStatusEntryV3 + import sbws.util.stem as stem_utils from stem import Flag from stem import DescriptorUnavailable @@ -11,6 +13,18 @@ from sbws.globals import resolve log = logging.getLogger(__name__)
+class RelayNS(RouterStatusEntryV3): + """Inherit from RouterStatusEntryV3 and add the attribute + master_key_ed25519. + + :param str ed25519: the ed25519 master key base 64 encoded. + """ + def __init__(self, ed25519=None, *args, **kwargs): + super().__init__(*args, **kwargs) + if ed25519 is not None: + self.master_key_ed25519 = ed25519 + + class RelayList: ''' Keeps a list of all relays in the current Tor network and updates it transparently in the background. Provides useful interfaces for getting @@ -68,6 +82,40 @@ class RelayList: # return [r for r in relays if r.measured is not None] return [r for r in relays if not r.is_unmeasured]
+ def relay_ed25519_master_key(self, ns): + """Obtain ed25519 master key of the relay represented by + the network status relay line. + + :param RouterStatusEntryV3 ns: the network status relay + :returns: str, the ed25519 master key base 64 encoded without + trailing '='s. + """ + # In theory this is never going to be the case? + if ns.identifier is None or ns.identifier_type != 'ed25519': + log.debug('Getting microdescriptor to obtain ed25519 identity.') + mdesc = self._controller.get_microdescriptor(ns.fingerprint, None) + if mdesc is not None: + if 'ed25519' in mdesc.identifiers.keys(): + ed25519 = mdesc.identifiers['ed25519'].rstrip('=') + log.debug('Found ed25519 master key.') + return ed25519 + log.debug('No ed25519 master-key found') + log.debug('Could not get microdescriptor') + # In case Tor can not retrive microdescriptors, + # try with server descriptors. + log.debug('Getting server descriptor to obtain ' + 'ed25519 master key.') + sdesc = self._controller.get_server_descriptor(ns.fingerprint, + None) + if sdesc is not None: + ed25519 = sdesc.ed25519_master_key().rstrip('=') + log.debug('Found ed25519 master key.') + return ed25519 + log.debug('Could not get server descriptor') + return None + log.debug('Relay has already ed25519 master key') + return ns.identifier + def exits_can_exit_to(self, host, port): ''' Return exits that can MOST LIKELY exit to the given host:port. **host** @@ -131,7 +179,14 @@ class RelayList: def _init_relays(self): c = self._controller assert stem_utils.is_controller_okay(c) - return [ns for ns in c.get_network_statuses()] + relays = [] + # for each network status relay, obtain the ed25519 master key + # and generate a new list of RelayNS objects + for ns in c.get_network_statuses(): + ed25519 = self.relay_ed25519_master_key(ns) + rns = RelayNS(ed25519=ed25519, content=ns._raw_contents) + relays.append(rns) + return relays
def _refresh(self): self._relays = self._init_relays() diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 4d0b2f6..2847fe1 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,8 +2,9 @@ from sbws.lib.resultdump import ResultError from sbws.lib.resultdump import ResultSuccess from sbws.lib.resultdump import Result from sbws.lib.resultdump import write_result_to_datadir -from sbws.util.config import get_config +from sbws.util.config import get_config, _get_default_config from sbws.util.parser import create_parser +import sbws.util.stem as stem_utils import sbws.core.init from tempfile import TemporaryDirectory import pytest @@ -61,6 +62,19 @@ def datadir(request): return D(request.fspath.dirpath("data"))
+@pytest.fixture() +def start_tor(request, tmpdir): + """Star Tor or connect to existing socket in a temporal directory.""" + conf = _get_default_config() + home = tmpdir.join('.sbws') + conf['paths']['sbws_home'] = home.strpath + controller, _ = stem_utils.init_controller( + path=conf['tor']['control_socket']) + if not controller: + controller = stem_utils.launch_tor(conf) + return controller + + @pytest.fixture(scope='session') def parser(): return create_parser() diff --git a/tests/unit/lib/test_relaylist.py b/tests/unit/lib/test_relaylist.py new file mode 100644 index 0000000..cdb71c2 --- /dev/null +++ b/tests/unit/lib/test_relaylist.py @@ -0,0 +1,13 @@ +from sbws.lib.relaylist import RelayList + + +def test_relaylist_master_key_ed25519(start_tor): + # This test starts tor, so it is slow. And it will fail whenever there are + # network problems + controller = start_tor + rl = RelayList(None, None, controller) + relay = [r for r in rl.relays if r.nickname == 'moria1'][0] + assert relay.fingerprint == '9695DFC35FFEB861329B9F1AB04C46397020CE31' + assert relay.identifier is None + assert relay.master_key_ed25519 == \ + 'yp0fwtp4aa/VMyZJGz8vN7Km3zYet1YBZwqZEk1CwHI'
tor-commits@lists.torproject.org