Sophie

Sophie

distrib > Fedora > 18 > i386 > by-pkgid > e4be28b383be195ff28bfce2053e734a > files > 57

python-stem-doc-1.1.0-1.fc18.noarch.rpm



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>stem.descriptor.networkstatus &mdash; Stem 1.1.0 documentation</title>
    
    <link rel="stylesheet" href="../../../_static/haiku.css" type="text/css" />
    <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
    <link rel="stylesheet" href="../../../_static/print.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../../../',
        VERSION:     '1.1.0',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../../../_static/jquery.js"></script>
    <script type="text/javascript" src="../../../_static/underscore.js"></script>
    <script type="text/javascript" src="../../../_static/doctools.js"></script>
    <script type="text/javascript" src="../../../_static/theme_extras.js"></script>
    <link rel="shortcut icon" href="../../../_static/favicon.png"/>
    <link rel="top" title="Stem 1.1.0 documentation" href="../../../index.html" />
    <link rel="up" title="stem" href="../../stem.html" /> 
  </head>
  <body>
      <div class="header"><img class="rightlogo" src="../../../_static/logo.png" alt="Logo"/><h1 class="heading"><a href="../../../index.html">
          <span>Stem Docs</span></a></h1>
        <h2 class="heading"><span>stem.descriptor.networkstatus</span></h2>
      </div>
      <div class="topnav">
      
        <p>

        <ul id="navbar">
          <li><a href="../../../index.html">Home</a></li>
          <li><a href="../../../tutorials.html">Tutorials</a>
            <ul>
              <li><a href="../../../tutorials/the_little_relay_that_could.html">Hello World</a></li>
              <li><a href="../../../tutorials/to_russia_with_love.html">Client Usage</a></li>
              <li><a href="../../../tutorials/tortoise_and_the_hare.html">Event Listening</a></li>
              <li><a href="../../../tutorials/mirror_mirror_on_the_wall.html">Tor Descriptors</a></li>
              <li><a href="../../../tutorials/east_of_the_sun.html">Utilities</a></li>
              <li><a href="../../../tutorials/double_double_toil_and_trouble.html">Examples</a></li>
            </ul>
          </li>
          <li><a href="../../../api.html">API</a>
            <ul>
              <li><a href="../../../api/control.html">stem.control</a></li>
              <li><a href="../../../api/connection.html">stem.connection</a></li>
              <li><a href="../../../api/socket.html">stem.socket</a></li>
              <li><a href="../../../api/process.html">stem.process</a></li>
              <li><a href="../../../api/response.html">stem.response</a></li>
              <li><a href="../../../api/exit_policy.html">stem.exit_policy</a></li>
              <li><a href="../../../api/version.html">stem.version</a></li>
              <li><a href="../../../api.html#descriptors">Descriptors</a></li>
              <li><a href="../../../api.html#utilities">Utilities</a></li>
            </ul>
          </li>
          <li><a href="https://trac.torproject.org/projects/tor/wiki/doc/stem">Development</a>
            <ul>
              <li><a href="../../../faq.html">FAQ</a></li>
              <li><a href="../../../change_log.html">Change Log</a></li>
              <li><a href="https://trac.torproject.org/projects/tor/wiki/doc/stem/bugs">Bug Tracker</a></li>
              <li><a href="../../../download.html">Download</a></li>
            </ul>
          </li>
        </ul>
        </p>

      </div>
      <div class="content">
        
        
  <h1>Source code for stem.descriptor.networkstatus</h1><div class="highlight"><pre>
<span class="c"># Copyright 2012-2013, Damian Johnson and The Tor Project</span>
<span class="c"># See LICENSE for licensing information</span>

<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Parsing for Tor network status documents. This supports both the v2 and v3</span>
<span class="sd">dir-spec. Documents can be obtained from a few sources...</span>

<span class="sd">* the &#39;cached-consensus&#39; file in tor&#39;s data directory</span>
<span class="sd">* tor metrics, at https://metrics.torproject.org/data.html</span>
<span class="sd">* directory authorities and mirrors via their DirPort</span>

<span class="sd">... and contain the following sections...</span>

<span class="sd">* document header</span>
<span class="sd">* list of :class:`stem.descriptor.networkstatus.DirectoryAuthority`</span>
<span class="sd">* list of :class:`stem.descriptor.router_status_entry.RouterStatusEntry`</span>
<span class="sd">* document footer</span>

<span class="sd">Of these, the router status entry section can be quite large (on the order of</span>
<span class="sd">hundreds of kilobytes). As such we provide a couple of methods for reading</span>
<span class="sd">network status documents through :func:`~stem.descriptor.__init__.parse_file`.</span>
<span class="sd">For more information see :func:`~stem.descriptor.__init__.DocumentHandler`...</span>

<span class="sd">::</span>

<span class="sd">  from stem.descriptor import parse_file, DocumentHandler</span>

