
    h9             	          d Z ddlZddlZddlZddlZddlZddlZddlZddl	Zddl
mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z! ddlm"Z"m#Z#m$Z$m%Z% dZ&dZ'dZ(dZ)d	Z*d
Z+dZ,i dddddddddddddddddddddd d!d"d#d$d%d&d'd&d(d&d)d*d*d+d,d-d.d/dd0Z-d1Z.d2Z/d3\  Z0Z1i d4d5d6d7e1fd8d7e1fd9d7e1fd:d;dd&e1fdd;dd<dd=dd>dd?dd@de0dAfdd&e1fddBe1fd!dCd#dDi d%d;d'd;d(d;dEd;dFdGe1fdHdIdJdKdLdMdNdOdPd;dQd&e1fd)dRdSdRdTdUdVdUdWdKdXdYdZd;d[Z2 G d\ d] ejf                  d]g d^            Z4 G d_ d` ejf                  d`g da            Z5 G db dc ejf                  dcg dd            Z6ddedeejn                  fdfZ8ddgZ9ddhZ: G di dje      Z;dk Z<dl Z=dm Z>dn Z? e<dodpd-      Z@ edqdq      ZA edrdr      ZB edsdtdu      ZC edvdwdx y      ZD edzd{d| y      ZE ed}d}      ZF ed~dd y      ZG edddd      ZH edd      ZI G d de;      ZJd ZKd ZLd ZMd ZNd ZOd ZPd ZQd ZRd ZSd ZTd ZUd ZVd ZWd ZXd ZYd ZZ edd      Z[ edd      Z\ edd      Z] ePdvdw      Z^ ePdzd{      Z_ eddd y      Z` eddd y      Za edd      Zb edd      Zc edd      Zd edd      Ze edd      Zf G d de;      Zgd Zhd Zid Zj edd      Zk edd      Zl G d de      Zmd Zn e<ddpd      Zo edd}      Zp edd      Zq edddu      Zr edsdtdu      Zs edddë      Zt eddd      Zu G dƄ de      Zv G dȄ dew      Zx G dʄ de      Zy G d̄ de;      Zzy)aC  
Parsing for Tor network status documents. This supports both the v2 and v3
`dir-spec <https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_.
Documents can be obtained from a few sources...

* The 'cached-consensus' file in Tor's data directory.

* Archived descriptors provided by `CollecTor
  <https://metrics.torproject.org/collector.html>`_.

* Directory authorities and mirrors via their DirPort.

... and contain the following sections...

* document header
* list of :class:`stem.descriptor.networkstatus.DirectoryAuthority`
* list of :class:`stem.descriptor.router_status_entry.RouterStatusEntry`
* document footer

**For a great graphical overview see** `Jordan Wright's chart describing the
anatomy of the consensus
<https://jordan-wright.github.io/images/blog/how_tor_works/consensus.png>`_.

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

::

  from stem.descriptor import parse_file, DocumentHandler

  with open('.tor/cached-consensus', 'rb') as consensus_file:
    # Processes the routers as we read them in. The routers refer to a document
    # with an unset 'routers' attribute.

    for router in parse_file(consensus_file, 'network-status-consensus-3 1.0', document_handler = DocumentHandler.ENTRIES):
      print router.nickname

**Module Overview:**

::

  NetworkStatusDocument - Network status document
    |- NetworkStatusDocumentV2 - Version 2 network status document
    |- NetworkStatusDocumentV3 - Version 3 network status document
    +- BridgeNetworkStatusDocument - Version 3 network status document for bridges

  KeyCertificate - Certificate used to authenticate an authority
  DocumentSignature - Signature of a document by a directory authority
  DetachedSignature - Stand alone signature used when making the consensus
  DirectoryAuthority - Directory authority as defined in a v3 network status document
    N)PGP_BLOCK_END
Descriptor
DigestHashDigestEncodingTypeAnnotationDocumentHandler_descriptor_content_descriptor_components_read_until_keywords_value_values_parse_simple_line_parse_if_present_parse_timestamp_line_parse_forty_character_hex_parse_protocol_line_parse_key_block_mappings_for_random_nickname_random_fingerprint_random_ipv4_address_random_date_random_crypto_blob)RouterStatusEntryV2RouterStatusEntryBridgeV2RouterStatusEntryV3RouterStatusEntryMicroV3)
)network-status-versionT)
dir-sourceTfingerprintT)contactTdir-signing-keyT)client-versionsF)server-versionsF)	publishedT)dir-optionsF)directory-signatureT))r   TTT)vote-statusTTT)consensus-methodsTFF)consensus-methodFTF)r'   TFT)valid-afterTTT)fresh-untilTTT)valid-untilTTT)voting-delayTTT)r%   TTF)r&   TTF)packageTTF)known-flagsTTT)flag-thresholdsTFF)shared-rand-participateTFF)shared-rand-commitTFF)shared-rand-previous-valueTTF)shared-rand-current-valueTTF)bandwidth-file-headersTFF)bandwidth-file-digestTFF)recommended-client-protocolsTTF)recommended-relay-protocolsTTF)required-client-protocolsTTF)required-relay-protocolsTTF)paramsTTF))directory-footerTTF)bandwidth-weightsFTF)r)   TTTr   rr?   r)   bwweightscale'  cbtdisabledcbtnummodes   cbtrecentcount   cbtmaxtimeouts   cbtmincircsd   cbtquantileP   cbtclosequantile_   cbttestfreq<   cbtmintimeouti  cbtinitialtimeout`  cbtlearntimeout   cbtmaxopencircs
   UseOptimisticData   Support022HiddenServicesusecreatefastz%max-consensuses-age-to-cache-for-diffH            P    )!try-diff-for-consensus-newer-thanonion-key-rotation-daysonion-key-grace-period-dayshs_service_max_rdv_failurescirc_max_cell_queue_sizecircpad_max_circ_queued_cells"HiddenServiceEnableIntroDoSDefense)	)dir-key-certificate-versionT)dir-addressFr    )dir-identity-keyT)dir-key-publishedT)dir-key-expiresTr#   )dir-key-crosscertF)dir-key-certificationT))consensus-digestTF)r-   TF)r.   TF)r/   TF)additional-digestFT)additional-signatureFT)r)   FT)i   i
circwindow)rL   rc   CircuitPriorityHalflifeMsecperconnbwrateperconnbwburstrefuseunknownexits)r   r[   )r[   rH   )rF   rc   )rF   rC   )r[   rC   )rY   c   r{   i  )rY   rU   )r      UseNTorHandshakeFastFlagMinThreshold   NumDirectoryGuards)r   rY   NumEntryGuards)r[   rY   GuardLifetime)i ' i Sg	NumNTorsPerTAP)r[   i AllowNonearlyExtendAuthDirNumSRVAgreements)r   i    rd   re   )r[   Z   rf   rg   rh   )rc   l    )r   rb   )ri   rj   c                       e Zd ZdZy)PackageVersionz
  Latest recommended version of a package that's available.

  :var str name: name of the package
  :var str version: latest recommended version
  :var str url: package's url
  :var dict digests: mapping of digest types to their value
  N__name__
__module____qualname____doc__     g/var/www/betterdocs.net/sherlock_api/venv/lib/python3.12/site-packages/stem/descriptor/networkstatus.pyr   r     s    r   r   )nameversionurldigestsc                       e Zd ZdZy)SharedRandomnessCommitmenta  
  Directory authority's commitment for generating the next shared random value.

  :var int version: shared randomness protocol version
  :var str algorithm: hash algorithm used to make the commitment
  :var str identity: authority's sha1 identity fingerprint
  :var str commit: base64 encoded commitment hash to the shared random value
  :var str reveal: base64 encoded commitment to the shared random value,
    **None** of not provided
  Nr   r   r   r   r   r     s    	r   r   )r   	algorithmidentitycommitrevealc                       e Zd ZdZy)DocumentDigestz
  Digest of a consensus document.

  .. versionadded:: 1.8.0

  :var str flavor: consensus type this digest is for (for example, 'microdesc')
  :var str algorithm: hash algorithm used to make the digest
  :var str digest: digest value of the consensus
  Nr   r   r   r   r   r     s    r   r   )flavorr   digestFc              +     K   |t         }|t        k(  rt        t        }}n`|t         k(  r|rt        nt        }nH|t
        k(  rt
        t        }}n2|t        k(  r || j                         |fi | yt        d|z        |t        j                  k(  r || j                         |fi | yt        t        t        t        f|       }|r|d   j!                  d      r|dd }| j#                         }t        t        t        f| d       | j#                         }	| j%                         }
