
    <i9             	          S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	rSSK
JrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJ r J!r!  SSKJ"r"J#r#J$r$J%r%  Sr&Sr'Sr(Sr)S	r*S
r+Sr,0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS _S!S"_S#S$_S%S&_S'S&_S(S&_S)S*_S*S+S,S-S.S/SS0.Er-S1r.S2r/S3u  r0r10 S4S5_S6S7\14_S8S7\14_S9S7\14_S:S;_SS&\14_SS;_SS<_SS=_SS>_SS?_SS@_S\0SA4_SS&\14_SSB\14_S!SC_S#SD_0 S%S;_S'S;_S(S;_SES;_SFSG\14_SHSI_SJSK_SLSM_SNSO_SPS;_SQS&\14_S)SR_SSSR_STSU_SVSU_SWSK_SXSY_ESZS;S[.Er2 " S\ S]\Rf                  " S]/ S^Q5      5      r4 " S_ S`\Rf                  " S`/ SaQ5      5      r5 " Sb Sc\Rf                  " Sc/ SdQ5      5      r6SSeSe\Rn                  4Sf jr8SSg jr9SSh jr: " Si Sj\5      r;Sk r<Sl r=Sm r>Sn r?\<" SoSpS-5      r@\" SqSq5      rA\" SrSr5      rB\" SsStSu5      rC\" SvSwSx Sy9rD\" SzS{S| Sy9rE\" S}S}5      rF\" S~SS Sy9rG\" SSSSS9rH\" SS5      rI " S S\;5      rJS rKS rLS rMS rNS rOS rPS rQS rRS rSS rTS rUS rVS rWS rXS rYS rZ\" SS5      r[\" SS5      r\\" SS5      r]\P" SvSw5      r^\P" SzS{5      r_\" SSS Sy9r`\" SSS Sy9ra\" SS5      rb\" SS5      rc\" SS5      rd\" SS5      re\" SS5      rf " S S\;5      rgS rhS riS rj\" SS5      rk\" SS5      rl " S S\5      rmS rn\<" SSpS5      ro\" SS}5      rp\" SS5      rq\" SSSu5      rr\" SsStSu5      rs\" SSS5      rt\" SSS5      ru " S S\5      rv " S S\w5      rx " S S\5      ry " S S\;5      rzg)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                       \ rS rSrSrSrg)PackageVersioni  z
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____firstlineno____doc____static_attributes__r       W/home/james-whalen/.local/lib/python3.13/site-packages/stem/descriptor/networkstatus.pyr   r     s    r   r   )nameversionurldigestsc                       \ rS rSrSrSrg)SharedRandomnessCommitmenti  a  
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
r   Nr   r   r   r   r   r     s    	r   r   )r   	algorithmidentitycommitrevealc                       \ rS rSrSrSrg)DocumentDigesti  z
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
r   Nr   r   r   r   r   r     s    r   r   )flavorr   digestFc              +     #    Uc  [         nU[        :X  a  [        [        paOgU[         :X  a  U(       a  [        O[        nOIU[
        :X  a  [
        [        paO3U[        :X  a  U" U R                  5       U40 UD6v   g[        SU-  5      eU[        R                  :X  a  U" U R                  5       U40 UD6v   g[        [        [        [        4U 5      nU(       a  US   R!                  S5      (       a  USS nU R#                  5       n[        [        [        4U SS9  U R#                  5       n	U R%                  5       n
[&        R)                  SXz-   5      nU[        R*                  :X  a  U" X40 UD6v   gU[        R,                  :X  aK  [.        R0                  R2                  R4                  " U U4U[        UU	U" X5      4S	.UD6nU H  nUv   M	     g[        S
U-  5      e7f)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;//.@*FYK33!<>W;))
**,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V_5666
(
=f
==?222OO77CC	  #$ !"2=?	 		M j  8;KK
LLs   G G"c              #     #     [        SU 5      n[        R                  " SS5      S   nU[        X0S5      -  nU(       a?  [        R                  R
                  R                  [        R                  SU5      US9v   OgM~  7f)	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+,<PTUUOOO))88C9Yfn8oo 	s   B Bc              #      #     [        SU SS9nU(       a?  [        R                  R                  R	                  [
        R                  SU5      US9v   OgMT  7f)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     sT       	/0BD[lpqOO));;EJJsL`<anv;ww 	s   AAc                   N    \ rS rSrSr\R                  \R                  4S jr	Sr
g)NetworkStatusDocumenti  z-
Common parent for network status documents.
c                 \   U R                  SS9nU[        R                  :X  a4  [        R                  R                  [        R                  " U5      U5      $ U[        R                  :X  a4  [        R                  R                  [        R                  " U5      U5      $ [        SU-  5      e)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   NetworkStatusDocument.digest  s    " !!(@!AGJOO#__++GLL,A8LL	j''	'__++GNN7,CXNN or{ {||r   r   N)r   r   r   r   r   r   r   r   HEXr   r   r   r   r   r   r     s      *>;M;M }r   r   c                    ^ ^^ UUU 4S jnU$ )Nc                    > [        TU5      nUR                  5       (       d  [        ST< SU< 35      e[        U T[	        U5      5        [	        U5      T:w  a  [        STU4-  5      eg )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   _parse#_parse_version_line.<locals>._parse  sd    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                    [        SU5      nUR                  5       n[        U5      S:  a  [        SU-  5      eUS   (       d  [        SU-  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   S	S
9(       d  [        SUS   -  5      eUS   U l	        US   U l
        US   S:X  a  S U l        g [        US   5      U l        g )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I
IO\]L^^
__99--oa.@t-T
9OA<NN
OO'**&q)* / 2c 9*s?STCU?V*r   c                     / n[        SU5       HK  nUR                  S5      n[        U5      S:  a  [        SU-  5      eUR	                  [        US S 6 5        MM     X l        g )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    sr    '('2c99S>D
4y1}  C  FI  I  J  JNN>48,- 3 #*r   c                    / nUS    Hw  u  p4nUR                  S5      n[        U5      S:  a  [        SU-  5      eU(       a  US:w  a  [        SU-  5      eUR                  [	        US   US   US	   XVS
   SS95        My     X l        g )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%c~99S>D
4y1}  `  cf  f  g  gz[8ehrrss'Qa$q'>ab\cptuv *I &0"r   r   r   r!   r"   r$   signing_keyRSA PUBLIC KEYr%   client_versionsc                 $    U R                  S5      $ N,r   vs    r   <lambda>r"        hihohopshtr   )funcr&   server_versionsc                 $    U R                  S5      $ r  r  r   s    r   r"  r"    r#  r   r'   r(   optionsc                 "    U R                  5       $ Nr  r   s    r   r"  r"    s    XYX_X_Xar   	signaturer  signing_authority)value_attributerr   consensus_digestc                      ^  \ rS rSrSrSrS\4S\4S\4S\4S\4S\	4S\
4/ \4/ \4S\4/ \4S\4S\4S.r\\\\	\
\\\\\S.
r\SS j5       rSU 4S jjrS	 rS
rU =r$ )r   i  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                     U(       a  [        SU R                  -  5      e[        XSS[        5       < S[        5       < S34S[	        5       4SS[        5       4S	[        S
5      44SS[        S5      -   445      $ )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   NetworkStatusDocumentV2.contentX  s     ?#,, NOOt%#7#9;O;QRS)+,(LN#-.>?@/ h)<[)IIJ	 	r   c           	      \  > [         [        U ]  X(       + S9  [        R                  " U5      n[
        R                  S[        [        [        4U5      5      n[        R                  R                  R                  UU[        [        [        4U 4S9n[        S U 5       5      U l        [#        US-   UR%                  5       -   U5      nU(       aW  U R'                  U5        U R)                  Xb5        SU R*                  ;   a$  SU;   a  SU;   d  [-        S	[/        U 5      -  5      eg g X`l        g )
N	lazy_loadr   r   r   section_end_keywordsr   c              3   <   #    U  H  oR                   U4v   M     g 7fr)  r!   .0r   s     r   	<genexpr>3NetworkStatusDocumentV2.__init__.<locals>.<genexpr>|       I[T))40[      
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   rI   NetworkStatusDocumentV2.__init__h  s0   	
!41+<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'$
 
t||	#->'-IN_cjNj  g  jm  nr  js  s  t  	t Ok	# mr   c           	         [          VVs/ s H  u  p#U(       d  M  UPM     nnnU H$  nXQ;  d  M
  [        SU< S[        U 5      < 35      e   [          VVs/ s H  u  p&UPM	     nnnU H@  nXQ;   d  M
  [        X   5      S:  d  M  [        SU[        X   5      [        U 5      4-  5      e   S[	        UR                  5       5      S   :w  a  [        S[        U 5      -  5      eg s  snnf s  snnf )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   rO  r   listkeys)r   r   fieldis_mandatoryrequired_fieldsr   _single_fieldss           r   rN  *NetworkStatusDocumentV2._check_constraints  s   :Rc:R!6%Vbu:ROc"		V]_bcg_hijj #
 .FF-EzU-EMF 		G$4 5 9eipruv}  wG  sH  JM  NR  JS  iT  T  U  	U !  4#7#::ux{  }A  yB  B  C  C ; d Gs   C&C&C,)rP  rM  Nr   FF)r   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   rI  rN  r   __classcell__rS  s   @r   r   r     s    8 , 89-.,--.12)*567878-.+, ?@89*& A(*"222&*:/  "HC Cr   r   c                 .   [        SU5      nSU;   a  UR                  SS5      u  p4OUSpCUR                  5       (       d  [        SU-  5      e[	        U5      U l        X@l        US:H  U l        U R
                  S:w  a  [        SU R
                  -  5      eg )	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_lineru    s     )7
3%E\kk#q)OGVTV			
cfkk
ll7|*$"(K"7*1
]`j`r`rr
ss r   c                     [        SU5      nUS:X  a  Su  U l        U l        g US:X  a  Su  U l        U l        g [        SU-  5      e)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_liner}    sW     
(%
k2=/JZ/2=/JZ/
wz  A  Ar   c                 (   U R                   (       a  U R                  (       a  S/U l        [        SU5      / p2UR	                  S5       H@  nUR                  5       (       d  [        SU-  5      eUR                  [        U5      5        MB     X0l        g )Nr[   r+   r   z\A network status document's consensus-methods must be a list of integer values, but was '%s')	_lazy_loadingr{  consensus_methodsr   r   r   r   r  r   )r   r   r   r  entrys        r   $_parse_header_consensus_methods_liner    sy     *"4"4$%3J #$7A2	{{3e==??ux}}~~SZ(	   "3r   c                     U R                   (       a  U R                  (       a  SU l        [        SU5      nUR	                  5       (       d  [        SU-  5      e[        U5      U l        g )Nr[   r,   zMA network status document's consensus-method must be an integer, but was '%s')r  rz  consensus_methodr   r   r   r   r|  s      r   #_parse_header_consensus_method_liner    sS     *"9"9"#J
#W
-%	
dgll
mm #E
*r   c                 $   [        SU5      nUR                  S5      n[        U5      S:X  aW  US   R                  5       (       a?  US   R                  5       (       a'  [	        US   5      U l        [	        US   5      U l        g [        SU-  5      e)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5*Q-:O:O:Q:Q
1.J
1.J
ux}}
~~r   c                    ^ ^ UU 4S jnU$ )Nc                   > [        TU5      / pUR                  S5       H2  n UR                  [        R                  R                  U5      5        M4     [        U TU5        g ! [         a    [        ST< SU< ST< SU< 35      ef = f)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   r  r   r   s       r   r   $_parse_versions_line.<locals>._parse  s    GW-r7S!Wt||0078 " 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           	      f   [        SU5      R                  5       0 p2[        SU5       Hd  u  pE UR                  S5      (       a&  [	        SUS S R                  SSS5      -   5      X4'   MB  SU;   a  [	        U5      X4'   MW  [        U5      X4'   Mf     X0l        g ! [         a    [        SU-  5      ef = f)	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9hcM	c		
  s3Bx'7'7R'C CD
#:*
c(
 :  *  M  D  GL  L  M  MMs   :B*B?BB0c                     U R                   (       a'  U R                  (       a  [        [        5      O0 U l        [        SU5      nUS:w  a#  [        SUS5      U l        U R                  5         g g )Nr>   r  T)r  _default_paramsrL  DEFAULT_PARAMSr>   r   _parse_int_mappings_check_params_constraintsr|  s      r   _parse_header_parameters_liner    sZ     0:0J0J^,PRJ
7
#%
b[+HeTBJ((* r   c                 F    [        SU5      nU(       a  [        SU-  5      eg )Nr?   ziA network status document's 'directory-footer' line shouldn't have any content, got 'directory-footer %s')r   r   r|  s      r   _parse_directory_footer_liner  $  s;     #W
-%

  A  DI  I  J  J r   c                 d   / nUS    H  u  p4nUR                  S5      S;  a  [        SU-  5      eU(       a  US:w  a  [        SU-  5      eUR                  S5      S:X  a  SnUR                  SS5      u  pxOUR                  SS	5      u  pgnUR                  [	        XgXS
S95        M     X l        g )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+i^s6)  n  qz  z  {  {Z;6dgqqrrsq f )Q 7k:(1Q(?%f:'Zdhij 0N %r   c           	      2   / nUS    H  u  n  nUR                  SS5      n[        U5      S:  a  [        SU-  5      eUS S u  pgn0 n	[        U5      S:X  a  [        SUS   5       H	  u  pXU
'   M     UR	                  [        XgX5      5        M     X l        g )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   r]  r  r   r   r   r   r  r  s               r   _parse_package_liner  B  s    Y'keQS!$J
:UX]]^^#BQD3G
:!#Iz!}=(# > N4#GH ( )r   c           
      Z   / nUS    H  u  n  nUR                  5       n[        U5      S:  a  [        SU-  5      eUS S u  pgp[        U5      S:  a  US   OS n
UR                  5       (       d  [        SU-  5      eUR	                  [        [        U5      XxX5      5        M     X l        g )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   r]  r  r   r   r   r   r   s              r   _parsed_shared_rand_commitr  W  s     +12keQJ
:hkppqq+5bq>(G!*o2Z]F??[^ccdd1#g,	U[de 3 .9*r   c                     [        SU5      nUR                  S5      n[        U5      S:X  a6  US   R                  5       (       a  [	        US   5      U l        US   U l        g [        SU-  5      e)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  s|     -w
7%{{3*_jm33559<Z]9KJ62<Q-J/
  Q  TY  Y  Z  Zr   c                     [        SU5      nUR                  S5      n[        U5      S:X  a6  US   R                  5       (       a  [	        US   5      U l        US   U l        g [        SU-  5      e)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  s|     ,g
6%{{3*_jm33558;JqM8JJ51;AJ.
  P  SX  X  Y  Yr   c                 ^    [        SU5      n0 n[        SU5       H	  u  pEXSU'   M     X0l        g )Nr8   )r   r   bandwidth_file_headersr   r   r   resultsr  r  s         r   _parse_bandwidth_file_headersr    s:     )7
3%' 8%@hcCL A '.#r   c                 ^    [        SU5      n0 n[        SU5       H	  u  pEXSU'   M     X0l        g )Nr9   )r   r   bandwidth_file_digestr  s         r   _parse_bandwidth_file_digestr    s:     ('
2%' 7?hcCL @ &-"r   r-   valid_afterr.   fresh_untilr/   valid_untilr2   known_flagsc                 `    U R                  S5       Vs/ s H  o(       d  M  UPM     sn$ s  snf )Nr   r  )r!  r  s     r   r"  r"    sJ    wxw~w~  @C  xD  dN  xDns  HMdi  xD  dN  dNs   
++r@   bandwidth_weightsc                     [        SU S5      $ )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                   $  ^  \ rS rSrSr0 SS\4_SS\4_SS\4_S	S
\4_SS
\4_S/ \4_SS\4_SS\	4_SS\
4_SS\4_SS\4_SS\4_SS\4_S/ \4_S/ \4_S/ \4_S/ \4_0 \40 \40 \40 \40 \40 \4S\4S\4S\4S\40 \40 \4/ \40 \4S.Er0 S\_S\_S\_S\	_S\_S\
_S\_S\_S \_S!\_S"\_S#\_S$\_S%\_S&\_S'\_S(\_\\\\\\S).Er\ \\S*.r!\"S8S+ j5       r#\"S9S, j5       r$S:U 4S- jjr%S. r&S/ r'S0 r(S1 r)U 4S2 jr*S3 r+S4 r,S5 r-S6 r.S7r/U =r0$ );r   i  aV  
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   Nrt  rr  rz  Tr{  Fr   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.   r/   r0   r%   r&   r1   r2   r3   r:   r;   r<   )r=   r>   r6   r7   r8   r9   )r?   r@   r)   c                    U(       a  [        SU R                  -  5      eUc  0 O
[        U5      nUR                  S5      S:H  nU(       a  S[	        5       S.nOSS0nU(       a  Uc  [
        R                  US9/nUR                  5        H  u  pU(       a  X;   a  M  X;  d  M  XU'   M      [        XS	S
SSSS[	        5       4S[	        5       4S[	        5       4SSSSSS4SSS[        5       < S[        5       < [        S5      < 3445      n
U(       a  SU
;   a  U
R                  S5      S-   nO5SU
;   a  U
R                  S 5      S-   nOU(       a  U
S!-  n
[        U
5      S-   n[        R                  R                  R!                  S"R#                  U Vs/ s H  n[%        U5      PM     sn5      S"-   5      nU
S U U-   XS  -   n
U(       a  SU
;   a  U
R                  S5      S-   nO5SU
;   a  U
R                  S 5      S-   nOU(       a  U
S!-  n
[        U
5      S-   n[        R                  R                  R!                  S"R#                  U Vs/ s H  n[%        U5      PM     sn5      S"-   5      nU
S U U-   XS  -   n
U
$ s  snf s  snf )#Nr0  r*   rx  z1 9)r+   r'   r,   9)r{  )r   3)r*   rw  )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-signaturerF  
)r   r   rL  getr   DirectoryAuthoritycreateitemsr	   r   r   findr   r   r  	str_tools	_to_bytesr   rO  )r4  r5  r6  r7  authoritiesrM  r{  extra_defaultskr!  desc_content
footer_divaauthority_contentrA   router_contents                   r   r   NetworkStatusDocumentV3.contentS  s    ?#,, NOO24:Dhh}%/G-2Pn*C0n;&'...ABk$$&	Q\=Q	 ' 't%"! ln%ln%ln%!i7  !+>+@BUBWYlmxYyz{L. 		,!&&'<=A
!\1!&&'?@1D

%
,&*
))--77		S^B_S^a3q6S^B_8`cg8gh!+:.1BB\R]E^^l		,!&&'<=A
!\1!&&'?@1D

%
,&*
yy**44TYYPW?XPW1APW?X5Y\`5`an!+:.?,{B[[l# C` @Ys   JJc           	      2    U " U R                  XXEU5      US9$ )Nr   r   )r4  r5  r6  r   r7  r  rM  s          r   r  NetworkStatusDocumentV3.create  s    s{{4$WERZ[[r   c                   > [         [        U ]  X(       + S9  [        R                  " U5      nSU l        / U l        X0l        U R                  XB5        [        [        R                  R                  R                  UU[        [        [         ["        [$        4U R&                  4S95      U l        U(       aW  U R&                  (       aF  [+        U R(                  5      S:w  a-  [-        S[+        U R(                  5      U R(                  4-  5      e[        R                  R                  R                  UUU R.                  (       a  [0        O[2        [         ["        [$        4U 4S9n[5        S U 5       5      U l        U R9                  XB5        g)ab  
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
r:  Fr<  r[   zPVotes should only have an authority entry for the one that issued it, got %i: %sc              3   <   #    U  H  oR                   U4v   M     g 7fr)  r?  r@  s     r   rB  3NetworkStatusDocumentV3.__init__.<locals>.<genexpr>  rD  rE  N)rH  r   rI  rJ  rK  r  r  r  _headertupler   r   r   r   r  
AUTH_STARTr   r   r   r{  directory_authoritiesr   r   r   r   r   rL  rM  _footer)r   rQ  r   default_paramsr   rR  rS  s         r   rI   NetworkStatusDocumentV3.__init__  sf    

!41+<1XJJ{+M -2D))+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                     [        U [        5      (       a  [        SSS5      $ U R                  (       d&  [        U R                  (       d  SSS5      $ SSS5      $ [        SSS5      $ )Nbridge-network-statusr[   r   znetwork-status-consensus-3znetwork-status-vote-3z$network-status-microdesc-consensus-3)
isinstancer   r   r   r{  r   s    r   type_annotation'NetworkStatusDocumentV3.type_annotation  sb    $3443Q::$$8klnoppRiklnopp BAqIIr   c                     U R                   [        R                  R                  5       s=:  =(       a    U R                  :  $ s  $ )a.  
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_valid NetworkStatusDocumentV3.is_valid  8     h//668KK4;K;KKKKKr   c                     U R                   [        R                  R                  5       s=:  =(       a    U R                  :  $ 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_fresh NetworkStatusDocumentV3.is_fresh  r  r   c                    U R                  SS5      n[        R                  " U5      R                  5       R	                  5       nSu  pE[        U R                  5      S-  n[        U Vs/ s H  owR                  UR                  4PM     sn5      nU R                   HN  n	U	R                  U;  a  M  U R                  XR                     U	R                  5      n
US-  nX:X  d  MI  US-  nMP     XF:  a  [        SXEU4-  5      egs  snf )a  
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  rL  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_signatures+NetworkStatusDocumentV3.validate_signatures  s    (()ACYZN<</99;AACL#' M4??+c1)T)$**D,<,<=)TUL	\	)00ll1KS]][mqm		&  'cgt  FV  gW  W  X  X ( Us   *!Dc                    > U R                   (       aQ  U R                  U R                  SU R                  S9  U R                  U R                  SU R
                  S9  SU l         [        [        U ]#  5       $ )NFparser_for_line)	r  r   _header_entries_HEADER_PARSER_FOR_LINE_footer_entries_FOOTER_PARSER_FOR_LINErH  r   get_unrecognized_lines)r   rS  s    r   r  .NetworkStatusDocumentV3.get_unrecognized_lines  sa    
kk$&&A]A]k^
kk$&&A]A]k^ d($FHHr   c                     U R                   b  U R                   U:  $ U R                  b-  [        U R                   Vs/ s H  o"U:  d  M
  UPM     sn5      $ gs  snf )a   
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  r  bool)r   r  xs      r   meets_consensus_method.NetworkStatusDocumentV3.meets_consensus_method%  s\     (""f,,				+d44D4V14DEE Es   	A
Ac                    [         R                  S[        [        [        [
        4U5      5      n[        X25      n[         Vs/ s H  oUS   PM	     nnU(       GaE  [        UR                  5       5       HD  u  px[        U5      S:  d  M  Xv;   d  M  US:w  d  M%  US:w  d  M-  [        SU[        U5      4-  5      e   U R                  (       a  [        [        5      U l        U R!                  XBU R"                  S9  U R%                  S5      (       d(  S	[        UR'                  5       5      ;   a  [        S
5      e[)        X[        5        U R*                  (       a  U R,                  (       d  SU l        g U R.                  (       a  U R0                  (       d	  S/U l        g g g X@l        U R4                  R7                  U5        g s  snf )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_FIELDSrX  r  r   r   r  rL  r  r>   r   r  r  rY  (_check_for_missing_and_disallowed_fieldsrz  r  r{  r  r  rP  update)	r   r   r   r   r   r5  header_fieldsr   valuess	            r   r  NetworkStatusDocumentV3._header7  sb   jj2J|3\^klmG$W7G)FG)F!W)FMG "'--/2/'v;?w7Gy<PU\`tUt^biknoukvawwx
x 3 
		>*
kk't7S7SkT ((++D<P0Pvww.t>[\ 
		4#8#8 !<< 6 6"# !7< %
mm7#; Hs   Gc                    [        UR                  5       U5      n[         Vs/ s H  oDS   PM	     nnU(       Ga
  [        UR	                  5       5       HM  u  pg[        U5      S:  d  M  Xe;   d  M  US:X  a  U R                  (       a  M6  [        SU[        U5      4-  5      e   U R                  X2U R                  S9  U(       a~  U R                  S5      (       a,  [        UR                  5       5      S   S:w  a  [        S5      eO+[        UR                  5       5      S   S:w  a  [        S	5      e[        X[        5        g g X0l        U R                  R                  U5        g s  snf )
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_FIELDSrX  r  r   rz  r   r   r  r  rY  r"  r  rP  r#  )r   r   r   r   r5  footer_fieldsr   r%  s           r   r  NetworkStatusDocumentV3._footerY  sN   $]%7%7%98DG)FG)F!W)FMG!'--/2/' v;?w722t7H7H7H`dkmpqwmxcyyzz 3 kk't7S7SkT 
&&q))',,.!!$(::  K  L  L ; ',,.!!$(==  K  L  L0@]^ 
 %
mm7#9 Hs   E'c                 L   U R                   R                  5        H  u  p[        R                  U[        [
        45      u  p4US:X  a  U R                   R                  SU5      nO"US:X  a  U R                   R                  SU5      nX#:  d  X$:  d  Mx  [        SXXB4-  5      e   g)zJ
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  1NetworkStatusDocumentV3._check_params_constraintsy  s    
 kk'')
$y).DEg 
"	"++//-9%%++///7;	EO`dgry  dB  B  C  	C *r   )r  r  r  r  r  r  r  r  r>   rM  r  )Nr   FNN)Nr   TFNNry  )1r   r   r   r   r   ru  r}  r  ri  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_linerl  r  r  r  rn  r   r  rI  r  r  r  r  r  r  r  r  r  r   ro  rp  s   @r   r   r     sC   ]~!?@!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 Cr   r   c                 $   / / pCU H  u  pVpxU(       aX  U R                   (       a  U(       d  U R                  (       a/  U(       a(  XQR                  5       ;  a  UR                  U5        Mc  Me  U R                   (       a  U(       a  U R                  (       d  M  U(       a  M  XQR                  5       ;   d  M  UR                  U5        M     U(       a  [	        SSR                  U5      -  5      eU(       a  [	        SSR                  U5      -  5      eg)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)rz  r{  rY  r  r   r   )	documentr   fieldsmissing_fieldsdisallowed_fieldsrZ  in_votesin_consensus	mandatorys	            r   r"  r"    s     ')"#28.e|x,,8CSCSX`	lln	$e$ 
%


(:J:J:JS[S[	,,.	   ' 39 
MPTPYPYZhPii
jj
tw{  xA  xA  BS  xT  T  U  U r   c                 L   0 / pCSU < SU< S3n[        X5       Hg  u  pgU(       a  U H  nX:  d  M
  [        US-  5      e    UR                  S5      (       a
  [        5       e[        U5      X6'   UR	                  U5        Mi     U$ ! [         a    [        USU-  -  5      ef = f)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    
 29W^`ef./hc )?>,TTU
U !O 
		lXgl S# 0& 
.  O~)F)LMNNOs   -BB#c                 J   [        SU5      nUR                  S5      n[        U5      S:  a  [        SU-  5      e[        R
                  R                  R                  US   R                  S5      5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   5      (       d  [        S	US   -  5      eUS
   (       d  [        SU-  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   SS9(       d  [        SUS   -  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      eUS   U l        US   U l        US
   U l        US   U l        US   S:X  a  S O[#        US   5      U l        [#        US   5      U l        U R                  R)                  S5      U l        g )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_linerW    s    w
'%KK$/A
^aff
gg				.	.q/A/H/H/S	T	T
:_Q=OO
PP9933OA4FGG
9OA<NN
OO1
IEQ
RR9955oa6HII
IO\]L^^
__99--oa.@t-T
9OA<NN
OO99--oa.@A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            	         ^  \ rS rSrSr0 SS\4_SS\4_SS\4_SS\4_SS\4_S	S\4_S
S\4_SS\4_SS\4_SS\4_SS\	4_S/ \
4_SS\4_SS\4_SS\4_SS\4_r\\\\\	\
\\S.r\SS j5       r\SS j5       rSU 4S jjrSrU =r$ )r  i  a  
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.
rS  NrT  r  r  r  rU  rV  Fr"   r[  rY  r  r  r  r  r  r  )r   r"   rX  rZ  r4   r5   r6   r7   c                 \   U(       a  [        SU R                  -  5      eUc  0 O
[        U5      nU(       d   SU;   d  U(       a  SU;   d  [        5       US'   [	        XS[        5       < S[        5       < S[        5       < S34S45      nU(       a  US[        R                  5       -   -  nU$ )	Nr0  rZ  r   r   z no.place.com z
 9030 9090)r"   zMike Perry <email>rF  )	r   r   rL  r   r	   r   r   r   r   )r4  r5  r6  r7  r{  r   s         r   r   DirectoryAuthority.contentE  s     ?#,, NOO24:D MT1g-SZBZ/1d=!$:J:LNaNceye{|}'2 G
 //111gNr   c                 0    U " U R                  XXE5      X5S9$ )N)r   r{  r  )r4  r5  r6  r   r7  r{  s         r   r  DirectoryAuthority.create[  s    s{{4$8Xaar   c           	        > [         [        U ]  X(       + S9  [        R                  R
                  R                  U5      nUR                  S5      nUS:w  a  [        XES-   S U5      U l	        USUS-    nOSU l	        [        XB5      nU(       a.  S[        UR                  5       5      S   :w  a  [        SU-  5      eU(       Gan  S	UR                  S5      pU(       a(  US   S   R                  5       S   R!                  S
5      nS// pU(       d  U	S/-  n	U(       a&  U R                  (       d  [        SU-  5      eU
S/-  n
O9U(       d2  U R                  (       a  [        SU-  5      eU(       d  U	S/-  n	U
S/-  n
U	 H  nX;  d  M
  [        SU< SU< 35      e   U H*  nX;   d  M
  U(       a  SOSn[        SU< SU< SU< 35      e   [        UR#                  5       5       H6  u  p[%        U5      S:  d  M  US;   d  M  [        SU[%        U5      U4-  5      e   U R'                  Xb5        OX`l        U R*                  U l        g)an  
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
r:  z
dir-key-certificate-versionrw   r[   Nr   r   zDAuthority entries are expected to start with a 'dir-source' line:
%sFrN  r"   z/Authority votes must have a key certificate:
%srZ  z@Authority consensus entries shouldn't have a key certificate:
%srX  zAuthority entries must have a 'rV  voteszconsensus entriesz
Authority z shouldn't have a ')r   r"   rX  rZ  z>Authority entries can only have a single '%s' line, got %i:
%s)rH  r  rI  r   r  r  _to_unicoder  r   key_certificater
   rX  rY  r   r  r   r  r  r   r   rP  rT  r!   )r   rQ  r   r{  r   key_divr   rV  dir_source_entryr\  excluded_fieldsr   
type_labelr%  rS  s                 r   rI  DirectoryAuthority.__init___  s/    

d,[l,Sii!!--k:G ll:;G"}+GaKL,A8Ld1%g!d$W7GLD$8$;;^bijkk $)7;;|+D!	$Q'*00215>>yI	*6I;&	##MPWWX
XM?*^ahhi
i
m_
,/,--$'!WV]^_
_ % '%")w/B*ZY`bijk
k  "'--/2/'v;?w*dd\`gilmsitv}_~~
 3 kk'$m ||Dr   )rP  r!   rd  )Nr   FF)Nr   TFF)FF)r   r   r   r   r   rW  re  _parse_vote_digest_line_parse_legacy_dir_key_line#_parse_shared_rand_participate_liner  r  r  rl  rm  rn  r   r  rI  r   ro  rp  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                    [        SU5      nSU;  a  [        SU-  5      eUR                  SS5      u  p4[        R                  R
                  R                  U5      (       d  [        SU-  5      e[        R                  R
                  R                  U5      (       d  [        SU-  5      eX0l        [        U5      U l
        g )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_linerq    s     
(%
qtyy
zz\\#q)'				3	3G	<	<
[^cc
dd99--g66
KeS
TTG*r   rk   rn   ro   expiresrm   identity_keyrp   	crosscertzID SIGNATURErq   certificationc                      ^  \ rS rSrSrSrS\4S\4S\4S\4S\	4S\
4S\4S\4S\4S\4S.
r\\\\
\\	\\\S.	r\S
S j5       rSU 4S jjrS	rU =r$ )r   i  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!   rs  r'   rr  r  rt  ru  )	rk   rl   r!   rn   ro   rm   r$   rp   rq   c                     U(       a  [        SU R                  -  5      e[        XSS[        5       4S[	        5       4S[	        5       4S[        S5      4S[        S5      44S	[        S
5      445      $ )Nr0  )rk   r  r!   rn   ro   rm   r  r$   rq   r  )r   r   r	   r   r   r   r3  s       r   r   KeyCertificate.content  s     ?#,, NOOt*)+,LN+,.)./?@A-.>?@/  3K @A	 	r   c                   > [         [        U ]  X(       + S9  [        X5      nU(       a  S[	        UR                  5       5      S   :w  a  [        SU-  5      eS[	        UR                  5       5      S   :w  a  [        SU-  5      e[         HU  u  pEU(       a  XC;  a  [        SU< S	U< 35      e[        UR                  U/ 5      5      nUS
:  d  MG  [        SXFU4-  5      e   U R                  X25        g X0l        g )Nr:  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 'rV  r[   z=Key certificates can only have a single '%s' line, got %i:
%s)rH  r   rI  r
   rX  rY  r   KEY_CERTIFICATE_PARAMSr   r  r   rP  )r   rQ  r   r   r   r[  entry_countrS  s          r   rI  KeyCertificate.__init__
  s    	.$(,(O$[;G	&$w||~*>q*A	Aeituvv"d7<<>&:2&>>]almnn
 $:
'G2GU`ab
b'++gr23?[_f  vA  _B  B  C  C $: kk'$mr   rP  r`  ra  )r   r   r   r   r   rb  '_parse_dir_key_certificate_version_linerq  rd  _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_linerl  rm  rn  r   rI  r   ro  rp  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                   F    \ rS rSrSrSS jrS rS rS rS r	S	 r
S
 rSrg)r  i$  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                 >   U(       ax  [         R                  R                  R                  U5      (       d  [	        SU-  5      e[         R                  R                  R                  U5      (       d  [	        SU-  5      eXl        X l        X0l        X@l        XPl	        g )Nz4Malformed fingerprint (%s) in the document signaturez3Malformed key digest (%s) in the document signature)
r   r  rO  rR  r   r  r   r  r*  r   )r   r  r   r  r*  r   r   s          r   rI  DocumentSignature.__init__3  sz     YY  55h??ORZZ[[YY  55jAANQ[[\\KM ONKr   c                     [        U[        5      (       d  gS H8  n[        X5      [        X5      :w  d  M  U" [        X5      [        X5      5      s  $    U" SS5      $ )NF)r  r   r  r*  r   T)r  r  getattr)r   otherr  r5  s       r   _compareDocumentSignature._compareD  sV    e.//K		 4	4gd)75+?@@ L $r   c                 F    [        [        U 5      R                  5       5      $ r)  )hashrO  r  r  s    r   __hash__DocumentSignature.__hash__N  s    D	!""r   c                 (    U R                  US 5      $ )Nc                 
    X:H  $ r)  r   sos     r   r"  *DocumentSignature.__eq__.<locals>.<lambda>R      QVr   r  r   r  s     r   __eq__DocumentSignature.__eq__Q      == 344r   c                     X:X  + $ r)  r   r  s     r   __ne__DocumentSignature.__ne__T  s    r   c                 (    U R                  US 5      $ )Nc                 
    X:  $ r)  r   r  s     r   r"  *DocumentSignature.__lt__.<locals>.<lambda>X  s    QUr   r  r  s     r   __lt__DocumentSignature.__lt__W  s    == 233r   c                 (    U R                  US 5      $ )Nc                 
    X:*  $ r)  r   r  s     r   r"  *DocumentSignature.__le__.<locals>.<lambda>[  r  r   r  r  s     r   __le__DocumentSignature.__le__Z  r  r   )r   r   r  r  r*  )NF)r   r   r   r   r   rI  r  r  r  r  r  r  r   r   r   r   r  r  $  s*    "#545r   r  c                      ^  \ rS rSrSrSrS\4S\4S\4S\	4/ \
4/ \4/ \4S.r\\\\	\
\\S.r\S
S j5       rSU 4S jjrS	rU =r$ )r   i^  a  
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           
          U(       a  [        SU R                  -  5      e[        XSS[        5       4S[        5       4S[        5       445      $ )Nr0  )rr   (6D3CC0EFA408F228410A4A8145E1B0BB0670E442r-   r.   r/   )r   r   r	   r   r3  s       r   r   DetachedSignature.content  sO     ?#,, NOOtFln%ln%ln%	/  r   c                   > [         [        U ]  X(       + S9  [        X5      nU(       a  S[	        UR                  5       5      S   :w  a  [        SU-  5      e[         H_  u  pEnU(       a  XC;  a  [        SU< SU< 35      e[        UR                  U/ 5      5      nU(       a  MI  US:  d  MQ  [        SXGU4-  5      e   U R                  X25        g X0l        g )	Nr:  rr   r   zADetached signatures must start with a 'consensus-digest' line:
%sz!Detached signatures must have a 'rV  r[   z@Detached signatures can only have a single '%s' line, got %i:
%s)rH  r   rI  r
   rX  rY  r   DETACHED_SIGNATURE_PARAMSr   r  r   rP  )	r   rQ  r   r   r   r[  is_multipler{  rS  s	           r   rI  DetachedSignature.__init__  s    	
T+K\+R$[;G	tGLLN3A6	6]almnn 1J
,'G2wXcde
e'++gr23{{Q^bi  yD  bE  E  F  F 1J kk'$mr   r}  r`  ra  )r   r   r   r   r   rb  _parse_consensus_digest_liner3  r4  r5  r  r  r  rl  rm  rn  r   rI  r   ro  rp  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                   4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )r   i  a0  
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                   > [         [        U ]  U5        S U l        [        R
                  " U5      n[        R                  R                  R                  UR                  5       5      nUR                  S5      (       aS  UR                  SS5      S   R                  5       n [        R                  R                  R                  U5      U l        O<U(       a5  [        S[        R                  R                  R                  U5      -  5      e[        R                   R"                  R%                  UU[&        U 4S9n[)        S U 5       5      U l        g ! [         a    U(       a  [        SU-  5      e Nhf = f)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   <   #    U  H  oR                   U4v   M     g 7fr)  r?  r@  s     r   rB  7BridgeNetworkStatusDocument.__init__.<locals>.<genexpr>  rD  rE  )rH  r   rI  r'   rJ  rK  r   r  r  rc  readliner   r   r  _parse_timestampr   r   r   r   r   rL  rM  )r   rQ  r   r   published_linerR  rS  s         r   rI  $BridgeNetworkStatusDocument.__init__  sU   	
%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 E76E7)r'   rM  ra  )	r   r   r   r   r   rb  rI  r   ro  rp  s   @r   r   r     s     1J Jr   r   ra  ){r   collectionsr  r   rJ  #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   rW  r!  r)  r  r   r   r   r  rz  r  r.  r/  r-  
namedtupler   r   r   r   r   r   r   r   r   r
  r  r  rc  rd  re  rf  rg  rh  ri  rj  rk  r  r   ru  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r3  r4  r5  r6  r7  r8  r=  rl  r9  r:  r;  r<  r   r"  r  rW  rk  rj  r  rq  r~  r  r  r  r  r  r  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!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   