<span class="sd">  with open(&#39;.tor/cached-consensus&#39;, &#39;rb&#39;) as consensus_file:</span>
<span class="sd">    # Processes the routers as we read them in. The routers refer to a document</span>
<span class="sd">    # with an unset &#39;routers&#39; attribute.</span>

<span class="sd">    for router in parse_file(consensus_file, &#39;network-status-consensus-3 1.0&#39;, document_handler = DocumentHandler.ENTRIES):</span>
<span class="sd">      print router.nickname</span>

<span class="sd">**Module Overview:**</span>

<span class="sd">::</span>

<span class="sd">  NetworkStatusDocument - Network status document</span>
<span class="sd">    |- NetworkStatusDocumentV2 - Version 2 network status document</span>
<span class="sd">    |- NetworkStatusDocumentV3 - Version 3 network status document</span>
<span class="sd">    +- BridgeNetworkStatusDocument - Version 3 network status document for bridges</span>

<span class="sd">  KeyCertificate - Certificate used to authenticate an authority</span>
<span class="sd">  DocumentSignature - Signature of a document by a directory authority</span>
<span class="sd">  DirectoryAuthority - Directory authority as defined in a v3 network status document</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">import</span> <span class="nn">datetime</span>
<span class="kn">import</span> <span class="nn">io</span>

<span class="kn">import</span> <span class="nn">stem.descriptor.router_status_entry</span>
<span class="kn">import</span> <span class="nn">stem.util.str_tools</span>
<span class="kn">import</span> <span class="nn">stem.util.tor_tools</span>
<span class="kn">import</span> <span class="nn">stem.version</span>

<span class="kn">from</span> <span class="nn">stem.descriptor</span> <span class="kn">import</span> <span class="p">(</span>
  <span class="n">PGP_BLOCK_END</span><span class="p">,</span>
  <span class="n">Descriptor</span><span class="p">,</span>
  <span class="n">DocumentHandler</span><span class="p">,</span>
  <span class="n">_get_descriptor_components</span><span class="p">,</span>
  <span class="n">_read_until_keywords</span><span class="p">,</span>
<span class="p">)</span>

<span class="c"># Version 2 network status document fields, tuples of the form...</span>
<span class="c"># (keyword, is_mandatory)</span>

<span class="n">NETWORK_STATUS_V2_FIELDS</span> <span class="o">=</span> <span class="p">(</span>
  <span class="p">(</span><span class="s">&quot;network-status-version&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;dir-source&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;fingerprint&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;contact&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;dir-signing-key&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;client-versions&quot;</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;server-versions&quot;</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;published&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;dir-options&quot;</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;directory-signature&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
<span class="p">)</span>

<span class="c"># Network status document are either a &#39;vote&#39; or &#39;consensus&#39;, with different</span>
<span class="c"># mandatory fields for each. Both though require that their fields appear in a</span>
<span class="c"># specific order. This is an ordered listing of the following...</span>
<span class="c">#</span>
<span class="c"># (field, in_votes, in_consensus, is_mandatory)</span>

<span class="n">HEADER_STATUS_DOCUMENT_FIELDS</span> <span class="o">=</span> <span class="p">(</span>
  <span class="p">(</span><span class="s">&quot;network-status-version&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;vote-status&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;consensus-methods&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;consensus-method&quot;</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;published&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;valid-after&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;fresh-until&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;valid-until&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;voting-delay&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;client-versions&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;server-versions&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;known-flags&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;flag-thresholds&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;params&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
<span class="p">)</span>

<span class="n">FOOTER_STATUS_DOCUMENT_FIELDS</span> <span class="o">=</span> <span class="p">(</span>
  <span class="p">(</span><span class="s">&quot;directory-footer&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;bandwidth-weights&quot;</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&quot;directory-signature&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
<span class="p">)</span>

<span class="n">HEADER_FIELDS</span> <span class="o">=</span> <span class="p">[</span><span class="n">attr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">attr</span> <span class="ow">in</span> <span class="n">HEADER_STATUS_DOCUMENT_FIELDS</span><span class="p">]</span>
<span class="n">FOOTER_FIELDS</span> <span class="o">=</span> <span class="p">[</span><span class="n">attr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">attr</span> <span class="ow">in</span> <span class="n">FOOTER_STATUS_DOCUMENT_FIELDS</span><span class="p">]</span>

<span class="n">AUTH_START</span> <span class="o">=</span> <span class="s">&quot;dir-source&quot;</span>
<span class="n">ROUTERS_START</span> <span class="o">=</span> <span class="s">&quot;r&quot;</span>
<span class="n">FOOTER_START</span> <span class="o">=</span> <span class="s">&quot;directory-footer&quot;</span>
<span class="n">V2_FOOTER_START</span> <span class="o">=</span> <span class="s">&quot;directory-signature&quot;</span>

<span class="n">DEFAULT_PARAMS</span> <span class="o">=</span> <span class="p">{</span>
  <span class="s">&quot;bwweightscale&quot;</span><span class="p">:</span> <span class="mi">10000</span><span class="p">,</span>
  <span class="s">&quot;cbtdisabled&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
  <span class="s">&quot;cbtnummodes&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
  <span class="s">&quot;cbtrecentcount&quot;</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
  <span class="s">&quot;cbtmaxtimeouts&quot;</span><span class="p">:</span> <span class="mi">18</span><span class="p">,</span>
  <span class="s">&quot;cbtmincircs&quot;</span><span class="p">:</span> <span class="mi">100</span><span class="p">,</span>
  <span class="s">&quot;cbtquantile&quot;</span><span class="p">:</span> <span class="mi">80</span><span class="p">,</span>
  <span class="s">&quot;cbtclosequantile&quot;</span><span class="p">:</span> <span class="mi">95</span><span class="p">,</span>
  <span class="s">&quot;cbttestfreq&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
  <span class="s">&quot;cbtmintimeout&quot;</span><span class="p">:</span> <span class="mi">2000</span><span class="p">,</span>
  <span class="s">&quot;cbtinitialtimeout&quot;</span><span class="p">:</span> <span class="mi">60000</span><span class="p">,</span>
  <span class="s">&quot;Support022HiddenServices&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="p">}</span>

<span class="c"># KeyCertificate fields, tuple is of the form...</span>
<span class="c"># (keyword, is_mandatory)</span>

<span class="n">KEY_CERTIFICATE_PARAMS</span> <span class="o">=</span> <span class="p">(</span>
  <span class="p">(</span><span class="s">&#39;dir-key-certificate-version&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-address&#39;</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;fingerprint&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-identity-key&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-key-published&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-key-expires&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-signing-key&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-key-crosscert&#39;</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
  <span class="p">(</span><span class="s">&#39;dir-key-certification&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
<span class="p">)</span>


<span class="k">def</span> <span class="nf">_parse_file</span><span class="p">(</span><span class="n">document_file</span><span class="p">,</span> <span class="n">document_type</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">is_microdescriptor</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">document_handler</span> <span class="o">=</span> <span class="n">DocumentHandler</span><span class="o">.</span><span class="n">ENTRIES</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Parses a network status and iterates over the RouterStatusEntry in it. The</span>
<span class="sd">  document that these instances reference have an empty &#39;routers&#39; attribute to</span>
<span class="sd">  allow for limited memory usage.</span>

<span class="sd">  :param file document_file: file with network status document content</span>
<span class="sd">  :param class document_type: NetworkStatusDocument subclass</span>
<span class="sd">  :param bool validate: checks the validity of the document&#39;s contents if</span>
<span class="sd">    **True**, skips these checks otherwise</span>
<span class="sd">  :param bool is_microdescriptor: **True** if this is for a microdescriptor</span>
<span class="sd">    consensus, **False** otherwise</span>
<span class="sd">  :param stem.descriptor.__init__.DocumentHandler document_handler: method in</span>
<span class="sd">    which to parse :class:`~stem.descriptor.networkstatus.NetworkStatusDocument`</span>
<span class="sd">  :param dict kwargs: additional arguments for the descriptor constructor</span>

<span class="sd">  :returns: :class:`stem.descriptor.networkstatus.NetworkStatusDocument` object</span>

<span class="sd">  :raises:</span>
<span class="sd">    * **ValueError** if the document_version is unrecognized or the contents is</span>
<span class="sd">      malformed and validate is **True**</span>
<span class="sd">    * **IOError** if the file can&#39;t be read</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="c"># we can&#39;t properly default this since NetworkStatusDocumentV3 isn&#39;t defined yet</span>

  <span class="k">if</span> <span class="n">document_type</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">document_type</span> <span class="o">=</span> <span class="n">NetworkStatusDocumentV3</span>

  <span class="k">if</span> <span class="n">document_type</span> <span class="o">==</span> <span class="n">NetworkStatusDocumentV2</span><span class="p">:</span>
    <span class="n">document_type</span> <span class="o">=</span> <span class="n">NetworkStatusDocumentV2</span>
    <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV2</span>
  <span class="k">elif</span> <span class="n">document_type</span> <span class="o">==</span> <span class="n">NetworkStatusDocumentV3</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">is_microdescriptor</span><span class="p">:</span>
      <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV3</span>
    <span class="k">else</span><span class="p">:</span>
      <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryMicroV3</span>
  <span class="k">elif</span> <span class="n">document_type</span> <span class="o">==</span> <span class="n">BridgeNetworkStatusDocument</span><span class="p">:</span>
    <span class="n">document_type</span> <span class="o">=</span> <span class="n">BridgeNetworkStatusDocument</span>
    <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV2</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Document type </span><span class="si">%i</span><span class="s"> isn&#39;t recognized (only able to parse v2, v3, and bridge)&quot;</span> <span class="o">%</span> <span class="n">document_type</span><span class="p">)</span>

  <span class="k">if</span> <span class="n">document_handler</span> <span class="o">==</span> <span class="n">DocumentHandler</span><span class="o">.</span><span class="n">DOCUMENT</span><span class="p">:</span>
    <span class="k">yield</span> <span class="n">document_type</span><span class="p">(</span><span class="n">document_file</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span> <span class="n">validate</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
    <span class="k">return</span>

  <span class="c"># getting the document without the routers section</span>

  <span class="n">header</span> <span class="o">=</span> <span class="n">_read_until_keywords</span><span class="p">((</span><span class="n">ROUTERS_START</span><span class="p">,</span> <span class="n">FOOTER_START</span><span class="p">,</span> <span class="n">V2_FOOTER_START</span><span class="p">),</span> <span class="n">document_file</span><span class="p">)</span>

  <span class="n">routers_start</span> <span class="o">=</span> <span class="n">document_file</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
  <span class="n">_read_until_keywords</span><span class="p">((</span><span class="n">FOOTER_START</span><span class="p">,</span> <span class="n">V2_FOOTER_START</span><span class="p">),</span> <span class="n">document_file</span><span class="p">,</span> <span class="n">skip</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
  <span class="n">routers_end</span> <span class="o">=</span> <span class="n">document_file</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>

  <span class="n">footer</span> <span class="o">=</span> <span class="n">document_file</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
  <span class="n">document_content</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">b</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">header</span> <span class="o">+</span> <span class="n">footer</span><span class="p">)</span>

  <span class="k">if</span> <span class="n">document_handler</span> <span class="o">==</span> <span class="n">DocumentHandler</span><span class="o">.</span><span class="n">BARE_DOCUMENT</span><span class="p">:</span>
    <span class="k">yield</span> <span class="n">document_type</span><span class="p">(</span><span class="n">document_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  <span class="k">elif</span> <span class="n">document_handler</span> <span class="o">==</span> <span class="n">DocumentHandler</span><span class="o">.</span><span class="n">ENTRIES</span><span class="p">:</span>
    <span class="n">desc_iterator</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span>
      <span class="n">document_file</span><span class="p">,</span>
      <span class="n">validate</span><span class="p">,</span>
      <span class="n">entry_class</span> <span class="o">=</span> <span class="n">router_type</span><span class="p">,</span>
      <span class="n">entry_keyword</span> <span class="o">=</span> <span class="n">ROUTERS_START</span><span class="p">,</span>
      <span class="n">start_position</span> <span class="o">=</span> <span class="n">routers_start</span><span class="p">,</span>
      <span class="n">end_position</span> <span class="o">=</span> <span class="n">routers_end</span><span class="p">,</span>
      <span class="n">extra_args</span> <span class="o">=</span> <span class="p">(</span><span class="n">document_type</span><span class="p">(</span><span class="n">document_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">),),</span>
      <span class="o">**</span><span class="n">kwargs</span>
    <span class="p">)</span>

    <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">desc_iterator</span><span class="p">:</span>
      <span class="k">yield</span> <span class="n">desc</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Unrecognized document_handler: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">document_handler</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">_parse_file_key_certs</span><span class="p">(</span><span class="n">certificate_file</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Parses a file containing one or more authority key certificates.</span>

<span class="sd">  :param file certificate_file: file with key certificates</span>
<span class="sd">  :param bool validate: checks the validity of the certificate&#39;s contents if</span>
<span class="sd">    **True**, skips these checks otherwise</span>

<span class="sd">  :returns: iterator for :class:`stem.descriptor.networkstatus.KeyCertificate`</span>
<span class="sd">    instance in the file</span>

<span class="sd">  :raises:</span>
<span class="sd">    * **ValueError** if the key certificate content is invalid and validate is</span>
<span class="sd">      **True**</span>
<span class="sd">    * **IOError** if the file can&#39;t be read</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">keycert_content</span> <span class="o">=</span> <span class="n">_read_until_keywords</span><span class="p">(</span><span class="s">&quot;dir-key-certification&quot;</span><span class="p">,</span> <span class="n">certificate_file</span><span class="p">)</span>

    <span class="c"># we&#39;ve reached the &#39;router-signature&#39;, now include the pgp style block</span>
    <span class="n">block_end_prefix</span> <span class="o">=</span> <span class="n">PGP_BLOCK_END</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39; &#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">keycert_content</span> <span class="o">+=</span> <span class="n">_read_until_keywords</span><span class="p">(</span><span class="n">block_end_prefix</span><span class="p">,</span> <span class="n">certificate_file</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">keycert_content</span><span class="p">:</span>
      <span class="k">yield</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">networkstatus</span><span class="o">.</span><span class="n">KeyCertificate</span><span class="p">(</span><span class="nb">bytes</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">b</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">keycert_content</span><span class="p">),</span> <span class="n">validate</span> <span class="o">=</span> <span class="n">validate</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
      <span class="k">break</span>  <span class="c"># done parsing file</span>


<div class="viewcode-block" id="NetworkStatusDocument"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.NetworkStatusDocument">[docs]</a><span class="k">class</span> <span class="nc">NetworkStatusDocument</span><span class="p">(</span><span class="n">Descriptor</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Common parent for network status documents.</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">):</span>
    <span class="nb">super</span><span class="p">(</span><span class="n">NetworkStatusDocument</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">=</span> <span class="p">[]</span>

<div class="viewcode-block" id="NetworkStatusDocument.get_unrecognized_lines"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.NetworkStatusDocument.get_unrecognized_lines">[docs]</a>  <span class="k">def</span> <span class="nf">get_unrecognized_lines</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span><span class="p">)</span>

</div></div>
<div class="viewcode-block" id="NetworkStatusDocumentV2"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.NetworkStatusDocumentV2">[docs]</a><span class="k">class</span> <span class="nc">NetworkStatusDocumentV2</span><span class="p">(</span><span class="n">NetworkStatusDocument</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Version 2 network status document. These have been deprecated and are no</span>
<span class="sd">  longer generated by Tor.</span>

<span class="sd">  :var dict routers: fingerprints to :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV2`</span>
<span class="sd">    contained in the document</span>

<span class="sd">  :var int version: **\*** document version</span>

<span class="sd">  :var str hostname: **\*** hostname of the authority</span>
<span class="sd">  :var str address: **\*** authority&#39;s IP address</span>
<span class="sd">  :var int dir_port: **\*** authority&#39;s DirPort</span>
<span class="sd">  :var str fingerprint: **\*** authority&#39;s fingerprint</span>
<span class="sd">  :var str contact: **\*** authority&#39;s contact information</span>
<span class="sd">  :var str signing_key: **\*** authority&#39;s public signing key</span>

<span class="sd">  :var list client_versions: list of recommended client tor version strings</span>
<span class="sd">  :var list server_versions: list of recommended server tor version strings</span>
<span class="sd">  :var datetime published: **\*** time when the document was published</span>
<span class="sd">  :var list options: **\*** list of things that this authority decides</span>

<span class="sd">  :var str signing_authority: **\*** name of the authority signing the document</span>
<span class="sd">  :var str signature: **\*** authority&#39;s signature for the document</span>

<span class="sd">  **\*** attribute is either required when we&#39;re parsed with validation or has</span>
<span class="sd">  a default value, others are left as **None** if undefined</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="nb">super</span><span class="p">(</span><span class="n">NetworkStatusDocumentV2</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">hostname</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">contact</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">signing_key</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">client_versions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">server_versions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">signing_authority</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">signatures</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="c"># Splitting the document from the routers. Unlike v3 documents we&#39;re not</span>
    <span class="c"># bending over backwards on the validation by checking the field order or</span>
    <span class="c"># that header/footer attributes aren&#39;t in the wrong section. This is a</span>
    <span class="c"># deprecated descriptor type - patches welcome if you want those checks.</span>

    <span class="n">document_file</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="n">document_content</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">b</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">_read_until_keywords</span><span class="p">((</span><span class="n">ROUTERS_START</span><span class="p">,</span> <span class="n">V2_FOOTER_START</span><span class="p">),</span> <span class="n">document_file</span><span class="p">))</span>

    <span class="n">router_iter</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span>
      <span class="n">document_file</span><span class="p">,</span>
      <span class="n">validate</span><span class="p">,</span>
      <span class="n">entry_class</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV2</span><span class="p">,</span>
      <span class="n">entry_keyword</span> <span class="o">=</span> <span class="n">ROUTERS_START</span><span class="p">,</span>
      <span class="n">section_end_keywords</span> <span class="o">=</span> <span class="p">(</span><span class="n">V2_FOOTER_START</span><span class="p">,),</span>
      <span class="n">extra_args</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="p">,),</span>
    <span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">routers</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">desc</span><span class="o">.</span><span class="n">fingerprint</span><span class="p">,</span> <span class="n">desc</span><span class="p">)</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">router_iter</span><span class="p">)</span>

    <span class="n">document_content</span> <span class="o">+=</span> <span class="n">b</span><span class="s">&quot;</span><span class="se">\n</span><span class="s">&quot;</span> <span class="o">+</span> <span class="n">document_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
    <span class="n">document_content</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">document_content</span><span class="p">)</span>

    <span class="n">entries</span> <span class="o">=</span> <span class="n">_get_descriptor_components</span><span class="p">(</span><span class="n">document_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="bp">self</span><span class="o">.</span><span class="n">_check_constraints</span><span class="p">(</span><span class="n">entries</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_parse</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">_parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="n">value</span><span class="p">,</span> <span class="n">block_contents</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

      <span class="n">line</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>  <span class="c"># original line</span>

      <span class="k">if</span> <span class="n">block_contents</span><span class="p">:</span>
        <span class="n">line</span> <span class="o">+=</span> <span class="s">&quot;</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">block_contents</span>

      <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;network-status-version&quot;</span><span class="p">:</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">value</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document has a non-numeric version: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Expected a version 2 network status document, got version &#39;</span><span class="si">%s</span><span class="s">&#39; instead&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;dir-source&quot;</span><span class="p">:</span>
        <span class="n">dir_source_comp</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;The &#39;dir-source&#39; line of a v2 network status document must have three values: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="c"># https://trac.torproject.org/7055</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s hostname can&#39;t be blank: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_ipv4_address</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s address isn&#39;t a valid IPv4 address: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">allow_zero</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s DirPort is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="k">continue</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">hostname</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">if</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;0&#39;</span> <span class="k">else</span> <span class="nb">int</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;fingerprint&quot;</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s fingerprint in a v2 network status document is malformed: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;contact&quot;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">contact</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;dir-signing-key&quot;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">signing_key</span> <span class="o">=</span> <span class="n">block_contents</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&quot;client-versions&quot;</span><span class="p">,</span> <span class="s">&quot;server-versions&quot;</span><span class="p">):</span>
        <span class="c"># v2 documents existed while there were tor versions using the &#39;old&#39;</span>
        <span class="c"># style, hence we aren&#39;t attempting to parse them</span>

        <span class="k">for</span> <span class="n">version_str</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;,&quot;</span><span class="p">):</span>
          <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;client-versions&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">client_versions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">version_str</span><span class="p">)</span>
          <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;server-versions&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">server_versions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">version_str</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;published&quot;</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S&quot;</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
          <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Version 2 network status document&#39;s &#39;published&#39; time wasn&#39;t parsable: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;dir-options&quot;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;directory-signature&quot;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">signing_authority</span> <span class="o">=</span> <span class="n">value</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">signature</span> <span class="o">=</span> <span class="n">block_contents</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

    <span class="c"># &#39;client-versions&#39; and &#39;server-versions&#39; are only required if &quot;Versions&quot;</span>
    <span class="c"># is among the options</span>

    <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="s">&quot;Versions&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="p">:</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="s">&#39;client-versions&#39;</span> <span class="ow">in</span> <span class="n">entries</span> <span class="ow">and</span> <span class="s">&#39;server-versions&#39;</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Version 2 network status documents must have a &#39;client-versions&#39; and &#39;server-versions&#39; when &#39;Versions&#39; is listed among its dir-options:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>

  <span class="k">def</span> <span class="nf">_check_constraints</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entries</span><span class="p">):</span>
    <span class="n">required_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">is_mandatory</span><span class="p">)</span> <span class="ow">in</span> <span class="n">NETWORK_STATUS_V2_FIELDS</span> <span class="k">if</span> <span class="n">is_mandatory</span><span class="p">]</span>
    <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">required_fields</span><span class="p">:</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document (v2) must have a &#39;</span><span class="si">%s</span><span class="s">&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)))</span>

    <span class="c"># all recognized fields can only appear once</span>
    <span class="n">single_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="n">NETWORK_STATUS_V2_FIELDS</span><span class="p">]</span>
    <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">single_fields</span><span class="p">:</span>
      <span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">entries</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">entries</span><span class="p">[</span><span class="n">keyword</span><span class="p">])</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document (v2) can only have a single &#39;</span><span class="si">%s</span><span class="s">&#39; line, got </span><span class="si">%i</span><span class="s">:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">entries</span><span class="p">[</span><span class="n">keyword</span><span class="p">]),</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)))</span>

    <span class="k">if</span> <span class="s">&#39;network-status-version&#39;</span> <span class="o">!=</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]:</span>
      <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document (v2) are expected to start with a &#39;network-status-version&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>

</div>
<div class="viewcode-block" id="NetworkStatusDocumentV3"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.NetworkStatusDocumentV3">[docs]</a><span class="k">class</span> <span class="nc">NetworkStatusDocumentV3</span><span class="p">(</span><span class="n">NetworkStatusDocument</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Version 3 network status document. This could be either a vote or consensus.</span>

<span class="sd">  :var tuple routers: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`</span>
<span class="sd">    contained in the document</span>

<span class="sd">  :var int version: **\*** document version</span>
<span class="sd">  :var str version_flavor: **\*** flavor associated with the document (such as &#39;microdesc&#39;)</span>
<span class="sd">  :var bool is_consensus: **\*** **True** if the document is a consensus</span>
<span class="sd">  :var bool is_vote: **\*** **True** if the document is a vote</span>
<span class="sd">  :var bool is_microdescriptor: **\*** **True** if this is a microdescriptor</span>
<span class="sd">    flavored document, **False** otherwise</span>
<span class="sd">  :var datetime valid_after: **\*** time when the consensus became valid</span>
<span class="sd">  :var datetime fresh_until: **\*** time when the next consensus should be produced</span>
<span class="sd">  :var datetime valid_until: **\*** time when this consensus becomes obsolete</span>
<span class="sd">  :var int vote_delay: **\*** number of seconds allowed for collecting votes</span>
<span class="sd">    from all authorities</span>
<span class="sd">  :var int dist_delay: **\*** number of seconds allowed for collecting</span>
<span class="sd">    signatures from all authorities</span>
<span class="sd">  :var list client_versions: list of recommended client tor versions</span>
<span class="sd">  :var list server_versions: list of recommended server tor versions</span>
<span class="sd">  :var list known_flags: **\*** list of :data:`~stem.Flag` for the router&#39;s flags</span>
<span class="sd">  :var dict params: **\*** dict of parameter(**str**) =&gt; value(**int**) mappings</span>
<span class="sd">  :var list directory_authorities: **\*** list of :class:`~stem.descriptor.networkstatus.DirectoryAuthority`</span>
<span class="sd">    objects that have generated this document</span>
<span class="sd">  :var list signatures: **\*** :class:`~stem.descriptor.networkstatus.DocumentSignature`</span>
<span class="sd">    of the authorities that have signed the document</span>

<span class="sd">  **Consensus Attributes:**</span>

<span class="sd">  :var int consensus_method: method version used to generate this consensus</span>
<span class="sd">  :var dict bandwidth_weights: dict of weight(str) =&gt; value(int) mappings</span>

<span class="sd">  **Vote Attributes:**</span>

<span class="sd">  :var list consensus_methods: list of ints for the supported method versions</span>
<span class="sd">  :var datetime published: time when the document was published</span>
<span class="sd">  :var dict flag_thresholds: **\*** mapping of internal performance thresholds used while making the vote, values are **ints** or **floats**</span>

<span class="sd">  **\*** attribute is either required when we&#39;re parsed with validation or has</span>
<span class="sd">  a default value, others are left as None if undefined</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">default_params</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Parse a v3 network status document.</span>

<span class="sd">    :param str raw_content: raw network status document data</span>
<span class="sd">    :param bool validate: **True** if the document is to be validated, **False** otherwise</span>
<span class="sd">    :param bool default_params: includes defaults in our params dict, otherwise</span>
<span class="sd">      it just contains values from the document</span>

<span class="sd">    :raises: **ValueError** if the document is invalid</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nb">super</span><span class="p">(</span><span class="n">NetworkStatusDocumentV3</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="n">document_file</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_header</span> <span class="o">=</span> <span class="n">_DocumentHeader</span><span class="p">(</span><span class="n">document_file</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">default_params</span><span class="p">)</span>

    <span class="c"># merge header attributes into us</span>
    <span class="k">for</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">vars</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="p">)</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="k">if</span> <span class="n">attr</span> <span class="o">!=</span> <span class="s">&quot;_unrecognized_lines&quot;</span><span class="p">:</span>
        <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">+=</span> <span class="n">value</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">directory_authorities</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span>
      <span class="n">document_file</span><span class="p">,</span>
      <span class="n">validate</span><span class="p">,</span>
      <span class="n">entry_class</span> <span class="o">=</span> <span class="n">DirectoryAuthority</span><span class="p">,</span>
      <span class="n">entry_keyword</span> <span class="o">=</span> <span class="n">AUTH_START</span><span class="p">,</span>
      <span class="n">section_end_keywords</span> <span class="o">=</span> <span class="p">(</span><span class="n">ROUTERS_START</span><span class="p">,</span> <span class="n">FOOTER_START</span><span class="p">,</span> <span class="n">V2_FOOTER_START</span><span class="p">),</span>
      <span class="n">extra_args</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="o">.</span><span class="n">is_vote</span><span class="p">,),</span>
    <span class="p">))</span>

    <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="o">.</span><span class="n">is_vote</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">directory_authorities</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
      <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Votes should only have an authority entry for the one that issued it, got </span><span class="si">%i</span><span class="s">: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">directory_authorities</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">directory_authorities</span><span class="p">))</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="o">.</span><span class="n">is_microdescriptor</span><span class="p">:</span>
      <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV3</span>
    <span class="k">else</span><span class="p">:</span>
      <span class="n">router_type</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryMicroV3</span>

    <span class="n">router_iter</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span>
      <span class="n">document_file</span><span class="p">,</span>
      <span class="n">validate</span><span class="p">,</span>
      <span class="n">entry_class</span> <span class="o">=</span> <span class="n">router_type</span><span class="p">,</span>
      <span class="n">entry_keyword</span> <span class="o">=</span> <span class="n">ROUTERS_START</span><span class="p">,</span>
      <span class="n">section_end_keywords</span> <span class="o">=</span> <span class="p">(</span><span class="n">FOOTER_START</span><span class="p">,</span> <span class="n">V2_FOOTER_START</span><span class="p">),</span>
      <span class="n">extra_args</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="p">,),</span>
    <span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">routers</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">desc</span><span class="o">.</span><span class="n">fingerprint</span><span class="p">,</span> <span class="n">desc</span><span class="p">)</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">router_iter</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_footer</span> <span class="o">=</span> <span class="n">_DocumentFooter</span><span class="p">(</span><span class="n">document_file</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="p">)</span>

    <span class="c"># merge header attributes into us</span>
    <span class="k">for</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">vars</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_footer</span><span class="p">)</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="k">if</span> <span class="n">attr</span> <span class="o">!=</span> <span class="s">&quot;_unrecognized_lines&quot;</span><span class="p">:</span>
        <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">+=</span> <span class="n">value</span>

<div class="viewcode-block" id="NetworkStatusDocumentV3.meets_consensus_method"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.NetworkStatusDocumentV3.meets_consensus_method">[docs]</a>  <span class="k">def</span> <span class="nf">meets_consensus_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Checks if we meet the given consensus-method. This works for both votes and</span>
<span class="sd">    consensuses, checking our &#39;consensus-method&#39; and &#39;consensus-methods&#39;</span>
<span class="sd">    entries.</span>

<span class="sd">    :param int method: consensus-method to check for</span>

<span class="sd">    :returns: **True** if we meet the given consensus-method, and **False** otherwise</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_header</span><span class="o">.</span><span class="n">meets_consensus_method</span><span class="p">(</span><span class="n">method</span><span class="p">)</span>
</div>
  <span class="k">def</span> <span class="nf">_compare</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">NetworkStatusDocumentV3</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">False</span>

    <span class="k">return</span> <span class="n">method</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="nb">str</span><span class="p">(</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>

  <span class="k">def</span> <span class="nf">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>

  <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">==</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">o</span><span class="p">)</span>

</div>
<span class="k">class</span> <span class="nc">_DocumentHeader</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">document_file</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">default_params</span><span class="p">):</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">version_flavor</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">is_consensus</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">is_vote</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">is_microdescriptor</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">consensus_method</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">valid_after</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">fresh_until</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">valid_until</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">vote_delay</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">dist_delay</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">client_versions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">server_versions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">known_flags</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">flag_thresholds</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">params</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">DEFAULT_PARAMS</span><span class="p">)</span> <span class="k">if</span> <span class="n">default_params</span> <span class="k">else</span> <span class="p">{}</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="n">content</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">b</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">_read_until_keywords</span><span class="p">((</span><span class="n">AUTH_START</span><span class="p">,</span> <span class="n">ROUTERS_START</span><span class="p">,</span> <span class="n">FOOTER_START</span><span class="p">),</span> <span class="n">document_file</span><span class="p">))</span>
    <span class="n">content</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
    <span class="n">entries</span> <span class="o">=</span> <span class="n">_get_descriptor_components</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">_parse</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

    <span class="c"># doing this validation afterward so we know our &#39;is_consensus&#39; and</span>
    <span class="c"># &#39;is_vote&#39; attributes</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="n">_check_for_missing_and_disallowed_fields</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">HEADER_STATUS_DOCUMENT_FIELDS</span><span class="p">)</span>
      <span class="n">_check_for_misordered_fields</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">HEADER_FIELDS</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">meets_consensus_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">consensus_method</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
      <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">consensus_method</span> <span class="o">&gt;=</span> <span class="n">method</span>
    <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
      <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&gt;=</span> <span class="n">method</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span><span class="p">))</span>
    <span class="k">else</span><span class="p">:</span>
      <span class="k">return</span> <span class="bp">False</span>  <span class="c"># malformed document</span>

  <span class="k">def</span> <span class="nf">_parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="n">value</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
      <span class="n">line</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

      <span class="c"># all known header fields can only appear once except</span>
      <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">HEADER_FIELDS</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status documents can only have a single &#39;</span><span class="si">%s</span><span class="s">&#39; line, got </span><span class="si">%i</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)))</span>

      <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;network-status-version&#39;</span><span class="p">:</span>
        <span class="c"># &quot;network-status-version&quot; version</span>

        <span class="k">if</span> <span class="s">&#39; &#39;</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
          <span class="n">version</span><span class="p">,</span> <span class="n">flavor</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39; &#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
          <span class="n">version</span><span class="p">,</span> <span class="n">flavor</span> <span class="o">=</span> <span class="n">value</span><span class="p">,</span> <span class="bp">None</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">version</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document has a non-numeric version: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">version_flavor</span> <span class="o">=</span> <span class="n">flavor</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">is_microdescriptor</span> <span class="o">=</span> <span class="n">flavor</span> <span class="o">==</span> <span class="s">&#39;microdesc&#39;</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Expected a version 3 network status document, got version &#39;</span><span class="si">%s</span><span class="s">&#39; instead&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;vote-status&#39;</span><span class="p">:</span>
        <span class="c"># &quot;vote-status&quot; type</span>
        <span class="c">#</span>
        <span class="c"># The consensus-method and consensus-methods fields are optional since</span>
        <span class="c"># they weren&#39;t included in version 1. Setting a default now that we</span>
        <span class="c"># know if we&#39;re a vote or not.</span>

        <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="s">&#39;consensus&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">is_consensus</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_vote</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">consensus_method</span> <span class="o">=</span> <span class="mi">1</span>
        <span class="k">elif</span> <span class="n">value</span> <span class="o">==</span> <span class="s">&#39;vote&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">is_consensus</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_vote</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
        <span class="k">elif</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s vote-status line can only be &#39;consensus&#39; or &#39;vote&#39;, got &#39;</span><span class="si">%s</span><span class="s">&#39; instead&quot;</span> <span class="o">%</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;consensus-methods&#39;</span><span class="p">:</span>
        <span class="c"># &quot;consensus-methods&quot; IntegerList</span>

        <span class="n">consensus_methods</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">):</span>
          <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
            <span class="n">consensus_methods</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">entry</span><span class="p">))</span>
          <span class="k">elif</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s consensus-methods must be a list of integer values, but was &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="n">value</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span> <span class="o">=</span> <span class="n">consensus_methods</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="p">(</span><span class="mi">1</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">consensus_methods</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status votes must include consensus-method version 1&quot;</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;consensus-method&#39;</span><span class="p">:</span>
        <span class="c"># &quot;consensus-method&quot; Integer</span>

        <span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">consensus_method</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s consensus-method must be an integer, but was &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;published&#39;</span><span class="p">,</span> <span class="s">&#39;valid-after&#39;</span><span class="p">,</span> <span class="s">&#39;fresh-until&#39;</span><span class="p">,</span> <span class="s">&#39;valid-until&#39;</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
          <span class="n">date_value</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S&quot;</span><span class="p">)</span>

          <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;published&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="n">date_value</span>
          <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;valid-after&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">valid_after</span> <span class="o">=</span> <span class="n">date_value</span>
          <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;fresh-until&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">fresh_until</span> <span class="o">=</span> <span class="n">date_value</span>
          <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;valid-until&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">valid_until</span> <span class="o">=</span> <span class="n">date_value</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
          <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; time wasn&#39;t parsable: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;voting-delay&quot;</span><span class="p">:</span>
        <span class="c"># &quot;voting-delay&quot; VoteSeconds DistSeconds</span>

        <span class="n">value_comp</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39; &#39;</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">value_comp</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span> <span class="ow">and</span> <span class="n">value_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()</span> <span class="ow">and</span> <span class="n">value_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">vote_delay</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">dist_delay</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
        <span class="k">elif</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s &#39;voting-delay&#39; line must be a pair of integer values, but was &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="n">value</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&quot;client-versions&quot;</span><span class="p">,</span> <span class="s">&quot;server-versions&quot;</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;,&quot;</span><span class="p">):</span>
          <span class="k">try</span><span class="p">:</span>
            <span class="n">version_value</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">_get_version</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;client-versions&#39;</span><span class="p">:</span>
              <span class="bp">self</span><span class="o">.</span><span class="n">client_versions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">version_value</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;server-versions&#39;</span><span class="p">:</span>
              <span class="bp">self</span><span class="o">.</span><span class="n">server_versions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">version_value</span><span class="p">)</span>
          <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
              <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; line had &#39;</span><span class="si">%s</span><span class="s">&#39;, which isn&#39;t a parsable tor version: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">entry</span><span class="p">,</span> <span class="n">line</span><span class="p">))</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;known-flags&quot;</span><span class="p">:</span>
        <span class="c"># &quot;known-flags&quot; FlagList</span>

        <span class="c"># simply fetches the entries, excluding empty strings</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">known_flags</span> <span class="o">=</span> <span class="p">[</span><span class="n">entry</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">entry</span><span class="p">]</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;flag-thresholds&quot;</span><span class="p">:</span>
        <span class="c"># &quot;flag-thresholds&quot; SP THRESHOLDS</span>

        <span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>

        <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
          <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">):</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="s">&#39;=&#39;</span> <span class="ow">in</span> <span class="n">entry</span><span class="p">:</span>
              <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
                <span class="k">continue</span>

              <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; line is expected to be space separated key=value mappings, got: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">line</span><span class="p">))</span>

            <span class="n">entry_key</span><span class="p">,</span> <span class="n">entry_value</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;=&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

            <span class="k">try</span><span class="p">:</span>
              <span class="k">if</span> <span class="n">entry_value</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;%&quot;</span><span class="p">):</span>
                <span class="c"># opting for string manipulation rather than just</span>
                <span class="c"># &#39;float(entry_value) / 100&#39; because floating point arithmetic</span>
                <span class="c"># will lose precision</span>

                <span class="bp">self</span><span class="o">.</span><span class="n">flag_thresholds</span><span class="p">[</span><span class="n">entry_key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s">&quot;0.&quot;</span> <span class="o">+</span> <span class="n">entry_value</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;.&#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
              <span class="k">elif</span> <span class="s">&#39;.&#39;</span> <span class="ow">in</span> <span class="n">entry_value</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">flag_thresholds</span><span class="p">[</span><span class="n">entry_key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">entry_value</span><span class="p">)</span>
              <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">flag_thresholds</span><span class="p">[</span><span class="n">entry_key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">entry_value</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
              <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; line is expected to have float values, got: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">line</span><span class="p">))</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;params&quot;</span><span class="p">:</span>
        <span class="c"># &quot;params&quot; [Parameters]</span>
        <span class="c"># Parameter ::= Keyword &#39;=&#39; Int32</span>
        <span class="c"># Int32 ::= A decimal integer between -2147483648 and 2147483647.</span>
        <span class="c"># Parameters ::= Parameter | Parameters SP Parameter</span>

        <span class="c"># should only appear in consensus-method 7 or later</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">meets_consensus_method</span><span class="p">(</span><span class="mi">7</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s &#39;params&#39; line should only appear in consensus-method 7 or later&quot;</span><span class="p">)</span>

        <span class="c"># skip if this is a blank line</span>

        <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="s">&quot;&quot;</span><span class="p">:</span>
          <span class="k">continue</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">_parse_int_mappings</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">validate</span><span class="p">))</span>

        <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">_check_params_constraints</span><span class="p">()</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">_check_params_constraints</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Checks that the params we know about are within their documented ranges.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="c"># all parameters are constrained to int32 range</span>
      <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2147483648</span><span class="p">,</span> <span class="mi">2147483647</span>

      <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;circwindow&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1000</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;CircuitPriorityHalflifeMsec&quot;</span><span class="p">:</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&quot;perconnbwrate&quot;</span><span class="p">,</span> <span class="s">&quot;perconnbwburst&quot;</span><span class="p">):</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;refuseunknownexits&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;bwweightscale&quot;</span><span class="p">:</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtdisabled&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtnummodes&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">20</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtrecentcount&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1000</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtmaxtimeouts&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">10000</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtmincircs&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10000</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtquantile&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">99</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtclosequantile&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;cbtquantile&quot;</span><span class="p">,</span> <span class="n">minimum</span><span class="p">),</span> <span class="mi">99</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbttestfreq&quot;</span><span class="p">:</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtmintimeout&quot;</span><span class="p">:</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="mi">500</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;cbtinitialtimeout&quot;</span><span class="p">:</span>
        <span class="n">minimum</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;cbtmintimeout&quot;</span><span class="p">,</span> <span class="n">minimum</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;UseOptimisticData&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
      <span class="k">elif</span> <span class="n">key</span> <span class="o">==</span> <span class="s">&quot;Support022HiddenServices&quot;</span><span class="p">:</span>
        <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>

      <span class="k">if</span> <span class="n">value</span> <span class="o">&lt;</span> <span class="n">minimum</span> <span class="ow">or</span> <span class="n">value</span> <span class="o">&gt;</span> <span class="n">maximum</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;&#39;</span><span class="si">%s</span><span class="s">&#39; value on the params line must be in the range of </span><span class="si">%i</span><span class="s"> - </span><span class="si">%i</span><span class="s">, was </span><span class="si">%i</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">minimum</span><span class="p">,</span> <span class="n">maximum</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>