t&        j)                  d||
z         }|t        j*                  k(  r |||fi | y|t        j,                  k(  rIt/        j0                  j2                  j4                  | |f|t        ||	 |||      fd	|}|D ]  }|  yt        d
|z        w)a  
  Parses a network status and iterates over the RouterStatusEntry in it. The
  document that these instances reference have an empty 'routers' attribute to
  allow for limited memory usage.

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

  :returns: :class:`stem.descriptor.networkstatus.NetworkStatusDocument` object

  :raises:
    * **ValueError** if the document_version is unrecognized or the contents is
      malformed and validate is **True**
    * **IOError** if the file can't be read
  NzIDocument type %i isn't recognized (only able to parse v2, v3, and bridge)r   s   @typer[   T)skipr   )entry_classentry_keywordstart_positionend_position
extra_argsz!Unrecognized document_handler: %s)NetworkStatusDocumentV3NetworkStatusDocumentV2r   r   r   BridgeNetworkStatusDocumentr   DetachedSignatureread
ValueErrorr   DOCUMENTr   ROUTERS_STARTFOOTER_STARTV2_FOOTER_START
startswithtell	readlinesbytesjoinBARE_DOCUMENTENTRIESstem
descriptorrouter_status_entry_parse_file)document_filedocument_typevalidateis_microdescriptordocument_handlerkwargsrouter_typeheaderrouters_startrouters_endfooterdocument_contentdesc_iteratordescs                 r   r   r   (  s    4 +M--!8:M;M//.@*FYK33!<>W;M))
**,h
A&
AA

`cpp
qq111
**,h
A&
AA
  o NP]^&q	$$X.ABZF$$&-o6dS""$+""$&ZZVf_5666
((
=f
==?222OO77CC	  #$ !"2H=?	 		M  j 8;KK
LLs   GGc              #     K   	 t        d|       }t        j                  dd      d   }|t        || d      z  }|rBt        j                  j
                  j                  t        j                  d|      |       ny{w)	a  
  Parses a file containing one or more authority key certificates.

  :param file certificate_file: file with key certificates
  :param bool validate: checks the validity of the certificate's contents if
    **True**, skips these checks otherwise

  :returns: iterator for :class:`stem.descriptor.networkstatus.KeyCertificate`
    instances in the file

  :raises:
    * **ValueError** if the key certificates are invalid and validate is **True**
    * **IOError** if the file can't be read
  Trq    r[   r   r   r   N)	r   r   splitr   r   networkstatusKeyCertificater   r   )certificate_filer   keycert_contentblock_end_prefixs       r   _parse_file_key_certsr   w  s       	*+BDTUO %**3215+,<>NPTUUOOO))88C9Yfn8oo 	s   A=A?c              #      K   	 t        d| d      }|rBt        j                  j                  j	                  t
        j                  d|      |       nyTw)a  
  Parses a file containing one or more detached signatures.

  :param file detached_signature_file: file with detached signatures
  :param bool validate: checks the validity of the detached signature's
    contents if **True**, skips these checks otherwise

  :returns: iterator for :class:`stem.descriptor.networkstatus.DetachedSignature`
    instances in the file

  :raises:
    * **ValueError** if the detached signatures are invalid and validate is **True**
    * **IOError** if the file can't be read
  Trr   )ignore_firstr   r   N)r   r   r   r   r   r   r   )detached_signature_filer   detached_sig_contents      r   _parse_file_detached_sigsr     sU       	/0BD[lpqOO));;EJJsL`<anv;ww 	s   AAc                   D    e Zd ZdZej
                  ej                  fdZy)NetworkStatusDocumentz1
  Common parent for network status documents.
  c                 Z   | j                  d      }|t        j                  k(  r3t        j                  j                  t        j                  |      |      S |t        j                  k(  r3t        j                  j                  t        j                  |      |      S t        d|z        )a  
    Digest of this descriptor's content. These are referenced by...

      * **DetachedSignature**

        * Referer: :class:`~stem.descriptor.networkstatus.DetachedSignature` **consensus_digest** attribute
        * Format: **SHA1/HEX**

    .. versionadded:: 1.8.0

    :param stem.descriptor.DigestHash hash_type: digest hashing algorithm
    :param stem.descriptor.DigestEncoding encoding: digest encoding

    :returns: **hashlib.HASH** or **str** based on our encoding argument
    z
directory-signature )endzMNetwork status document digests are only available in sha1 and sha256, not %s)_content_ranger   SHA1r   r   _encode_digesthashlibsha1SHA256sha256NotImplementedError)self	hash_typeencodingcontents       r   r   zNetworkStatusDocument.digest  s    " !!(@!AGJOO#__++GLL,A8LL	j''	'__++GNN7,CXNN or{ {||r   N)	r   r   r   r   r   r   r   HEXr   r   r   r   r   r     s      *>;M;M }r   r   c                       fd}|S )Nc                     t        |      }|j                         st        dd|      t        | t	        |             t	        |      k7  rt        d|fz        y )Nz$Document has a non-numeric version: r   z<Expected a version %i document, but got version '%s' instead)r   isdigitr   setattrint)r   entriesvalue	attributeexpected_versionkeywords      r   _parsez#_parse_version_line.<locals>._parse  sb    7G$E==?guUVVJ	3u:.
5z%%UYikpXqqrr &r   r   )r   r   r   r   s   ``` r   _parse_version_liner     s    	s 
-r   c                     t        d|      }|j                         }t        |      dk  rt        d|z        |d   st        d|z        t        j
                  j                  j                  |d         st        d|d   z        t        j
                  j                  j                  |d   d	
      st        d|d   z        |d   | _	        |d   | _
        |d   dk(  rd | _        y t        |d         | _        y )Nr   rF   z[The 'dir-source' line of a v2 network status document must have three values: dir-source %sr   2Authority's hostname can't be blank: dir-source %sr[   2Authority's address isn't a valid IPv4 address: %sra   T
allow_zero"Authority's DirPort is invalid: %s0)r   r   lenr   r   util
connectionis_valid_ipv4_addressis_valid_porthostnameaddressr   dir_portr   r   r   dir_source_comps       r   _parse_dir_source_liner    s    
w
'%KKM/A
ruzz
{{		
IEQ
RR9955oa6HI
IO\]L^^
__99--oa.@t-T
9OA<NN
OO'**&q)* / 2c 9*s?STCU?V*r   c                     g }t        d|      D ]I  }|j                  d      }t        |      dk  rt        d|z        |j	                  t        |d d         K || _        y )Nrs   r   rF   ziadditional-digest lines should be of the form 'additional-digest [flavor] [algname] [digest]' but was: %s)r   r   r   r   appendr   additional_digests)r   r   r   valcomps        r   _parse_additional_digestsr    sy    '('2 .c99S>D
4y1}  C  FI  I  J  JNN>48,-. #**r   c                    g }|d   D ]t  \  }}}|j                  d      }t        |      dk  rt        d|z        |r|dk7  rt        d|z        |j                  t	        |d   |d   |d	   ||d
   d             v || _        y )Nrt   r   r   zadditional-signature lines should be of the form 'additional-signature [flavor] [algname] [identity] [signing_key_digest]' but was: %s	SIGNATUREzL'additional-signature' should be followed by a SIGNATURE block, but was a %sr[   ra   rF   r   T)r   r   )r   r   r   r  DocumentSignatureadditional_signatures)r   r   
signaturesr
  
block_typeblock_contentsr  s          r   _parse_additional_signaturesr    s    *)01G)H w%c:~99S>D
4y1}  `  cf  f  g  gz[8ehrrss'Qa$q'>\`ab\cptuvw &0*"r   r   r   r!   r"   r$   signing_keyRSA PUBLIC KEYr%   client_versionsc                 $    | j                  d      S N,r   vs    r   <lambda>r        hihohopsht r   )funcr&   server_versionsc                 $    | j                  d      S r  r  r  s    r   r  r    r  r   r'   r(   optionsc                 "    | j                         S Nr  r  s    r   r  r    s    XYX_X_Xa r   	signaturer  signing_authority)value_attributerr   consensus_digestc                        e Zd ZdZdZdefdefdefdefdefdefde	fg e
fg efdefg efdefdefdZeeeee	e
eeeed
Zed	d       Zd
 fd	Zd Z xZS )r   a  
  Version 2 network status document. These have been deprecated and are no
  longer generated by Tor.

  :var dict routers: fingerprints to :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV2`
    contained in the document

  :var int version: **\*** document version

  :var str hostname: **\*** hostname of the authority
  :var str address: **\*** authority's IP address
  :var int dir_port: **\*** authority's DirPort
  :var str fingerprint: **\*** authority's fingerprint
  :var str contact: **\*** authority's contact information
  :var str signing_key: **\*** authority's public signing key

  :var list client_versions: list of recommended client tor version strings
  :var list server_versions: list of recommended server tor version strings
  :var datetime published: **\*** time when the document was published
  :var list options: **\*** list of things that this authority decides

  :var str signing_authority: **\*** name of the authority signing the document
  :var str signature: **\*** authority's signature for the document

  **\*** attribute is either required when we're parsed with validation or has
  a default value, others are left as **None** if undefined
  znetwork-status-2N)r   r  r  r  r!   r"   r  r  r!  r'   r#  r'  r  )
r   r   r!   r"   r$   r%   r&   r'   r(   r)   c                     |rt        d| j                  z        t        ||ddt               dt               dfdt	               fddt               fd	t        d
      ffddt        d      z   ff      S )NSigning of %s not implemented)r   2r   r   z 80r!   )r"   zarma at mit dot edur'   r$   r  r)   moria2r  )r   r   r	   r   r   r   r   clsattrexcludesigns       r   r   zNetworkStatusDocumentV2.contentX  s     ?#,, NOOtW%#7#9;O;QRS)+,(LN#-.>?@/ h)<[)IIJ	 	r   c                 N   t         t        |   ||        t        j                  |      }t
        j                  dt        t        t        f|            }t        j                  j                  j                  ||t        t        t        f| f      }t        d |D              | _        t#        |dz   |j%                         z   |      }|rR| j'                  |       | j)                  ||       d| j*                  v r d|v rd|v st-        d	t/        |       z        y y || _        y )
N	lazy_loadr   r   r   section_end_keywordsr   c              3   8   K   | ]  }|j                   |f  y wr%  r!   .0r   s     r   	<genexpr>z3NetworkStatusDocumentV2.__init__.<locals>.<genexpr>|       IT))40I      
Versionsr%   r&   zVersion 2 network status documents must have a 'client-versions' and 'server-versions' when 'Versions' is listed among its dir-options:
%s)superr   __init__ioBytesIOr   r   r   r   r   r   r   r   r   r   dictroutersr
   r   _check_constraintsr   r#  r   str_entries)r   raw_contentr   r   r   router_iterr   	__class__s          r   rC  z NetworkStatusDocumentV2.__init__h  s6   	
!41+x<1X JJ{+Mzz#';]O<\^k'lm//55AA'#-/7 B K I[IIDL$%5%=@R@R@T%TV^_G
g&
kk'8$
 
t||	#->'-IN_cjNj  g  jm  nr  js  s  t  	t Ok	# dmr   c           	         t         D cg c]
  \  }}|s	| }}}|D ]   }||vst        d|dt        |              t         D cg c]  \  }}|	 }}}|D ]>  }||v st        ||         dkD  st        d|t        ||         t        |       fz         dt	        |j                               d   k7  rt        dt        |       z        y c c}}w c c}}w )Nz*Network status document (v2) must have a '' line:
r[   zINetwork status document (v2) can only have a single '%s' line, got %i:
%sr   r   z[Network status document (v2) are expected to start with a 'network-status-version' line:
%s)NETWORK_STATUS_V2_FIELDSr   rI  r   listkeys)r   r   fieldis_mandatoryrequired_fieldsr   _single_fieldss           r   rH  z*NetworkStatusDocumentV2._check_constraints  s8   :Rc!6%VbucOc" k		V]_bcg_hijjk
 .FFzqUFMF  U	G	GG$4 5 9eipruv}  F  wG  sH  JM  NR  JS  iT  T  U  	UU  4#7#::ux{  }A  yB  B  C  C ; d Gs   
CC
CNr   FF)r   r   r   r   TYPE_ANNOTATION_NAME"_parse_network_status_version_liner  _parse_fingerprint_line_parse_contact_line_parse_dir_signing_key_line_parse_client_versions_line_parse_server_versions_line_parse_published_line_parse_dir_options_line_parse_directory_signature_line
ATTRIBUTESPARSER_FOR_LINEclassmethodr   rC  rH  __classcell__rM  s   @r   r   r     s    8 , 89-.,--.12)*567878-.+, ?@89*& A(*"222&*:/  "HCr   r   c                 $   t        d|      }d|v r|j                  dd      \  }}n|d}}|j                         st        d|z        t	        |      | _        || _        |dk(  | _        | j
                  dk7  rt        d| j
                  z        y )	Nr   r   r[   nszLNetwork status document has a non-numeric version: network-status-version %s	microdescrF   zFExpected a version 3 network status document, got version '%s' instead)r   r   r   r   r   r   version_flavorr   )r   r   r   r   r   s        r   )_parse_header_network_status_version_linerm    s     )7
3%E\kk#q)OGVTVG		
cfkk
ll7|*$*"(K"7*1
]`j`r`rr
ss r   c                     t        d|      }|dk(  rd\  | _        | _        y |dk(  rd\  | _        | _        y t        d|z        )Nr*   	consensus)TFvoteFTz`A network status document's vote-status line can only be 'consensus' or 'vote', got '%s' instead)r   is_consensusis_voter   r   r   r   s      r   _parse_header_vote_status_lineru    sW     
(%
k2=/JZ/2=/JZ/
wz  A  Ar   c                 
   | j                   r| j                  rdg| _        t        d|      g }}|j	                  d      D ]:  }|j                         st        d|z        |j                  t        |             < || _        y )Nr[   r+   r   z\A network status document's consensus-methods must be a list of integer values, but was '%s')	_lazy_loadingrs  consensus_methodsr   r   r   r   r  r   )r   r   r   rx  entrys        r   $_parse_header_consensus_methods_linerz    s     *"4"4$%3J #$7A2	%{{3 )e==?ux}}~~SZ(	) "3*r   c                     | j                   r| j                  rd| _        t        d|      }|j	                         st        d|z        t        |      | _        y )Nr[   r,   zMA network status document's consensus-method must be an integer, but was '%s')rw  rr  consensus_methodr   r   r   r   rt  s      r   #_parse_header_consensus_method_liner}    sQ     *"9"9"#J
#W
-%	
dgll
mm #E
*r   c                    t        d|      }|j                  d      }t        |      dk(  rM|d   j                         r:|d   j                         r't	        |d         | _        t	        |d         | _        y t        d|z        )Nr0   r   ra   r   r[   z^A network status document's 'voting-delay' line must be a pair of integer values, but was '%s')r   r   r   r   r   
vote_delay
dist_delayr   r   r   r   
value_comps       r   _parse_header_voting_delay_liner    s|     
)%{{3*_jm335*Q-:O:O:Q
1.J
1.J
ux}}
~~r   c                       fd}|S )Nc                    t        |      g }}|j                  d      D ]1  }	 |j                  t        j                  j                  |             3 t        | |       y # t        $ r t        dd|dd|      w xY w)Nr  zNetwork status document's 'z' line had 'z'', which isn't a parsable tor version: r   )r   r   r  r   r   _get_versionr   r   )r   r   r   ry  r   r   s       r   r   z$_parse_versions_line.<locals>._parse  s    GW-r7ES! WWt||0078W J	7+  Wv}  @E  GN  PU  V  W  	WWs   .A##!Br   )r   r   r   s   `` r   _parse_versions_liner    s    	, 
-r   c           	      Z   t        d|      j                         i }}t        d|      D ]^  \  }}	 |j                  d      r&t	        d|d d j                  ddd      z         ||<   n!d|v rt	        |      ||<   nt        |      ||<   ` || _        y # t        $ r t        d|z        w xY w)	Nr3   %z0.rw   . r[   zjNetwork status document's 'flag-thresholds' line is expected to have float values, got: flag-thresholds %s)	r   stripr   endswithfloatreplacer   r   flag_thresholds)r   r   r   
thresholdskeyr
  s         r   "_parse_header_flag_thresholds_liner    s     .8>>@"% 159 Mhc3M	c	
  s3Bx'7'7R'C CD
3#:*
3c(
3M  **  M  D  GL  L  M  MMs   ABB*c                     | j                   r"| j                  rt        t              ni | _        t        d|      }|dk7  r#t        d|d      | _        | j                          y y )Nr>   r  T)rw  _default_paramsrF  DEFAULT_PARAMSr>   r   _parse_int_mappings_check_params_constraintsrt  s      r   _parse_header_parameters_liner    sZ     0:0J0J^,PRJ
7
#%
b[+HeTBJ((* r   c                 <    t        d|      }|rt        d|z        y )Nr?   ziA network status document's 'directory-footer' line shouldn't have any content, got 'directory-footer %s')r   r   rt  s      r   _parse_directory_footer_liner  $  s;     #W
-%

  A  DI  I  J  J r   c           
      `   g }|d   D ]  \  }}}|j                  d      dvrt        d|z        |r|dk7  rt        d|z        |j                  d      dk(  rd}|j                  dd      \  }}n|j                  dd	      \  }}}|j                  t	        ||||d
              || _        y )Nr)   r   )r[   ra   zAuthority signatures in a network status document are expected to be of the form 'directory-signature [METHOD] FINGERPRINT KEY_DIGEST', received: %sr  zK'directory-signature' should be followed by a SIGNATURE block, but was a %sr[   r   ra   Tr   )countr   r   r  r  r  )	r   r   r  	sig_valuer  r  methodr!   