<span class="k">class</span> <span class="nc">_DocumentFooter</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">document_file</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">header</span><span class="p">):</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">signatures</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">bandwidth_weights</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="n">content</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">document_file</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">content</span><span class="p">:</span>
      <span class="k">return</span>  <span class="c"># footer is optional and there&#39;s nothing to parse</span>

    <span class="n">entries</span> <span class="o">=</span> <span class="n">_get_descriptor_components</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">_parse</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">header</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="c"># Check that the footer has the right initial line. Prior to consensus</span>
      <span class="c"># method 9 it&#39;s a &#39;directory-signature&#39; and after that footers start with</span>
      <span class="c"># &#39;directory-footer&#39;.</span>

      <span class="k">if</span> <span class="n">header</span><span class="o">.</span><span class="n">meets_consensus_method</span><span class="p">(</span><span class="mi">9</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s">&#39;directory-footer&#39;</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s footer should start with a &#39;directory-footer&#39; line in consensus-method 9 or later&quot;</span><span class="p">)</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s">&#39;directory-signature&#39;</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document&#39;s footer should start with a &#39;directory-signature&#39; line prior to consensus-method 9&quot;</span><span class="p">)</span>

      <span class="n">_check_for_missing_and_disallowed_fields</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">FOOTER_STATUS_DOCUMENT_FIELDS</span><span class="p">)</span>
      <span class="n">_check_for_misordered_fields</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">FOOTER_FIELDS</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">_parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">header</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="n">value</span><span class="p">,</span> <span class="n">block_contents</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
      <span class="n">line</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

      <span class="c"># all known footer fields can only appear once except...</span>
      <span class="c"># * &#39;directory-signature&#39; in a consensus</span>

      <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">FOOTER_FIELDS</span><span class="p">:</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;directory-signature&#39;</span> <span class="ow">and</span> <span class="n">header</span><span class="o">.</span><span class="n">is_consensus</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status documents can only have a single &#39;</span><span class="si">%s</span><span class="s">&#39; line, got </span><span class="si">%i</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)))</span>

      <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;directory-footer&quot;</span><span class="p">:</span>
        <span class="c"># nothing to parse, simply checking that we don&#39;t have a value</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="n">value</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;A network status document&#39;s &#39;directory-footer&#39; line shouldn&#39;t have any content, got &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;bandwidth-weights&quot;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bandwidth_weights</span> <span class="o">=</span> <span class="n">_parse_int_mappings</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&quot;directory-signature&quot;</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">sig_value</span><span class="p">,</span> <span class="n">block_contents</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">sig_value</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">)</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">block_contents</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
              <span class="k">continue</span>

            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority signatures in a network status document are expected to be of the form &#39;directory-signature [METHOD] FINGERPRINT KEY_DIGEST</span><span class="se">\\</span><span class="s">nSIGNATURE&#39;, got:</span><span class="se">\n</span><span class="si">%s</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sig_value</span><span class="p">,</span> <span class="n">block_contents</span><span class="p">))</span>

          <span class="k">if</span> <span class="n">sig_value</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="n">method</span> <span class="o">=</span> <span class="s">&#39;sha1&#39;</span>  <span class="c"># default if none was provided</span>
            <span class="n">fingerprint</span><span class="p">,</span> <span class="n">key_digest</span> <span class="o">=</span> <span class="n">sig_value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
          <span class="k">else</span><span class="p">:</span>
            <span class="n">method</span><span class="p">,</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">key_digest</span> <span class="o">=</span> <span class="n">sig_value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>

          <span class="bp">self</span><span class="o">.</span><span class="n">signatures</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">DocumentSignature</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">key_digest</span><span class="p">,</span> <span class="n">block_contents</span><span class="p">,</span> <span class="n">validate</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">_check_for_missing_and_disallowed_fields</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">entries</span><span class="p">,</span> <span class="n">fields</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Checks that we have mandatory fields for our type, and that we don&#39;t have</span>
<span class="sd">  any fields exclusive to the other (ie, no vote-only fields appear in a</span>
<span class="sd">  consensus or vice versa).</span>

<span class="sd">  :param _DocumentHeader header: document header</span>
<span class="sd">  :param dict entries: ordered keyword/value mappings of the header or footer</span>
<span class="sd">  :param list fields: expected field attributes (either</span>
<span class="sd">    **HEADER_STATUS_DOCUMENT_FIELDS** or **FOOTER_STATUS_DOCUMENT_FIELDS**)</span>

<span class="sd">  :raises: **ValueError** if we&#39;re missing mandatory fields or have fields we shouldn&#39;t</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="n">missing_fields</span><span class="p">,</span> <span class="n">disallowed_fields</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>

  <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">in_votes</span><span class="p">,</span> <span class="n">in_consensus</span><span class="p">,</span> <span class="n">mandatory</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">mandatory</span> <span class="ow">and</span> <span class="p">((</span><span class="n">header</span><span class="o">.</span><span class="n">is_consensus</span> <span class="ow">and</span> <span class="n">in_consensus</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">header</span><span class="o">.</span><span class="n">is_vote</span> <span class="ow">and</span> <span class="n">in_votes</span><span class="p">)):</span>
      <span class="c"># mandatory field, check that we have it</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
        <span class="n">missing_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field</span><span class="p">)</span>
    <span class="k">elif</span> <span class="p">(</span><span class="n">header</span><span class="o">.</span><span class="n">is_consensus</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">in_consensus</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">header</span><span class="o">.</span><span class="n">is_vote</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">in_votes</span><span class="p">):</span>
      <span class="c"># field we shouldn&#39;t have, check that we don&#39;t</span>
      <span class="k">if</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
        <span class="n">disallowed_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field</span><span class="p">)</span>

  <span class="k">if</span> <span class="n">missing_fields</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document is missing mandatory field: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">missing_fields</span><span class="p">))</span>

  <span class="k">if</span> <span class="n">disallowed_fields</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Network status document has fields that shouldn&#39;t appear in this document type or version: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">disallowed_fields</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">_check_for_misordered_fields</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">expected</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  To be valid a network status document&#39;s fiends need to appear in a specific</span>
<span class="sd">  order. Checks that known fields appear in that order (unrecognized fields</span>
<span class="sd">  are ignored).</span>

<span class="sd">  :param dict entries: ordered keyword/value mappings of the header or footer</span>
<span class="sd">  :param list expected: ordered list of expected fields (either</span>
<span class="sd">    **HEADER_FIELDS** or **FOOTER_FIELDS**)</span>

<span class="sd">  :raises: **ValueError** if entries aren&#39;t properly ordered</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="c"># Earlier validation has ensured that our fields either belong to our</span>
  <span class="c"># document type or are unknown. Remove the unknown fields since they</span>
  <span class="c"># reflect a spec change and can appear anywhere in the document.</span>

  <span class="n">actual</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">field</span><span class="p">:</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">expected</span><span class="p">,</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>

  <span class="c"># Narrow the expected to just what we have. If the lists then match then the</span>
  <span class="c"># order&#39;s valid.</span>

  <span class="n">expected</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">field</span><span class="p">:</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">actual</span><span class="p">,</span> <span class="n">expected</span><span class="p">)</span>

  <span class="k">if</span> <span class="n">actual</span> <span class="o">!=</span> <span class="n">expected</span><span class="p">:</span>
    <span class="n">actual_label</span> <span class="o">=</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">actual</span><span class="p">)</span>
    <span class="n">expected_label</span> <span class="o">=</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">expected</span><span class="p">)</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;The fields in a section of the document are misordered. It should be &#39;</span><span class="si">%s</span><span class="s">&#39; but was &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">actual_label</span><span class="p">,</span> <span class="n">expected_label</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">_parse_int_mappings</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">validate</span><span class="p">):</span>
  <span class="c"># Parse a series of &#39;key=value&#39; entries, checking the following:</span>
  <span class="c"># - values are integers</span>
  <span class="c"># - keys are sorted in lexical order</span>

  <span class="n">results</span><span class="p">,</span> <span class="n">seen_keys</span> <span class="o">=</span> <span class="p">{},</span> <span class="p">[]</span>
  <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="s">&#39;=&#39;</span> <span class="ow">in</span> <span class="n">entry</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;must only have &#39;key=value&#39; entries&quot;</span><span class="p">)</span>

      <span class="n">entry_key</span><span class="p">,</span> <span class="n">entry_value</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;=&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

      <span class="k">try</span><span class="p">:</span>
        <span class="c"># the int() function accepts things like &#39;+123&#39;, but we don&#39;t want to</span>
        <span class="k">if</span> <span class="n">entry_value</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;+&#39;</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">()</span>

        <span class="n">entry_value</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">entry_value</span><span class="p">)</span>
      <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;&#39;</span><span class="si">%s</span><span class="s">&#39; is a non-numeric value&quot;</span> <span class="o">%</span> <span class="n">entry_value</span><span class="p">)</span>

      <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
        <span class="c"># parameters should be in ascending order by their key</span>
        <span class="k">for</span> <span class="n">prior_key</span> <span class="ow">in</span> <span class="n">seen_keys</span><span class="p">:</span>
          <span class="k">if</span> <span class="n">prior_key</span> <span class="o">&gt;</span> <span class="n">entry_key</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;parameters must be sorted by their key&quot;</span><span class="p">)</span>

      <span class="n">results</span><span class="p">[</span><span class="n">entry_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">entry_value</span>
      <span class="n">seen_keys</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">entry_key</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">ValueError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
        <span class="k">continue</span>

      <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Unable to parse network status document&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; line (</span><span class="si">%s</span><span class="s">): </span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">exc</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>

  <span class="k">return</span> <span class="n">results</span>


<div class="viewcode-block" id="DirectoryAuthority"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.DirectoryAuthority">[docs]</a><span class="k">class</span> <span class="nc">DirectoryAuthority</span><span class="p">(</span><span class="n">Descriptor</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Directory authority information obtained from a v3 network status document.</span>

<span class="sd">  Authorities can optionally use a legacy format. These are no longer found in</span>
<span class="sd">  practice, but have the following differences...</span>

<span class="sd">  * The authority&#39;s nickname ends with &#39;-legacy&#39;.</span>
<span class="sd">  * There&#39;s no **contact** or **vote_digest** attribute.</span>

<span class="sd">  :var str nickname: **\*** authority&#39;s nickname</span>
<span class="sd">  :var str fingerprint: **\*** authority&#39;s fingerprint</span>
<span class="sd">  :var str hostname: **\*** hostname of the authority</span>
<span class="sd">  :var str address: **\*** authority&#39;s IP address</span>
<span class="sd">  :var int dir_port: **\*** authority&#39;s DirPort</span>
<span class="sd">  :var int or_port: **\*** authority&#39;s ORPort</span>
<span class="sd">  :var bool is_legacy: **\*** if the authority&#39;s using the legacy format</span>
<span class="sd">  :var str contact: contact information, this is included if is_legacy is **False**</span>

<span class="sd">  **Consensus Attributes:**</span>

<span class="sd">  :var str vote_digest: digest of the authority that contributed to the consensus, this is included if is_legacy is **False**</span>

<span class="sd">  **Vote Attributes:**</span>

<span class="sd">  :var str legacy_dir_key: fingerprint of and obsolete identity key</span>
<span class="sd">  :var stem.descriptor.networkstatus.KeyCertificate key_certificate: **\***</span>
<span class="sd">    authority&#39;s key certificate</span>

<span class="sd">  **\*** mandatory attribute</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">is_vote</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Parse a directory authority entry in a v3 network status document.</span>

<span class="sd">    :param str raw_content: raw directory authority entry information</span>
<span class="sd">    :param bool validate: checks the validity of the content if True, skips</span>
<span class="sd">      these checks otherwise</span>
<span class="sd">    :param bool is_vote: True if this is for a vote, False if it&#39;s for a consensus</span>

<span class="sd">    :raises: ValueError if the descriptor data is invalid</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="nb">super</span><span class="p">(</span><span class="n">DirectoryAuthority</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="n">raw_content</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">nickname</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">hostname</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">or_port</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">is_legacy</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">contact</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">vote_digest</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">legacy_dir_key</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">key_certificate</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_parse</span><span class="p">(</span><span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">is_vote</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">_parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">,</span> <span class="n">is_vote</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Parses the given content and applies the attributes.</span>

<span class="sd">    :param str content: descriptor content</span>
<span class="sd">    :param bool validate: checks validity if True</span>
<span class="sd">    :param bool is_vote: **True** if this is for a vote, **False** if it&#39;s for</span>
<span class="sd">      a consensus</span>

<span class="sd">    :raises: **ValueError** if a validity check fails</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c"># separate the directory authority entry from its key certificate</span>
    <span class="n">key_div</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">&#39;</span><span class="se">\n</span><span class="s">dir-key-certificate-version&#39;</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">key_div</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
      <span class="n">key_cert_content</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="n">key_div</span> <span class="o">+</span> <span class="mi">1</span><span class="p">:]</span>
      <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="p">[:</span><span class="n">key_div</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
      <span class="n">key_cert_content</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="n">entries</span> <span class="o">=</span> <span class="n">_get_descriptor_components</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="s">&#39;dir-source&#39;</span> <span class="o">!=</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]:</span>
      <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority entries are expected to start with a &#39;dir-source&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">content</span><span class="p">))</span>

    <span class="c"># check that we have mandatory fields</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="n">is_legacy</span><span class="p">,</span> <span class="n">dir_source_entry</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">entries</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;dir-source&quot;</span><span class="p">)</span>

      <span class="k">if</span> <span class="n">dir_source_entry</span><span class="p">:</span>
        <span class="n">is_legacy</span> <span class="o">=</span> <span class="n">dir_source_entry</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;-legacy&quot;</span><span class="p">)</span>

      <span class="n">required_fields</span><span class="p">,</span> <span class="n">excluded_fields</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;dir-source&quot;</span><span class="p">],</span> <span class="p">[]</span>

      <span class="k">if</span> <span class="ow">not</span> <span class="n">is_legacy</span><span class="p">:</span>
        <span class="n">required_fields</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&quot;contact&quot;</span><span class="p">]</span>

      <span class="k">if</span> <span class="n">is_vote</span><span class="p">:</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">key_cert_content</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority votes must have a key certificate:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">content</span><span class="p">)</span>

        <span class="n">excluded_fields</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&quot;vote-digest&quot;</span><span class="p">]</span>
      <span class="k">elif</span> <span class="ow">not</span> <span class="n">is_vote</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">key_cert_content</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority consensus entries shouldn&#39;t have a key certificate:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">content</span><span class="p">)</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">is_legacy</span><span class="p">:</span>
          <span class="n">required_fields</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&quot;vote-digest&quot;</span><span class="p">]</span>

        <span class="n">excluded_fields</span> <span class="o">+=</span> <span class="p">[</span><span class="s">&quot;legacy-dir-key&quot;</span><span class="p">]</span>

      <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">required_fields</span><span class="p">:</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority entries must have a &#39;</span><span class="si">%s</span><span class="s">&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">content</span><span class="p">))</span>

      <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">excluded_fields</span><span class="p">:</span>
          <span class="n">type_label</span> <span class="o">=</span> <span class="s">&quot;votes&quot;</span> <span class="k">if</span> <span class="n">is_vote</span> <span class="k">else</span> <span class="s">&quot;consensus entries&quot;</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority </span><span class="si">%s</span><span class="s"> shouldn&#39;t have a &#39;</span><span class="si">%s</span><span class="s">&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">type_label</span><span class="p">,</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">content</span><span class="p">))</span>

    <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="n">value</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
      <span class="n">line</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

      <span class="c"># all known attributes can only appear at most once</span>
      <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;dir-source&#39;</span><span class="p">,</span> <span class="s">&#39;contact&#39;</span><span class="p">,</span> <span class="s">&#39;legacy-dir-key&#39;</span><span class="p">,</span> <span class="s">&#39;vote-digest&#39;</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority entries can only have a single &#39;</span><span class="si">%s</span><span class="s">&#39; line, got </span><span class="si">%i</span><span class="s">:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">),</span> <span class="n">content</span><span class="p">))</span>

      <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-source&#39;</span><span class="p">:</span>
        <span class="c"># &quot;dir-source&quot; nickname identity address IP dirport orport</span>

        <span class="n">dir_source_comp</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">6</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority entry&#39;s &#39;dir-source&#39; line must have six values: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_nickname</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s">&#39;-legacy&#39;</span><span class="p">)):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s nickname is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s fingerprint is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
            <span class="c"># https://trac.torproject.org/7055</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s hostname can&#39;t be blank: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_ipv4_address</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">3</span><span class="p">]):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s address isn&#39;t a valid IPv4 address: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">allow_zero</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s DirPort is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">5</span><span class="p">]):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority&#39;s ORPort is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()</span> <span class="ow">and</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()):</span>
          <span class="k">continue</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">nickname</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">hostname</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">if</span> <span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;0&#39;</span> <span class="k">else</span> <span class="nb">int</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">or_port</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">dir_source_comp</span><span class="p">[</span><span class="mi">5</span><span class="p">])</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">is_legacy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">nickname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;-legacy&quot;</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;contact&#39;</span><span class="p">:</span>
        <span class="c"># &quot;contact&quot; string</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">contact</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;legacy-dir-key&#39;</span><span class="p">:</span>
        <span class="c"># &quot;legacy-dir-key&quot; FINGERPRINT</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority has a malformed legacy directory key: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">legacy_dir_key</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;vote-digest&#39;</span><span class="p">:</span>
        <span class="c"># &quot;vote-digest&quot; digest</span>

        <span class="c"># technically not a fingerprint, but has the same characteristics</span>
        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Authority has a malformed vote digest: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">vote_digest</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">key_cert_content</span><span class="p">:</span>
      <span class="bp">self</span><span class="o">.</span><span class="n">key_certificate</span> <span class="o">=</span> <span class="n">KeyCertificate</span><span class="p">(</span><span class="n">key_cert_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

<div class="viewcode-block" id="DirectoryAuthority.get_unrecognized_lines"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.DirectoryAuthority.get_unrecognized_lines">[docs]</a>  <span class="k">def</span> <span class="nf">get_unrecognized_lines</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Returns any unrecognized lines.</span>

<span class="sd">    :returns: a list of unrecognized lines</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span>
</div>
  <span class="k">def</span> <span class="nf">_compare</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">DirectoryAuthority</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">False</span>

    <span class="k">return</span> <span class="n">method</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="nb">str</span><span class="p">(</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>

  <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">==</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">o</span><span class="p">)</span>

</div>
<div class="viewcode-block" id="KeyCertificate"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.KeyCertificate">[docs]</a><span class="k">class</span> <span class="nc">KeyCertificate</span><span class="p">(</span><span class="n">Descriptor</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Directory key certificate for a v3 network status document.</span>

<span class="sd">  :var int version: **\*** version of the key certificate</span>
<span class="sd">  :var str address: authority&#39;s IP address</span>
<span class="sd">  :var int dir_port: authority&#39;s DirPort</span>
<span class="sd">  :var str fingerprint: **\*** authority&#39;s fingerprint</span>
<span class="sd">  :var str identity_key: **\*** long term authority identity key</span>
<span class="sd">  :var datetime published: **\*** time when this key was generated</span>
<span class="sd">  :var datetime expires: **\*** time after which this key becomes invalid</span>
<span class="sd">  :var str signing_key: **\*** directory server&#39;s public signing key</span>
<span class="sd">  :var str crosscert: signature made using certificate&#39;s signing key</span>
<span class="sd">  :var str certification: **\*** signature of this key certificate signed with</span>
<span class="sd">    the identity key</span>

<span class="sd">  **\*** mandatory attribute</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="nb">super</span><span class="p">(</span><span class="n">KeyCertificate</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="n">raw_content</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">identity_key</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">expires</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">signing_key</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">crosscert</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">certification</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">_parse</span><span class="p">(</span><span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">_parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Parses the given content and applies the attributes.</span>

<span class="sd">    :param str content: descriptor content</span>
<span class="sd">    :param bool validate: checks validity if **True**</span>

<span class="sd">    :raises: **ValueError** if a validity check fails</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="n">entries</span> <span class="o">=</span> <span class="n">_get_descriptor_components</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">validate</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="k">if</span> <span class="s">&#39;dir-key-certificate-version&#39;</span> <span class="o">!=</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificates must start with a &#39;dir-key-certificate-version&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">content</span><span class="p">))</span>
      <span class="k">elif</span> <span class="s">&#39;dir-key-certification&#39;</span> <span class="o">!=</span> <span class="n">entries</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificates must end with a &#39;dir-key-certification&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">content</span><span class="p">))</span>

      <span class="c"># check that we have mandatory fields and that our known fields only</span>
      <span class="c"># appear once</span>

      <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">is_mandatory</span> <span class="ow">in</span> <span class="n">KEY_CERTIFICATE_PARAMS</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">is_mandatory</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificates must have a &#39;</span><span class="si">%s</span><span class="s">&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">content</span><span class="p">))</span>

        <span class="n">entry_count</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">entries</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="p">[]))</span>
        <span class="k">if</span> <span class="n">entry_count</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificates can only have a single &#39;</span><span class="si">%s</span><span class="s">&#39; line, got </span><span class="si">%i</span><span class="s">:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">entry_count</span><span class="p">,</span> <span class="n">content</span><span class="p">))</span>

    <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
      <span class="n">value</span><span class="p">,</span> <span class="n">block_contents</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
      <span class="n">line</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

      <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-key-certificate-version&#39;</span><span class="p">:</span>
        <span class="c"># &quot;dir-key-certificate-version&quot; version</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">value</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate has a non-integer version: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Expected a version 3 key certificate, got version &#39;</span><span class="si">%i</span><span class="s">&#39; instead&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-address&#39;</span><span class="p">:</span>
        <span class="c"># &quot;dir-address&quot; IPPort</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="s">&#39;:&#39;</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">continue</span>

          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s &#39;dir-address&#39; is expected to be of the form ADDRESS:PORT: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="n">address</span><span class="p">,</span> <span class="n">dirport</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;:&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_ipv4_address</span><span class="p">(</span><span class="n">address</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s address isn&#39;t a valid IPv4 address: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
          <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">dirport</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s dirport is invalid: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="n">dirport</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
          <span class="k">continue</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">address</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">dir_port</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">dirport</span><span class="p">)</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;fingerprint&#39;</span><span class="p">:</span>
        <span class="c"># &quot;fingerprint&quot; fingerprint</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s fingerprint is malformed: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span> <span class="o">=</span> <span class="n">value</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;dir-key-published&#39;</span><span class="p">,</span> <span class="s">&#39;dir-key-expires&#39;</span><span class="p">):</span>
        <span class="c"># &quot;dir-key-published&quot; YYYY-MM-DD HH:MM:SS</span>
        <span class="c"># &quot;dir-key-expires&quot; YYYY-MM-DD HH:MM:SS</span>

        <span class="k">try</span><span class="p">:</span>
          <span class="n">date_value</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S&quot;</span><span class="p">)</span>

          <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-key-published&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="n">date_value</span>
          <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-key-expires&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">expires</span> <span class="o">=</span> <span class="n">date_value</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
          <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; time wasn&#39;t parsable: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
      <span class="k">elif</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;dir-identity-key&#39;</span><span class="p">,</span> <span class="s">&#39;dir-signing-key&#39;</span><span class="p">,</span> <span class="s">&#39;dir-key-crosscert&#39;</span><span class="p">,</span> <span class="s">&#39;dir-key-certification&#39;</span><span class="p">):</span>
        <span class="c"># &quot;dir-identity-key&quot; NL a public key in PEM format</span>
        <span class="c"># &quot;dir-signing-key&quot; NL a key in PEM format</span>
        <span class="c"># &quot;dir-key-crosscert&quot; NL CrossSignature</span>
        <span class="c"># &quot;dir-key-certification&quot; NL Signature</span>

        <span class="k">if</span> <span class="n">validate</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">block_contents</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Key certificate&#39;s &#39;</span><span class="si">%s</span><span class="s">&#39; line must be followed by a key block: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">line</span><span class="p">))</span>

        <span class="k">if</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-identity-key&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">identity_key</span> <span class="o">=</span> <span class="n">block_contents</span>
        <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-signing-key&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">signing_key</span> <span class="o">=</span> <span class="n">block_contents</span>
        <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-key-crosscert&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">crosscert</span> <span class="o">=</span> <span class="n">block_contents</span>
        <span class="k">elif</span> <span class="n">keyword</span> <span class="o">==</span> <span class="s">&#39;dir-key-certification&#39;</span><span class="p">:</span>
          <span class="bp">self</span><span class="o">.</span><span class="n">certification</span> <span class="o">=</span> <span class="n">block_contents</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<div class="viewcode-block" id="KeyCertificate.get_unrecognized_lines"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.KeyCertificate.get_unrecognized_lines">[docs]</a>  <span class="k">def</span> <span class="nf">get_unrecognized_lines</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Returns any unrecognized lines.</span>