key_digests	            r   &_parse_footer_directory_signature_liner  -  s    */67L/M k+i^s6)  n  qz  z  {  {Z;6dgqqrrsq f )Q 7k:(1Q(?%fk:'Zdhijk %*r   c           	      2   g }|d   D ]  \  }}}|j                  dd      }t        |      dk  rt        d|z        |d d \  }}}i }	t        |      dk(  rt        d|d         D ]
  \  }
}||	|
<    |j	                  t        ||||	              || _        y )Nr1   r   rF   z<'package' must at least have a 'PackageName Version URL': %sr   )r   r   r   r   r  r   packages)r   r   package_versionsr   rV  r  r   r   r   r   r  r
  s               r   _parse_package_liner  B  s    Y' IkeQS!$J
:UX]]^^#BQD'3G
:!#Iz!}= (#s N4#wGHI )*r   c           
      R   g }|d   D ]  \  }}}|j                         }t        |      dk  rt        d|z        |d d \  }}}}	t        |      dk\  r|d   nd }
|j                         st        d|z        |j	                  t        t        |      |||	|
              || _        y )Nr5   r   zO'shared-rand-commit' must at least have a 'Version AlgName Identity Commit': %s   zBThe version on our 'shared-rand-commit' line wasn't an integer: %s)r   r   r   r   r  r   r   shared_randomness_commitments)r   r   commitmentsr   rV  r  r   r   r   r   r   s              r   _parsed_shared_rand_commitr  W  s     +12 fkeQJ
:hkppqq+5bq>(GY&!*o2Z]F??[^ccdd1#g,	8U[]cdef .9**r   c                     t        d|      }|j                  d      }t        |      dk(  r1|d   j                         rt	        |d         | _        |d   | _        y t        d|z        )Nr6   r   ra   r   r[   zyA network status document's 'shared-rand-previous-value' line must be a pair of values, the first an integer but was '%s')r   r   r   r   r   'shared_randomness_previous_reveal_count shared_randomness_previous_valuer   r  s       r   !_parse_shared_rand_previous_valuer  m  sy     -w
7%{{3*_jm3359<Z]9KJ62<Q-J/
  Q  TY  Y  Z  Zr   c                     t        d|      }|j                  d      }t        |      dk(  r1|d   j                         rt	        |d         | _        |d   | _        y t        d|z        )Nr7   r   ra   r   r[   zxA network status document's 'shared-rand-current-value' line must be a pair of values, the first an integer but was '%s')r   r   r   r   r   &shared_randomness_current_reveal_countshared_randomness_current_valuer   r  s       r    _parse_shared_rand_current_valuer  z  sy     ,g
6%{{3*_jm3358;JqM8JJ51;AJ.
  P  SX  X  Y  Yr   c                 `    t        d|      }i }t        d|      D ]
  \  }}|||<    || _        y )Nr8   )r   r   bandwidth_file_headersr   r   r   resultsr  r
  s         r   _parse_bandwidth_file_headersr    sD     )7
3%' 8%@ hc3GCL '.*#r   c                 `    t        d|      }i }t        d|      D ]
  \  }}|||<    || _        y )Nr9   )r   r   bandwidth_file_digestr  s         r   _parse_bandwidth_file_digestr    sD     ('
2%' 7? hc3GCL &-*"r   r-   valid_afterr.   fresh_untilr/   valid_untilr2   known_flagsc                 P    | j                  d      D cg c]  }|s|	 c}S c c}w )Nr   r  )r  ry  s     r   r  r    s>    wxw~w~  @C  xD  dNns  HMdi  dN   dNs   ##r@   bandwidth_weightsc                     t        d| d      S )Nr@   T)r  r  s    r   r  r    s'      vI  J]  _`  bf  vg r   r4    is_shared_randomness_participater:   recommended_client_protocolsr;   recommended_relay_protocolsr<   required_client_protocolsr=   required_relay_protocolsc                       e Zd ZdZi ddefddefddefdd	efd
d	efdg efddefddefdde	fdde
fddefddefddefdg efdg efdg efdg efi efi efi efi efi efi efdefdefdefdefi efi efg efi efdZi dededededede	de
deded ed!ed"ed#ed$ed%ed&ed'eeeeeeed(Zeeed)Z e!d6d*       Z"e!d7d+       Z#d8 fd,	Z$d- Z%d. Z&d/ Z'd0 Z( fd1Z)d2 Z*d3 Z+d4 Z,d5 Z- xZ.S )9r   a  
  Version 3 network status document. This could be either a vote or consensus.

  :var dict routers: fingerprint to :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`
    mapping for relays contained in the document

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

  **Consensus Attributes:**

  :var int consensus_method: method version used to generate this consensus
  :var dict bandwidth_weights: dict of weight(str) => value(int) mappings

  :var int shared_randomness_current_reveal_count: number of commitments
    used to generate the current shared random value
  :var str shared_randomness_current_value: base64 encoded current shared
    random value

  :var int shared_randomness_previous_reveal_count: number of commitments
    used to generate the last shared random value
  :var str shared_randomness_previous_value: base64 encoded last shared random
    value

  **Vote Attributes:**

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

  :var dict recommended_client_protocols: recommended protocols for clients
  :var dict recommended_relay_protocols: recommended protocols for relays
  :var dict required_client_protocols: required protocols for clients
  :var dict required_relay_protocols: required protocols for relays
  :var dict bandwidth_file_headers: headers from the bandwidth authority that
    generated this vote
  :var dict bandwidth_file_digest: hashes of the bandwidth authority file used
    to generate this vote, this is a mapping of hash functions to their resulting
    digest value

  **\*** attribute is either required when we're parsed with validation or has
  a default value, others are left as None if undefined

  .. versionchanged:: 1.4.0
     Added the packages attribute.

  .. versionchanged:: 1.5.0
     Added the is_shared_randomness_participate, shared_randomness_commitments,
     shared_randomness_previous_reveal_count,
     shared_randomness_previous_value,
     shared_randomness_current_reveal_count, and
     shared_randomness_current_value attributes.

  .. versionchanged:: 1.6.0
     Added the recommended_client_protocols, recommended_relay_protocols,
     required_client_protocols, and required_relay_protocols attributes.

  .. versionchanged:: 1.6.0
     The is_shared_randomness_participate and shared_randomness_commitments
     were misdocumented in the tor spec and as such never set. They're now an
     attribute of votes in the **directory_authorities**.

  .. versionchanged:: 1.7.0
     The shared_randomness_current_reveal_count and
     shared_randomness_previous_reveal_count attributes were undocumented and
     not provided properly if retrieved before their shred_randomness_*_value
     counterpart.

  .. versionchanged:: 1.7.0
     Added the bandwidth_file_headers attributbute.

  .. versionchanged:: 1.8.0
     Added the bandwidth_file_digest attributbute.
  r   Nrl  rj  rr  Trs  Fr   rx  r'   r|  r  r  r  r  r  r  r!  r  r  )r  r  r  r  r  r>   r  r  r  r  r  r  r  r  r   r*   r+   r,   r-   r.   r/   r0   r%   r&   r1   r2   r3   r:   r;   r<   )r=   r>   r6   r7   r8   r9   )r?   r@   r)   c                    |rt        d| j                  z        |i n
t        |      }|j                  d      dk(  }|rdt	               d}nddi}|r|t
        j                  |      g}|j                         D ]  \  }}	|r||v r||vs|	||<    t        ||d	d
ddddt	               fdt	               fdt	               fddddddfdddt               dt               t        d      ff      }
|rd|
v r|
j                  d      dz   }n.d|
v r|
j                  d       dz   }n|r|
d!z  }
t        |
      dz   }t        j                  j                  j!                  d"j#                  |D cg c]  }t%        |       c}      d"z         }|
d | |z   |
|d  z   }
|rd|
v r|
j                  d      dz   }n.d|
v r|
j                  d       dz   }n|r|
d!z  }
t        |
      dz   }t        j                  j                  j!                  d"j#                  |D cg c]  }t%        |       c}      d"z         }|
d | |z   |
|d  z   }
|
S c c}w c c}w )#Nr,  r*   rp  z1 9)r+   r'   r,   9)rs  )r   3)r*   ro  )r+   N)r,   N)r'   Nr-   r.   r/   )r0   z300 300)r%   N)r&   N)r1   N)r2   zPAuthority BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid)r>   N)r?   r  )r@   Nr)   r   r  s   directory-footers   
directory-footerr[   s   directory-signatures   
directory-signaturer@  
)r   r   rF  getr   DirectoryAuthoritycreateitemsr	   r   r   findr   r   r   	str_tools	_to_bytesr   rI  )r0  r1  r2  r3  authoritiesrG  rs  extra_defaultskr  desc_content
footer_divaauthority_contentrA   router_contents                   r   r   zNetworkStatusDocumentV3.contentS  s    ?#,, NOO24:Dhh}%/G-2Pn*C0n;&'...ABk$$& 1	Q'\D=Q	 'tW%"! ln%ln%ln%!i7  !+>+@BUBWYlmxYyz{L. 		,!&&'<=A
!\1!&&'?@1D

%
,&*
))--77		S^B_a3q6B_8`cg8gh!+:.1BB\R\R]E^^l		,!&&'<=A
!\1!&&'?@1D

%
,&*
yy**44TYYPW?X1A?X5Y\`5`an!+:.?,z{B[[l# C` @Ys   0I	Ic           	      <     | | j                  |||||      |      S )Nr   r   )r0  r1  r2  r   r3  r  rG  s          r   r  zNetworkStatusDocumentV3.create  s!    s{{4$WERZ[[r   c                    t         t        |   ||        t        j                  |      }d| _        g | _        || _        | j                  ||       t        t        j                  j                  j                  ||t        t        t         t"        t$        f| j&                  f            | _        |rQ| j&                  rEt+        | j(                        dk7  r-t-        dt+        | j(                        | j(                  fz        t        j                  j                  j                  ||| j.                  rt0        nt2        t         t"        t$        f| f      }t5        d |D              | _        | j9                  ||       y)a~  
    Parse a v3 network status document.

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

    :raises: **ValueError** if the document is invalid
    r5  Fr7  r[   zPVotes should only have an authority entry for the one that issued it, got %i: %sc              3   8   K   | ]  }|j                   |f  y wr%  r:  r;  s     r   r=  z3NetworkStatusDocumentV3.__init__.<locals>.<genexpr>  r>  r?  N)rB  r   rC  rD  rE  r  r  r  _headertupler   r   r   r   r  
AUTH_STARTr   r   r   rs  directory_authoritiesr   r   r   r   r   rF  rG  _footer)r   rK  r   default_paramsr   rL  rM  s         r   rC  z NetworkStatusDocumentV3.__init__  sn    

!41+x<1XJJ{+M -2D))+D&)DLL)!&t'J'J'V'V& +\?KLL? (W ( "D DLLS)C)C%D%Iimpqu  rL  rL  nM  OS  Oi  Oi  mj  j  k  k//55AA040G0G,M`#*O<7 B K I[IIDLLL)r   c                     t        | t              rt        ddd      S | j                  s!t        | j                  sddd      S ddd      S t        ddd      S )Nbridge-network-statusr[   r   znetwork-status-consensus-3znetwork-status-vote-3z$network-status-microdesc-consensus-3)
isinstancer   r   r   rs  r   s    r   type_annotationz'NetworkStatusDocumentV3.type_annotation  s_    $343Q::$$8klnoppRiklnopp BAqIIr   c                     | j                   t        j                  j                         cxk  xr | j                  k  S c S )aJ  
    Checks if the current time is between this document's **valid_after** and
    **valid_until** timestamps. To be valid means the information within this
    document reflects the current network state.

    .. versionadded:: 1.8.0

    :returns: **True** if this consensus is presently valid and **False**
      otherwise
    )r  datetimeutcnowr  r  s    r   is_validz NetworkStatusDocumentV3.is_valid  5     h//668K4;K;KKKKKr   c                     | j                   t        j                  j                         cxk  xr | j                  k  S c S )a&  
    Checks if the current time is between this document's **valid_after** and
    **fresh_until** timestamps. To be fresh means this should be the latest
    consensus.

    .. versionadded:: 1.8.0

    :returns: **True** if this consensus is presently fresh and **False**
      otherwise
    )r  r  r  r  r  s    r   is_freshz NetworkStatusDocumentV3.is_fresh  r  r   c                 
   | j                  dd      }t        j                  |      j                         j	                         }d\  }}t        | j                        dz  }t        |D cg c]  }|j                  |j                  f c}      }| j                  D ]J  }	|	j                  |vr| j                  ||	j                     |	j                        }
|dz  }|
|k(  sF|dz  }L ||k  rt        d|||fz        yc c}w )a7  
    Validates we're properly signed by the signing certificates.

    .. versionadded:: 1.6.0

    :param list key_certs: :class:`~stem.descriptor.networkstatus.KeyCertificates`
      to validate the consensus against

    :raises: **ValueError** if an insufficient number of valid signatures are present.
    r   zdirectory-signature )r   r   g       @r[   zJNetwork Status Document has %i valid signatures out of %i total, needed %iN)r   r   r   	hexdigestupperr   r  rF  r!   r  r   _digest_for_signaturer&  r   )r   	key_certsdigest_contentlocal_digestvalid_digeststotal_digestsrequired_digestscertsigning_keyssigsigned_digests              r   validate_signaturesz+NetworkStatusDocumentV3.validate_signatures  s    (()ACYZN<</99;AACL#' M=4??+c1)T$$**D,<,<=TUL 	\	)00cll1KS]][mqm	,	& ''cgt  wD  FV  gW  W  X  X ( Us   *D c                     | j                   rW| j                  | j                  d| j                         | j                  | j                  d| j
                         d| _         t        t        | #         S )NFparser_for_line)	rw  r   _header_entries_HEADER_PARSER_FOR_LINE_footer_entries_FOOTER_PARSER_FOR_LINErB  r   get_unrecognized_lines)r   rM  s    r   r  z.NetworkStatusDocumentV3.get_unrecognized_lines  sa    
kk$&&A]A]k^
kk$&&A]A]k^ d($FHHr   c                     | j                   | j                   |k\  S | j                  )t        | j                  D cg c]
  }||k\  s	| c}      S yc c}w )a8  
    Checks if we meet the given consensus-method. This works for both votes and
    consensuses, checking our 'consensus-method' and 'consensus-methods'
    entries.

    :param int method: consensus-method to check for

    :returns: **True** if we meet the given consensus-method, and **False** otherwise
    F)r|  rx  bool)r   r  xs      r   meets_consensus_methodz.NetworkStatusDocumentV3.meets_consensus_method%  sX     (""f,,				+d44DV1DEE Es   
AAc                 >   t         j                  dt        t        t        t
        f|            }t        ||      }t        D cg c]  }|d   	 }}|r"t        |j                               D ]=  \  }}t        |      dkD  s||v s|dk7  s |dk7  s&t        d|t        |      fz         | j                  rt        t              | _        | j!                  ||| j"                         | j%                  d      s&d	t        |j'                               v rt        d
      t)        | |t               | j*                  r| j,                  sd| _        y | j.                  r| j0                  s	dg| _        y y y || _        | j4                  j7                  |       y c c}w )Nr   r   r[   r1   r5   ANetwork status documents can only have a single '%s' line, got %ir  r`   r>   z[A network status document's 'params' line should only appear in consensus-method 7 or later)r   r   r   r  r   r   r
   HEADER_STATUS_DOCUMENT_FIELDSrQ  r  r   r   r  rF  r  r>   r   r  r  rR  (_check_for_missing_and_disallowed_fieldsrr  r|  rs  rx  r  rJ  update)	r   r   r   r   r   r1  header_fieldsr   valuess	            r   r  zNetworkStatusDocumentV3._header7  sq   jj2J|3\^klmG$Wh7G)FGT!WGMG "'--/2 y/'6v;?w-7Gy<PU\`tUt^biknoukvawwx
xy 
		>*
kk'8t7S7SkT ((+D<P0Pvww.tW>[\ 
		4#8#8 !<< 6 6"# !7< %d
mm7#; Hs   Fc                    t        |j                         |      }t        D cg c]  }|d   	 }}|rt        |j	                               D ]C  \  }}t        |      dkD  s||v s|dk(  r| j                  r,t        d|t        |      fz         | j                  ||| j                         |rw| j                  d      r*t        |j                               d   dk7  r5t        d      t        |j                               d   dk7  rt        d	      t        | |t               y y || _        | j                  j                  |       y c c}w )
Nr   r[   r)   r  r  	   r?   zkNetwork status document's footer should start with a 'directory-footer' line in consensus-method 9 or laterzkNetwork status document's footer should start with a 'directory-signature' line prior to consensus-method 9)r
   r   FOOTER_STATUS_DOCUMENT_FIELDSrQ  r  r   rr  r   r   r  r  rR  r  r  rJ  r  )r   r   r   r   r1  footer_fieldsr   r  s           r   r  zNetworkStatusDocumentV3._footerY  sQ   $]%7%7%98DG)FGT!WGMG!'--/2 {/'6 v;?w-722t7H7H`dkmpqwmxcyyzz{ kk'8t7S7SkT 
&&q)',,.!!$(::  K  L  L',,.!!$(==  K  L  L0w@]^ 
 %d
mm7#9 Hs   Ec                 L   | j                   j                         D ]  \  }}t        j                  |t        t
        f      \  }}|dk(  r| j                   j                  d|      }n!|dk(  r| j                   j                  d|      }||k  s||kD  swt        d||||fz         y)zR
    Checks that the params we know about are within their documented ranges.
    rO   rM   rT   rS   zE'%s' value on the params line must be in the range of %i - %i, was %iN)r>   r  PARAM_RANGEr  	MIN_PARAM	MAX_PARAMr   )r   r  r   minimummaximums        r   r  z1NetworkStatusDocumentV3._check_params_constraintsy  s    
 kk'') C