<span class="sd">    :returns: **list** of unrecognized lines</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_unrecognized_lines</span>
</div>
  <span class="k">def</span> <span class="nf">_compare</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">KeyCertificate</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">False</span>

    <span class="k">return</span> <span class="n">method</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="nb">str</span><span class="p">(</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>

  <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">==</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">o</span><span class="p">)</span>

</div>
<div class="viewcode-block" id="DocumentSignature"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.DocumentSignature">[docs]</a><span class="k">class</span> <span class="nc">DocumentSignature</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Directory signature of a v3 network status document.</span>

<span class="sd">  :var str method: algorithm used to make the signature</span>
<span class="sd">  :var str identity: fingerprint of the authority that made the signature</span>
<span class="sd">  :var str key_digest: digest of the signing key</span>
<span class="sd">  :var str signature: document signature</span>
<span class="sd">  :param bool validate: checks validity if **True**</span>

<span class="sd">  :raises: **ValueError** if a validity check fails</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">identity</span><span class="p">,</span> <span class="n">key_digest</span><span class="p">,</span> <span class="n">signature</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="c"># Checking that these attributes are valid. Technically the key</span>
    <span class="c"># digest isn&#39;t a fingerprint, but it has the same characteristics.</span>

    <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
      <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">identity</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Malformed fingerprint (</span><span class="si">%s</span><span class="s">) in the document signature&quot;</span> <span class="o">%</span> <span class="n">identity</span><span class="p">)</span>

      <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">key_digest</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Malformed key digest (</span><span class="si">%s</span><span class="s">) in the document signature&quot;</span> <span class="o">%</span> <span class="n">key_digest</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">method</span> <span class="o">=</span> <span class="n">method</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">identity</span> <span class="o">=</span> <span class="n">identity</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">key_digest</span> <span class="o">=</span> <span class="n">key_digest</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">signature</span> <span class="o">=</span> <span class="n">signature</span>

  <span class="k">def</span> <span class="nf">_compare</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">,</span> <span class="n">method</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">DocumentSignature</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">False</span>

    <span class="k">for</span> <span class="n">attr</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&quot;method&quot;</span><span class="p">,</span> <span class="s">&quot;identity&quot;</span><span class="p">,</span> <span class="s">&quot;key_digest&quot;</span><span class="p">,</span> <span class="s">&quot;signature&quot;</span><span class="p">):</span>
      <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">attr</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">method</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">),</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">attr</span><span class="p">))</span>

    <span class="k">return</span> <span class="n">method</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span>  <span class="c"># we&#39;re equal</span>

  <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">==</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;</span> <span class="n">o</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_compare</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">o</span><span class="p">)</span>