U$y).DEgw 
"	"++//-9%%++///7;	EGO`dgipry  |A  dB  B  C  	CCr   )Nr   FNN)Nr   TFNNrq  )/r   r   r   r   rm  ru  rz  ra  r}  _parse_header_valid_after_line_parse_header_fresh_until_line_parse_header_valid_until_liner  "_parse_header_client_versions_line"_parse_header_server_versions_liner  _parse_header_known_flags_liner  (_parse_recommended_client_protocols_line'_parse_recommended_relay_protocols_line%_parse_required_client_protocols_line$_parse_required_relay_protocols_liner  r  r  r  r  r  $_parse_footer_bandwidth_weights_linerd  r  r  r  rf  r   r  rC  r  r  r  r  r  r  r  r  r  rg  rh  s   @r   r   r     s=   ]~!?@!tFG! T9:! 56	!
 5"KL! "BC! $-.! BC! D89! D89! D89! 489! 489! >?! >?!  ()!!" B67#!$ >?%')Q$R$&(O#P"$&K!L!#%I J01046W/X)-/P(Q/35U.V(,.N'O!#@A ">?=>BCA!*FG1 = ;	
 & 1 1 1 3 9 9 " 1 9 #$L  "#J!"  !F#$ !E+"C!A;9/6 5=A H HT \ \/*b
JLL XDI$ $D$@Cr   r   c                    g g }}|D ]  \  }}}}|rA| j                   r|s| j                  r'|r%||j                         vs9|j                  |       K| j                   r|r| j                  sf|ri||j                         v s||j                  |        |rt	        ddj                  |      z        |rt	        ddj                  |      z        y)a#  
  Checks that we have mandatory fields for our type, and that we don't have
  any fields exclusive to the other (ie, no vote-only fields appear in a
  consensus or vice versa).

  :param NetworkStatusDocumentV3 document: network status document
  :param dict entries: ordered keyword/value mappings of the header or footer
  :param list fields: expected field attributes (either
    **HEADER_STATUS_DOCUMENT_FIELDS** or **FOOTER_STATUS_DOCUMENT_FIELDS**)

  :raises: **ValueError** if we're missing mandatory fields or have fields we shouldn't
  z6Network status document is missing mandatory field: %sz, z]Network status document has fields that shouldn't appear in this document type or version: %sN)rr  rs  rR  r  r   r   )	documentr   fieldsmissing_fieldsdisallowed_fieldsrS  in_votesin_consensus	mandatorys	            r   r  r    s     ')"#.28 (.eX|Yx,,8CSCSX`	glln	$e$


(:J:JS[	',,.	   '( 
MPTPYPYZhPii
jj
tw{  xA  xA  BS  xT  T  U  U r   c                 2   i g }}d| d|d}t        | |      D ]\  \  }}|r|D ]  }||kD  s	t        |dz         	 |j                  d      r
t               t        |      ||<   |j	                  |       ^ |S # t        $ r t        |d|z  z        w xY w)Nz+Unable to parse network status document's 'z' line (%s): 'z&parameters must be sorted by their key+z'%s' is a non-numeric value)r   r   r   r   r  )	r   r   r   r  	seen_keyserror_templater  r
  	prior_keys	            r   r  r    s    
 29'W^`ef./ hc3  V)s?>,TTU
UVO 
	lXgcl S#& 
.  O~)F)LMNNOs   )A;;Bc                    t        d|      }|j                  d      }t        |      dk  rt        d|z        t        j
                  j                  j                  |d   j                  d            st        d|d   z        t        j
                  j                  j                  |d         st        d	|d   z        |d
   st        d|z        t        j
                  j                  j                  |d         st        d|d   z        t        j
                  j                  j                  |d   d      st        d|d   z        t        j
                  j                  j                  |d         st        d|d   z        |d   | _        |d   | _        |d
   | _        |d   | _        |d   dk(  rd nt#        |d         | _        t#        |d         | _        | j                  j)                  d      | _        y )Nr   r      zGAuthority entry's 'dir-source' line must have six values: dir-source %sr   -legacyz#Authority's nickname is invalid: %sr[   z"Authority's v3ident is invalid: %sra   r   rF   r   r   Tr   r   r  z!Authority's ORPort is invalid: %sr   )r   r   r   r   r   r   	tor_toolsis_valid_nicknamerstripis_valid_fingerprintr   r   r   nicknamev3identr  r  r   r  or_portr  	is_legacyr  s       r   _parse_dirauth_source_linerA    s    w
'%KK$/A
^aff
gg				.	.q/A/H/H/S	T
:_Q=OO
PP9933OA4FG
9OA<NN
OO1
IEQ
RR9955oa6HI
IO\]L^^
__99--oa.@t-T
9OA<NN
OO99--oa.@A
8?1;MM
NN'**&q)*'**&q)* / 2c 9s?STCU?V*?1-.*#,,55i@*r   legacy-dir-keylegacy_dir_keyvote-digestvote_digestc            	           e Zd ZdZi ddefddefddefddefddefddefd	d
efddefddefddefdd
efdg e	fdde
fdde
fddefddefZeeeeee	e
edZedd       Zedd       Zd fd	Z xZS )r  aC	  
  Directory authority information obtained from a v3 network status document.

  Authorities can optionally use a legacy format. These are no longer found in
  practice, but have the following differences...

  * The authority's nickname ends with '-legacy'.
  * There's no **contact** or **vote_digest** attribute.

  :var str nickname: **\*** authority's nickname
  :var str v3ident: **\*** identity key fingerprint used to sign votes and consensus
  :var str hostname: **\*** hostname of the authority
  :var str address: **\*** authority's IP address
  :var int dir_port: **\*** authority's DirPort
  :var int or_port: **\*** authority's ORPort
  :var bool is_legacy: **\*** if the authority's using the legacy format
  :var str contact: contact information, this is included if is_legacy is **False**

  **Consensus Attributes:**

  :var str vote_digest: digest of the authority that contributed to the consensus, this is included if is_legacy is **False**

  **Vote Attributes:**

  :var str legacy_dir_key: fingerprint of and obsolete identity key
  :var stem.descriptor.networkstatus.KeyCertificate key_certificate: **\***
    authority's key certificate

  :var bool is_shared_randomness_participate: **\*** **True** if this authority
    participates in establishing a shared random value, **False** otherwise
  :var list shared_randomness_commitments: **\*** list of
    :data:`~stem.descriptor.networkstatus.SharedRandomnessCommitment` entries
  :var int shared_randomness_previous_reveal_count: number of commitments
    used to generate the last shared random value
  :var str shared_randomness_previous_value: base64 encoded last shared random
    value
  :var int shared_randomness_current_reveal_count: number of commitments
    used to generate the current shared random value
  :var str shared_randomness_current_value: base64 encoded current shared
    random value

  **\*** mandatory attribute

  .. versionchanged:: 1.4.0
     Renamed our 'fingerprint' attribute to 'v3ident' (prior attribute exists
     for backward compatability, but is deprecated).

  .. versionchanged:: 1.6.0
     Added the is_shared_randomness_participate, shared_randomness_commitments,
     shared_randomness_previous_reveal_count,
     shared_randomness_previous_value,
     shared_randomness_current_reveal_count, and
     shared_randomness_current_value attributes.
  r=  Nr>  r  r  r  r?  r@  Fr"   rE  rC  r  r  r  r  r  r  )r   r"   rB  rD  r4   r5   r6   r7   c                 &   |rt        d| j                  z        |i n
t        |      }|sd|v s|rd|v st               |d<   t	        ||dt               dt               dt               dfdf      }|r|dt        j                         z   z  }|S )	Nr,  rD  r   r   z no.place.com z
 9030 9090)r"   zMike Perry <email>r@  )	r   r   rF  r   r	   r   r   r   r   )r0  r1  r2  r3  rs  r   s         r   r   zDirectoryAuthority.contentE  s     ?#,, NOO24:D MT1g-SZBZ/1d=!$:J:LNaNceye{|}'2 G
 //111gNr   c                 <     | | j                  ||||      ||      S )N)r   rs  r  )r0  r1  r2  r   r3  rs  s         r   r  zDirectoryAuthority.create[  s!    s{{4$8XY`aar   c           	         t         t        |   ||        t        j                  j
                  j                  |      }|j                  d      }|dk7  r t        ||dz   d |      | _	        |d|dz    }nd| _	        t        ||      }|r-dt        |j                               d   k7  rt        d|z        |r9d	|j                  d      }}|r(|d   d   j                         d   j!                  d
      }dgg }
}	|s|	dgz  }	|r!| j                  st        d|z        |
dgz  }
n*|s(| j                  rt        d|z        |s|	dgz  }	|
dgz  }
|	D ]  }||vst        d|d|       |D ]   }||
v s|rdnd}t        d|d|d|       t        |j#                               D ]2  \  }}t%        |      dkD  s|dv st        d|t%        |      |fz         | j'                  ||       n|| _        | j*                  | _        y)a  
    Parse a directory authority entry in a v3 network status document.

    :param str raw_content: raw directory authority entry information
    :param bool validate: checks the validity of the content if True, skips
      these checks otherwise
    :param bool is_vote: True if this is for a vote, False if it's for a consensus

    :raises: ValueError if the descriptor data is invalid
    r5  z
dir-key-certificate-versionrw   r[   Nr   r   zDAuthority entries are expected to start with a 'dir-source' line:
%sFr8  r"   z/Authority votes must have a key certificate:
%srD  z@Authority consensus entries shouldn't have a key certificate:
%srB  zAuthority entries must have a 'rO  voteszconsensus entriesz
Authority z shouldn't have a ')r   r"   rB  rD  z>Authority entries can only have a single '%s' line, got %i:
%s)rB  r  rC  r   r   r  _to_unicoder  r   key_certificater
   rQ  rR  r   r  r   r  r  r   r   rJ  r>  r!   )r   rK  r   rs  r   key_divr   r@  dir_source_entryrU  excluded_fieldsr   
type_labelr  rM  s                 r   rC  zDirectoryAuthority.__init___  sX    

d,[(l,Sii!!--k:G ll:;G"}+GGaKL,A8Ld1%g!d$Wh7GLD$8$;;^bijkk $)7;;|+D!i	$Q'*00215>>yI	*6oI;&	##MPWWX
XM?*^ahhi
i
m_
,/,--$ `''!WV]^_
_`  l'o%")w/B*ZY`bijk
kl "'--/2 @/'6v;?w*dd\`gilmsitv}_~~
@ kk'8$dm ||Dr   )Nr   FF)Nr   TFF)FF)r   r   r   r   rA  r]  _parse_vote_digest_line_parse_legacy_dir_key_line#_parse_shared_rand_participate_liner  r  r  rd  re  rf  r   r  rC  rg  rh  s   @r   r  r    s   5n1201 12 01	
 12 01 %34 )* D12 t78 '0S(T $b*D%E .6W/X '/P(Q -t5U.V  &.N'O!*( -"0*B4"C!A	/  * b bN$ N$r   r  c                 t   t        d|      }d|vrt        d|z        |j                  dd      \  }}t        j                  j
                  j                  |      st        d|z        t        j                  j
                  j                  |      st        d|z        || _        t        |      | _
        y )Nrl   :zZKey certificate's 'dir-address' is expected to be of the form ADDRESS:PORT: dir-address %sr[   zDKey certificate's address isn't a valid IPv4 address: dir-address %sz4Key certificate's dirport is invalid: dir-address %s)r   r   rsplitr   r   r   r   r   r  r   r  )r   r   r   r  dirports        r   _parse_dir_address_linerX    s     
(%
qtyy
zz\\#q)'7				3	3G	<
[^cc
dd99--g6
KeS
TT*G*r   rk   rn   ro   expiresrm   identity_keyrp   	crosscertzID SIGNATURErq   certificationc                        e Zd ZdZdZdefdefdefdefdefde	fde
fdefdefdefd
Zeeee	e
eeeed	Zedd       Zd	 fd	Z xZS )
r   a  
  Directory key certificate for a v3 network status document.

  :var int version: **\*** version of the key certificate
  :var str address: authority's IP address
  :var int dir_port: authority's DirPort
  :var str fingerprint: **\*** authority's fingerprint
  :var str identity_key: **\*** long term authority identity key
  :var datetime published: **\*** time when this key was generated
  :var datetime expires: **\*** time after which this key becomes invalid
  :var str signing_key: **\*** directory server's public signing key
  :var str crosscert: signature made using certificate's signing key
  :var str certification: **\*** signature of this key certificate signed with
    the identity key

  **\*** mandatory attribute
  zdir-key-certificate-3N)
r   r  r  r!   rZ  r'   rY  r  r[  r\  )	rk   rl   r!   rn   ro   rm   r$   rp   rq   c                     |rt        d| j                  z        t        ||ddt               fdt	               fdt	               fdt        d      fdt        d      ffd	t        d
      ff      S )Nr,  )rk   r  r!   rn   ro   rm   r  r$   rq   r  )r   r   r	   r   r   r   r/  s       r   r   zKeyCertificate.content  s     ?#,, NOOtW*)+,LN+,.)./?@A-.>?@/  3K @A	 	r   c                    t         t        |   ||        t        ||      }|rdt	        |j                               d   k7  rt        d|z        dt	        |j                               d   k7  rt        d|z        t        D ]M  \  }}|r||vrt        d|d	|      t        |j                  |g             }|d
kD  s>t        d|||fz         | j                  ||       y || _        y )Nr5  rk   r   zIKey certificates must start with a 'dir-key-certificate-version' line:
%srq   rw   zAKey certificates must end with a 'dir-key-certification' line:
%szKey certificates must have a 'rO  r[   z=Key certificates can only have a single '%s' line, got %i:
%s)rB  r   rC  r
   rQ  rR  r   KEY_CERTIFICATE_PARAMSr   r  r   rJ  )r   rK  r   r   r   rT  entry_countrM  s          r   rC  zKeyCertificate.__init__
  s   	.$(h,(O$[(;G	&$w||~*>q*A	Aeituvv"d7<<>&:2&>>]almnn
 $: C
'<G72GU`ab
b'++gr23?[_fhs  vA  _B  B  C  CC kk'8$dmr   rX  rY  )r   r   r   r   rZ  '_parse_dir_key_certificate_version_linerX  r\  _parse_identity_key_line_parse_dir_key_published_line_parse_dir_key_expires_line_parse_signing_key_line_parse_dir_key_crosscert_line!_parse_dir_key_certification_linerd  re  rf  r   rC  rg  rh  s   @r   r   r     s    $ 1 =>-../123456121256=>* $K**620.6>
/   r   r   c                   <    e Zd ZdZd
dZd Zd Zd Zd Zd Z	d	 Z
y)r  a  
  Directory signature of a v3 network status document.

  :var str method: algorithm used to make the signature
  :var str identity: fingerprint of the authority that made the signature
  :var str key_digest: digest of the signing key
  :var str signature: document signature
  :var str flavor: consensus type this signature is for (such as 'microdesc'),
    **None** if for the standard consensus
  :param bool validate: checks validity if **True**

  :raises: **ValueError** if a validity check fails
  Nc                 *   |rnt         j                  j                  j                  |      st	        d|z        t         j                  j                  j                  |      st	        d|z        || _        || _        || _        || _        || _	        y )Nz4Malformed fingerprint (%s) in the document signaturez3Malformed key digest (%s) in the document signature)