</div>
<div class="viewcode-block" id="BridgeNetworkStatusDocument"><a class="viewcode-back" href="../../../api/descriptor/networkstatus.html#stem.descriptor.networkstatus.BridgeNetworkStatusDocument">[docs]</a><span class="k">class</span> <span class="nc">BridgeNetworkStatusDocument</span><span class="p">(</span><span class="n">NetworkStatusDocument</span><span class="p">):</span>
  <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">  Network status document containing bridges. This is only available through</span>
<span class="sd">  the metrics site.</span>

<span class="sd">  :var tuple routers: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV2`</span>
<span class="sd">    contained in the document</span>
<span class="sd">  :var datetime published: time when the document was published</span>
<span class="sd">  &quot;&quot;&quot;</span>

  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_content</span><span class="p">,</span> <span class="n">validate</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="nb">super</span><span class="p">(</span><span class="n">BridgeNetworkStatusDocument</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="n">document_file</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">raw_content</span><span class="p">)</span>
    <span class="n">published_line</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">document_file</span><span class="o">.</span><span class="n">readline</span><span class="p">())</span>

    <span class="k">if</span> <span class="n">published_line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;published &quot;</span><span class="p">):</span>
      <span class="n">published_line</span> <span class="o">=</span> <span class="n">published_line</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>

      <span class="k">try</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">published</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">published_line</span><span class="p">,</span> <span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S&quot;</span><span class="p">)</span>
      <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">validate</span><span class="p">:</span>
          <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Bridge network status document&#39;s &#39;published&#39; time wasn&#39;t parsable: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">published_line</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">validate</span><span class="p">:</span>
      <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">&quot;Bridge network status documents must start with a &#39;published&#39; line:</span><span class="se">\n</span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">raw_content</span><span class="p">))</span>

    <span class="n">router_iter</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span>
      <span class="n">document_file</span><span class="p">,</span>
      <span class="n">validate</span><span class="p">,</span>
      <span class="n">entry_class</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV2</span><span class="p">,</span>
      <span class="n">extra_args</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="p">,),</span>
    <span class="p">)</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">routers</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">desc</span><span class="o">.</span><span class="n">fingerprint</span><span class="p">,</span> <span class="n">desc</span><span class="p">)</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">router_iter</span><span class="p">)</span></div>
</pre></div>

      </div>
      <div class="bottomnav">
      </div>

    <div class="footer">
    </div>
  </body>
</html>