r   r   r9  r<  r   r  r   r  r&  r   )r   r  r   r  r&  r   r   s          r   rC  zDocumentSignature.__init__3  s~     YY  55h?ORZZ[[YY  55jANQ[[\\DKDM DODNDKr   c                     t        |t              sydD ]:  }t        | |      t        ||      k7  s |t        | |      t        ||            c S   |dd      S )NF)r  r   r  r&  r   T)r  r  getattr)r   otherr  r1  s       r   _comparezDocumentSignature._compareD  sa    e./K A	t	t 4	4gdD)75$+?@@A $r   c                 F    t        t        |       j                               S r%  )hashrI  r  r  s    r   __hash__zDocumentSignature.__hash__N  s    D	!""r   c                 (    | j                  |d       S )Nc                     | |k(  S r%  r   sos     r   r  z*DocumentSignature.__eq__.<locals>.<lambda>R  
    Q!V r   rn  r   rm  s     r   __eq__zDocumentSignature.__eq__Q      == 344r   c                     | |k(   S r%  r   ry  s     r   __ne__zDocumentSignature.__ne__T  s    u}r   c                 (    | j                  |d       S )Nc                     | |k  S r%  r   rt  s     r   r  z*DocumentSignature.__lt__.<locals>.<lambda>X  s
    QU r   rx  ry  s     r   __lt__zDocumentSignature.__lt__W  s    == 233r   c                 (    | j                  |d       S )Nc                     | |k  S r%  r   rt  s     r   r  z*DocumentSignature.__le__.<locals>.<lambda>[  rw  r   rx  ry  s     r   __le__zDocumentSignature.__le__Z  r{  r   )NF)r   r   r   r   rC  rn  rq  rz  r}  r  r  r   r   r   r  r  $  s*    "#545r   r  c                   ~     e Zd ZdZdZdefdefdefdefg e	fg e
fg efdZeeeee	e
edZedd       Zd	 fd	Z xZS )
r   aG  
  Stand alone signature of the consensus. These are exchanged between directory
  authorities when determining the next hour's consensus.

  Detached signatures are defined in section 3.10 of the dir-spec, and only
  available to be downloaded for five minutes between minute 55 until the end
  of the hour.

  .. versionadded:: 1.8.0

  :var str consensus_digest: **\*** digest of the consensus being signed
  :var datetime valid_after: **\*** time when the consensus became valid
  :var datetime fresh_until: **\*** time when the next consensus should be produced
  :var datetime valid_until: **\*** time when this consensus becomes obsolete
  :var list additional_digests: **\***
    :class:`~stem.descriptor.networkstatus.DocumentDigest` for additional
    consensus flavors
  :var list additional_signatures: **\***
    :class:`~stem.descriptor.networkstatus.DocumentSignature` for additional
    consensus flavors
  :var list signatures: **\*** :class:`~stem.descriptor.networkstatus.DocumentSignature`
    of the authorities that have signed the document

  **\*** mandatory attribute
  zdetached-signature-3N)r)  r  r  r  r	  r  r  )rr   r-   r.   r/   rs   rt   r)   c           
          |rt        d| j                  z        t        ||ddt               fdt               fdt               ff      S )Nr,  )rr   (6D3CC0EFA408F228410A4A8145E1B0BB0670E442r-   r.   r/   )r   r   r	   r   r/  s       r   r   zDetachedSignature.content  sQ     ?#,, NOOtWFln%ln%ln%	/  r   c                    t         t        |   ||        t        ||      }|rdt	        |j                               d   k7  rt        d|z        t        D ]Q  \  }}}|r||vrt        d|d|      t        |j                  |g             }|r<|dkD  sBt        d|||fz         | j                  ||       y || _        y )	Nr5  rr   r   zADetached signatures must start with a 'consensus-digest' line:
%sz!Detached signatures must have a 'rO  r[   z@Detached signatures can only have a single '%s' line, got %i:
%s)rB  r   rC  r
   rQ  rR  r   DETACHED_SIGNATURE_PARAMSr   r  r   rJ  )	r   rK  r   r   r   rT  is_multiplera  rM  s	           r   rC  zDetachedSignature.__init__  s    	
T+K\+R$[(;G	tGLLN3A6	6]almnn 1J F
,'<G72wXcde
e'++gr23{Q^bikv  yD  bE  E  F  FF kk'8$dmr   rX  rY  )r   r   r   r   rZ  _parse_consensus_digest_liner  r  r  r  r  r  rd  re  rf  r   rC  rg  rh  s   @r   r   r   ^  s    4 0 ;<89898989 ">?=>* 511128A/ 	 	 r   r   c                   (     e Zd ZdZdZd fd	Z xZS )r   a<  
  Network status document containing bridges. This is only available through
  the metrics site.

  :var dict routers: fingerprint to :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`
    mapping for relays contained in the document
  :var datetime published: time when the document was published
  r  c                    t         t        |   |       d | _        t	        j
                  |      }t        j                  j                  j                  |j                               }|j                  d      rS|j                  dd      d   j                         }	 t        j                  j                  j                  |      | _        n7|r5t        dt        j                  j                  j                  |      z        t        j                   j"                  j%                  ||t&        | f      }t)        d |D              | _        y # t        $ r |rt        d|z        Y ew xY w)Nz
published r   r[   zEBridge network status document's 'published' time wasn't parsable: %szFBridge network status documents must start with a 'published' line:
%s)r   r   c              3   8   K   | ]  }|j                   |f  y wr%  r:  r;  s     r   r=  z7BridgeNetworkStatusDocument.__init__.<locals>.<genexpr>  r>  r?  )rB  r   rC  r'   rD  rE  r   r   r  rK  readliner   r   r  _parse_timestampr   r   r   r   r   rF  rG  )r   rK  r   r   published_linerL  rM  s         r   rC  z$BridgeNetworkStatusDocument.__init__  sR   	
%t5kBDNJJ{+MYY((44]5K5K5MNN  .%++C3A6<<>nu,,==nM 
`cgclclcvcv  dC  dC  DO  dP  P  Q  Q//55AA'7	 B K I[IIDL  ubesst
t us   .E E)(E)rY  )r   r   r   r   rZ  rC  rg  rh  s   @r   r   r     s     1J Jr   r   rY  ){r   collectionsr  r   rD  #stem.descriptor.router_status_entryr   stem.util.str_toolsstem.util.tor_toolsstem.versionstem.descriptorr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rP  r  r  r  r   r   r   r  r`  r  r  r  r  
namedtupler   r   r   r   r   r   r   r   r   r  r  r  r[  r\  r]  r^  r_  r`  ra  rb  rc  r  r   rm  ru  rz  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r!  r"  r'  rS  r#  r$  r%  r&  r   r  r  rA  rR  rQ  r  rX  rb  rd  re  rc  rf  rg  rh  r   objectr  r   r   r   r   r   <module>r     s  4l    	 *         4  &! 8!  
!'5  B	
 B   b  4 u S R q a  1!" *2#$ (*!"!"##'()1<
   / 	9%%"i% B	?% RO	%
 % Ay>% % % I% J% % % y"o% !Y% C#%  [!%" W#%$ v%%& f'%( 6)%* f+%, 1i.-%. /%0 G1%2 '3%4 K5%6 7%8 a^9%: *9;%< &y=%> W?%@  A%B  C%D 0E%F $.(.I%P+[++,<>cd 
!7!7!78T  WO  "P 
	+[++,<>_` 	 04\a  wF  wN  wN LM^:2}J }@W(*0  &99QS\^_%` "4]MR (I> ./@-Qab 01BDU^tu 01BDU^tu -k;G ,]INab "23H+Wb  wJ  #K 12DFXY C3 CDt*A"3"+
*.+ J%*)*9,
Z
Y.	- "7}m!T !6}m!T !6}m!T %9:KM^%_ "%9:KM^%_ "!3M=  ZN  "O '9:MOb  lg  (h $&78QSu&v #+?@^`~+ (*>?\^{*| '(<=XZu(v %';<VXr's $YC3 YCxUB<A@ 88HJZ[ 4]MR ~$ ~$B%& +>>[]fhi*j ' 56I; W 34EyQ +,>P`a *+<mM]^  01DkSa b $45Lo_j$k !UZ Up75 75tQ
 Qh&J"7 &Jr   