
    <i>                        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	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  / SQrSrSrSr\R0                  " S\< S	\< S
35      rS\-  r\R0                  " S\< \< S35      rSr/ 0 \" 5       4rSrSr Sr!Sr"\RF                  RH                  RK                  SS5      r&\RF                  RH                  RK                  SSS5      r'\RF                  RH                  RK                  SSS5      r( " S S\)5      r*S r+\RF                  RH                  RY                  S\*" SSS S!S" 5      4S#\*" S$S%S$S&S' 5      4S(\*" S)S*S)S+S, 5      4S-\*" S.S.S/S0S1 5      4S2\*" S3S3S4S5\+5      45      r- " S6 S7\R\                  " S7/ S8Q5      5      r/ " S9 S:\R\                  " S:/ S;Q5      5      r0SS<\(Rb                  S4S= jr2S> r3S? r4S@ r5SA r6S_SB jr7SC r8SD r9S`SE jr:SF r;SG r<SaSH jr=SI r>SJ r?SK r@S`SL jrASbSM jrBSN rCSO rD " SP SQ\)5      rE " SR SS\)5      rFScST jrGSU rHSV rIS`SW jrJSX rKSY rLSZ rMS[ rNS\ rOS`S] jrPSdS^ jrQSSKRrSSKSrSSKTrSSKUrSSKVrSSKWrSSKXrg! \ a
    SSKJr   GN=f = f)ea  
Package for parsing and processing descriptor data.

**Module Overview:**

::

  parse_file - Parses the descriptors in a file.
  create_signing_key - Cretes a signing key that can be used for creating descriptors.

  Compression - method of descriptor decompression

  Descriptor - Common parent for all descriptor file types.
    | |- content - creates the text of a new descriptor
    | |- create - creates a new descriptor
    | +- from_str - provides a parsed descriptor for the given string
    |
    |- type_annotation - provides our @type annotation
    |- get_path - location of the descriptor on disk if it came from a file
    |- get_archive_path - location of the descriptor within the archive it came from
    |- get_bytes - similar to str(), but provides our original bytes content
    |- get_unrecognized_lines - unparsed descriptor content
    +- __str__ - string that the descriptor was made from

.. data:: DigestHash (enum)

  .. versionadded:: 1.8.0

  Hash function used by tor for descriptor digests.

  =========== ===========
  DigestHash  Description
  =========== ===========
  SHA1        SHA1 hash
  SHA256      SHA256 hash
  =========== ===========

.. data:: DigestEncoding (enum)

  .. versionadded:: 1.8.0

  Encoding of descriptor digests.

  ================= ===========
  DigestEncoding    Description
  ================= ===========
  RAW               hash object
  HEX               uppercase hexidecimal encoding
  BASE64            base64 encoding `without trailing '=' padding <https://en.wikipedia.org/wiki/Base64#Decoding_Base64_without_padding>`_
  ================= ===========

.. data:: DocumentHandler (enum)

  Ways in which we can parse a
  :class:`~stem.descriptor.networkstatus.NetworkStatusDocument`.

  Both **ENTRIES** and **BARE_DOCUMENT** have a 'thin' document, which doesn't
  have a populated **routers** attribute. This allows for lower memory usage
  and upfront runtime. However, if read time and memory aren't a concern then
  **DOCUMENT** can provide you with a fully populated document.

  Handlers don't change the fact that most methods that provide
  descriptors return an iterator. In the case of **DOCUMENT** and
  **BARE_DOCUMENT** that iterator would have just a single item -
  the document itself.

  Simple way to handle this is to call **next()** to get the iterator's one and
  only value...

  ::

    import stem.descriptor.remote
    from stem.descriptor import DocumentHandler

    consensus = next(stem.descriptor.remote.get_consensus(
      document_handler = DocumentHandler.BARE_DOCUMENT,
    )


  =================== ===========
  DocumentHandler     Description
  =================== ===========
  **ENTRIES**         Iterates over the contained :class:`~stem.descriptor.router_status_entry.RouterStatusEntry`. Each has a reference to the bare document it came from (through its **document** attribute).
  **DOCUMENT**        :class:`~stem.descriptor.networkstatus.NetworkStatusDocument` with the :class:`~stem.descriptor.router_status_entry.RouterStatusEntry` it contains (through its **routers** attribute).
  **BARE_DOCUMENT**   :class:`~stem.descriptor.networkstatus.NetworkStatusDocument` **without** a reference to its contents (the :class:`~stem.descriptor.router_status_entry.RouterStatusEntry` are unread).
  =================== ===========
    N)OrderedDict)bandwidth_filecertificate	collectorexportextrainfo_descriptorhidden_servicemicrodescriptornetworkstatusreaderremoterouter_status_entryserver_descriptortordnsel
Descriptor
parse_filezFile object isn't seekable. Try using Descriptor.from_str() instead:

  content = my_file.read()
  parsed_descriptors = stem.descriptor.Descriptor.from_str(content)
z
a-zA-Z0-9-z 	z^([z]+)(?:[	]+(.*))?$z^(%%s)(?:[%s]+(.*))?$z^-----BEGIN ([z	]+)-----$z-----END %s-----s           z
MIGJAoGBAJv5IIWQ+WDWYUdyA/0L8qbIkEVH/cwryZWoIaPAzINfrw1WfNZGtBmg
skFtXhOHHqTRN4GPPrZsAIUOQGzQtGb66IQgT4tO/pj+P6QmSCCdTfhvGfgTCsC+
WPi4Fl2qryzTb3QO5r5x7T8OsG2IBUET1bLQzmtbC560SYR49IvVAgMBAAE=
SHA1SHA256RAWHEXBASE64ENTRIESDOCUMENTBARE_DOCUMENTc                   *    \ rS rSrSrS rS rS rSrg)_Compression   a\  
Compression method supported by CollecTor.

:var bool available: **True** if this method of decryption is available,
  **False** otherwise
:var str encoding: `http 'Accept-Encoding' parameter <https://en.wikipedia.org/wiki/HTTP_compression#Content-Encoding_tokens>`_
:var str extension: file extension of this compression

.. versionadded:: 1.8.0
c                     Uc  S U l         SU l        O [        U5      U l         SU l        X@l        X0l        Xl        X l        XPl        g ! [         a    S U l         SU l         N9f = fNTF)	_module	available
__import__ImportError	extensionencoding_name_module_name_decompression_func)selfnamemoduler(   r'   decompression_funcs         R/home/james-whalen/.local/lib/python3.13/site-packages/stem/descriptor/__init__.py__init___Compression.__init__   si    ~dldn!&)
 NMJ1  s   A
 
A%$A%c                 D   U R                   (       dN  U R                  S:X  a  [        S5      eU R                  S:X  a  [        S5      e[        SU R                  -  5      e U R	                  U R
                  U5      $ ! [         a  n[        SU < SU< 35      eSnAff = f)	aC  
Decompresses the given content via this method.

:param bytes content: content to be decompressed

:returns: **bytes** with the decompressed content

:raises:
  If unable to decompress this provide...

  * **IOError** if content isn't compressed with this
  * **ImportError** if this method if decompression is unavalable
zstdzDDecompressing zstd data requires https://pypi.org/project/zstandard/lzmazLDecompressing lzma data requires https://docs.python.org/3/library/lzma.htmlz('%s' decompression module is unavailablezFailed to decompress as z: N)r$   r)   r&   r*   r+   r#   	ExceptionIOError)r,   contentexcs      r0   
decompress_Compression.decompress   s     >>	v	`aa::hiiDtGXGXXYYD%%dllG<< DcBCCDs   !A= =
BBBc                     U R                   $ N)r)   r,   s    r0   __str___Compression.__str__   s    ::    )r+   r#   r*   r)   r$   r(   r'   N)	__name__
__module____qualname____firstlineno____doc__r1   r:   r?   __static_attributes__ rA   r0   r   r      s    	2.D8rA   r   c                     [         R                  " 5       nU R                  5       R                  U5       nUR	                  U5        S S S 5        UR                  5       $ ! , (       d  f       UR                  5       $ = fr=   )ioBytesIOZstdDecompressorwrite_towritegetvalue)r.   r8   output_bufferdecompressors       r0   _zstd_decompressrR      sd    **,- ))-8Lw 9 
			!! 98 
			!!s   A
A<	PLAINTEXT	plaintextidentityz.txtc                     U$ r=   rH   r.   r8   s     r0   <lambda>rX      s    \crA   GZIPgzipzlibz.gzc                 >    U R                  XR                  S-  5      $ )N    )r:   	MAX_WBITSrW   s     r0   rX   rX      s     vO`O`ahjzjz}j  PArA   BZ2bzip2bz2z.bz2c                 $    U R                  U5      $ r=   r:   rW   s     r0   rX   rX      s    PVPaPabiPjrA   LZMAr5   z
x-tor-lzmaz.xzc                 $    U R                  U5      $ r=   rc   rW   s     r0   rX   rX     s    U[UfUfgnUorA   ZSTDr4   zx-zstdz.zstc                       \ rS rSrSrS rSrg)TypeAnnotationi  aa  
`Tor metrics type annotation
<https://metrics.torproject.org/collector.html#relay-descriptors>`_. The
string representation is the header annotation, for example "@type
server-descriptor 1.0".

.. versionadded:: 1.8.0

:var str name: name of the descriptor type
:var int major_version: major version number
:var int minor_version: minor version number
c                 Z    SU R                   < SU R                  < SU R                  < 3$ )Nz@type  .r-   major_versionminor_versionr>   s    r0   r?   TypeAnnotation.__str__  s    #yy$*<*<d>P>PQQrA   rH   N)rB   rC   rD   rE   rF   r?   rG   rH   rA   r0   rh   rh     s    RrA   rh   rl   c                       \ rS rSrSrSrg)
SigningKeyi  aa  
Key used by relays to sign their server and extrainfo descriptors.

.. versionadded:: 1.6.0

:var cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey private: private key
:var cryptography.hazmat.backends.openssl.rsa._RSAPublicKey public: public key
:var bytes public_digest: block that can be used for the a server descrptor's 'signing-key' field
rH   N)rB   rC   rD   rE   rF   rG   rH   rA   r0   rq   rq     s    rA   rq   )privatepublicpublic_digestFc              +     ^^^^^^^^#    Sn[         R                  R                  U 5      (       a<  [         R                  R                  R	                  U 5      (       a  [
        nO,[        nO%[        U [        R                  5      (       a  [        nU(       a  U" U TTT40 TD6 H  nUv   M	     g U R                  5         U R                  5       n[         R                  R                  R                  U R!                  5       R#                  5       5      m[$        R&                  " ST5      mT(       d  U R)                  U5        [+        U SS5      n	U	c  SO([,        R.                  R1                  U R2                  5      mUUUUUUUU4S jn
U
" U 5       H8  nU	b.  UR5                  [,        R.                  R7                  U	5      5        Uv   M:     g! [         a    [        [        5      ef = f7f)a:  
Simple function to read the descriptor contents from a file, providing an
iterator for its :class:`~stem.descriptor.__init__.Descriptor` contents.

If you don't provide a **descriptor_type** argument then this automatically
tries to determine the descriptor type based on the following...

* The @type annotation on the first line. These are generally only found in
  the `CollecTor archives <https://metrics.torproject.org/collector.html#relay-descriptors>`_.

* The filename if it matches something from tor's data directory. For
  instance, tor's 'cached-descriptors' contains server descriptors.

This is a handy function for simple usage, but if you're reading multiple
descriptor files you might want to consider the
:class:`~stem.descriptor.reader.DescriptorReader`.

Descriptor types include the following, including further minor versions (ie.
if we support 1.1 then we also support everything from 1.0 and most things
from 1.2, but not 2.0)...

========================================= =====
Descriptor Type                           Class
========================================= =====
server-descriptor 1.0                     :class:`~stem.descriptor.server_descriptor.RelayDescriptor`
extra-info 1.0                            :class:`~stem.descriptor.extrainfo_descriptor.RelayExtraInfoDescriptor`
microdescriptor 1.0                       :class:`~stem.descriptor.microdescriptor.Microdescriptor`
directory 1.0                             **unsupported**
network-status-2 1.0                      :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV2` (with a :class:`~stem.descriptor.networkstatus.NetworkStatusDocumentV2`)
dir-key-certificate-3 1.0                 :class:`~stem.descriptor.networkstatus.KeyCertificate`
network-status-consensus-3 1.0            :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` (with a :class:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3`)
network-status-vote-3 1.0                 :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` (with a :class:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3`)
network-status-microdesc-consensus-3 1.0  :class:`~stem.descriptor.router_status_entry.RouterStatusEntryMicroV3` (with a :class:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3`)
bridge-network-status 1.0                 :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` (with a :class:`~stem.descriptor.networkstatus.BridgeNetworkStatusDocument`)
bridge-server-descriptor 1.0              :class:`~stem.descriptor.server_descriptor.BridgeDescriptor`
bridge-extra-info 1.1 or 1.2              :class:`~stem.descriptor.extrainfo_descriptor.BridgeExtraInfoDescriptor`
torperf 1.0                               **unsupported**
bridge-pool-assignment 1.0                **unsupported**
tordnsel 1.0                              :class:`~stem.descriptor.tordnsel.TorDNSEL`
hidden-service-descriptor 1.0             :class:`~stem.descriptor.hidden_service.HiddenServiceDescriptorV2`
========================================= =====

If you're using **python 3** then beware that the open() function defaults to
using text mode. **Binary mode** is strongly suggested because it's both
faster (by my testing by about 33x) and doesn't do universal newline
translation which can make us misparse the document.

::

  my_descriptor_file = open(descriptor_path, 'rb')

:param str,file,tarfile descriptor_file: path or opened file with the descriptor contents
:param str descriptor_type: `descriptor type <https://metrics.torproject.org/collector.html#data-formats>`_, this is guessed if not provided
:param bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:param stem.descriptor.__init__.DocumentHandler document_handler: method in
  which to parse the :class:`~stem.descriptor.networkstatus.NetworkStatusDocument`
:param bool normalize_newlines: converts windows newlines (CRLF), this is the
  default when reading data directories on windows
:param dict kwargs: additional arguments for the descriptor constructor

:returns: iterator for :class:`~stem.descriptor.__init__.Descriptor` instances in the file

:raises:
  * **ValueError** if the contents is malformed and validate is True
  * **TypeError** if we can't match the contents of the file to a descriptor type
  * **IOError** if unable to read from the descriptor_file
Nz^@type (\S+) (\d+).(\d+)$r-   z<undefined>c                 ,  > T(       a  [        U 5      n Tb_  [        R                  " ST5      nU(       a6  UR                  5       u  p#n[	        U[        U5      [        U5      U TT40 T	D6$ [        S5      eT
(       a6  T
R                  5       u  p#n[	        U[        U5      [        U5      U TT40 T	D6$ Tc8  [        R                  R                  R                  5       (       a  [        U 5      n TS:X  d  TS:X  a-  [        R                  R                  R                  " U 4ST0T	D6$ TS:X  d  TS:X  a-  [        R                  R                  R                  " U 4ST0T	D6$ TS:X  d  TS	:X  a-  [        R                  R                  R                  " U 4ST0T	D6$ TS
:X  a.  [        R                  R                   R                  " U 4TTS.T	D6$ TS:X  a/  [        R                  R                   R                  " U 4STTS.T	D6$ [#        ST< ST< S35      e)Nz^(\S+) (\d+).(\d+)$zPThe descriptor_type must be of the form '<type> <major_version>.<minor_version>'zcached-descriptorszcached-descriptors.newvalidatezcached-extrainfozcached-extrainfo.newzcached-microdescszcached-microdescs.newzcached-consensusrw   document_handlerzcached-microdesc-consensusTis_microdescriptorrw   ry   z6Unable to determine the descriptor's type. filename: 'z', first line: '')NewlineNormalizerrematchgroups_parse_metrics_fileint
ValueErrorstemutilsystem
is_windows
descriptorr   _parse_filer   r
   r   	TypeError)descriptor_filedescriptor_type_match	desc_typerm   rn   descriptor_typery   filename
first_linekwargsmetrics_header_matchnormalize_newlinesrw   s        r0   parseparse_file.<locals>.parse  sF   )/:o" hh'?Q	2G2N2N2P/	-"9c-.@#mBTVego  rB  M  FL  M  	Mkll	 1E0K0K0M-i C,>M@RTcemo  K  DJ  K  K 
	#		(8(8(C(C(E(E+O<	)	)X9Q-Q00<<_lYalekll))X9O-O33??o\dohnoo**h:Q.Q..::?jW_jcijj)),,88  NU]  sC  N  GM  N  	N33,,88  i_cpx  N^  i  bh  i  	iiqs}~rA   )r   r   _is_strr   
is_tarfile_parse_file_for_tar_path_parse_file_for_path
isinstancetarfileTarFile_parse_file_for_tarfiletellr7   UNSEEKABLE_MSG	str_tools_to_unicodereadlinestripr~   r   seekgetattrospathbasenamer-   	_set_pathabspath)r   r   rw   ry   r   r   handlerdescinitial_positiondescriptor_pathr   r   r   r   s    `````     @@@r0   r   r   $  s    P '	YY''yy""?33(g$g/7??33%G(DT_X^_j ` " %))+yy""../G/G/I/O/O/QR*"@*M	)*OVT:/-5]277;K;KOL`L`;a("@ "@H O$d"
nnRWW___56
J	 %o 
 "
.
!!"s   B'G02G DG0G--G0c              /      #    [        U S5       n[        U/UQ70 UD6 H  nUv   M	     S S S 5        g ! , (       d  f       g = f7f)Nrb)openr   )r   argsr   	desc_filer   s        r0   r   r     s:     OT"i96t6v6j 7 #""s   A3	A
AAc              /   4  #    [         R                  " U 5      n [        U/UQ70 UD6 H5  nUR                  [        R
                  R                  U 5      5        Uv   M7     U(       a  UR                  5         g g ! U(       a  UR                  5         f f = f7fr=   )r   r   r   r   r   r   r   close)r   r   r   tar_filer   s        r0   r   r     su     \\/*(85d5f5
nnRWW___56j 6 nn xnn s   BAA; "B;BBc              /   H  #    U  H  nUR                  5       (       d  M  U R                  U5      nUR                  S:X  a  M=   [        U/UQ70 UD6 H"  nUR	                  UR
                  5        Uv   M$     UR                  5         M     g ! UR                  5         f = f7fNr   )isfileextractfilesizer   _set_archive_pathr-   r   )r   r   r   	tar_entryentryr   s         r0   r   r     s     "i)))4e	1	u6t6v6D

 
 
,* 7 	 # 	s"   B"#B"5B8B"BB"c              +     #    U [         R                  R                  R                  R                  :X  a@  US:X  a:  [         R                  R                  R
                  " U4SUS.UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  a@  US:X  a:  [         R                  R                  R
                  " U4SUS.UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  a@  US:X  a:  [         R                  R                  R
                  " U4SUS.UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  a?  US:X  a9  [         R                  R                  R
                  " U4SU0UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  a@  US:X  a:  [         R                  R                  R
                  " U4SUS.UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  ac  US:X  a]  [         R                  R                  R                  n[         R                  R                  R
                  " X84XES.UD6 H  nUv   M	     g U [         R                  R                  R                  R                  :X  a?  US:X  a9  [         R                  R                  R                  " U4SU0UD6 H  nUv   M	     g U S;   ac  US:X  a]  [         R                  R                  R                   n[         R                  R                  R
                  " X84XES.UD6 H  nUv   M	     g U S:X  ad  US:X  a^  [         R                  R                  R                   n[         R                  R                  R
                  " X84SXES	.UD6 H  nUv   M	     g U [         R                  R                  R"                  R                  :X  ac  US:X  a]  [         R                  R                  R"                  n[         R                  R                  R
                  " X84XES.UD6 H  nUv   M	     g U [         R                  R                  R$                  R                  :X  ac  US:X  a]  [         R                  R                  R$                  n[         R                  R                  R
                  " X84XES.UD6 H  nUv   M	     g U [         R                  R&                  R(                  R                  :X  a?  US:X  a9  [         R                  R&                  R
                  " U4SU0UD6 H  nUv   M	     g U [         R                  R*                  R,                  R                  :X  ac  US:X  a]  [         R                  R*                  R,                  n	[         R                  R*                  R
                  " X94SU0UD6 H  nUv   M	     g U [         R                  R*                  R.                  R                  :X  ac  US:X  a]  [         R                  R*                  R.                  n	[         R                  R*                  R
                  " X94SU0UD6 H  nUv   M	     g U [         R                  R0                  R2                  R                  :X  a?  US:X  a9  [         R                  R0                  R
                  " U4SU0UD6 H  nUv   M	     g [5        S
XU4-  5      e7f)N   F)	is_bridgerw   Trw   rx   )znetwork-status-consensus-3znetwork-status-vote-3z$network-status-microdesc-consensus-3rz   zDUnrecognized metrics descriptor format. type: '%s', version: '%i.%i')r   r   r   RelayDescriptorTYPE_ANNOTATION_NAMEr   BridgeDescriptorr   RelayExtraInfoDescriptorr
   MicrodescriptorBridgeExtraInfoDescriptorr   NetworkStatusDocumentV2KeyCertificate_parse_file_key_certsNetworkStatusDocumentV3BridgeNetworkStatusDocumentDetachedSignaturer   TorDNSELr	   HiddenServiceDescriptorV2HiddenServiceDescriptorV3r   BandwidthFiler   )
r   rm   rn   r   rw   ry   r   r   document_typer   s
             r0   r   r     sK     99II^^^cptucu11==o  A[`mu  Ay  Aj A$//;;LLaaafswxfx11==o[_ltx~j @$//>>WWlllq~  CD  rD44@@  D^cpx  D  }C  Dj D$//99II^^^cptucu//;;OkX`kdjkj l$//>>XXmmmr  DE  sE 44@@  C^bow  C  |B  Cj C$//77OOdddivz{i{OO11IIM--99/  ^em  ^  W]  ^j ^$//77FF[[[`mqr`r--CCOs`hslrsj tQQVcghVhOO11IIM--99/  ^em  ^  W]  ^j ^@@]VWEWOO11IIM--99/  yos  AI  y  rx  yj y$//77SShhhmz~mOO11MMM--99/  ^em  ^  W]  ^j ^$//77II^^^cptucuOO11CCM--99/  ^em  ^  W]  ^j ^$//22;;PPPUbfgUg((44_dQYd]cdj e$//88RRgggly}~l~..HHI..::?ubjuntuj v$//88RRgggly}~l~..HHI..::?ubjuntuj v$//88FF[[[`mqr`r..::?jW_jcijj k Z^m  L  ^M  M  N  Ns   ]]c                 z   / / pTU c  0 O
[        U 5      n XB4XS44 H  u  pgU H  u  pX;   a  M  [        R                  R                  R	                  U R                  X5      5      n	U	c  MI  [        U	[        [        45      (       a#  U	 H  n
UR                  U< SU
< 35        M     M  U	S:X  a  UR                  U5        M  U	R                  S5      (       a  UR                  U< U	< 35        M  UR                  U< SU	< 35        M     M     / nU R                  5        HU  u  p[        U
[        [        45      (       a  X Vs/ s H  o< SU< 3PM     sn-  nM=  UR                  U< SU
< 35        MW     [        R                  R                  R                  SR                  XK-   U-   5      5      $ s  snf )a  
Constructs a minimal descriptor with the given attributes. The content we
provide back is of the form...

* header_template (with matching attr filled in)
* unused attr entries
* footer_template (with matching attr filled in)

So for instance...

::

  _descriptor_content(
    attr = {'nickname': 'caerSidi', 'contact': 'atagar'},
    header_template = (
      ('nickname', 'foobar'),
      ('fingerprint', '12345'),
    ),
  )

... would result in...

::

  nickname caerSidi
  fingerprint 12345
  contact atagar

:param dict attr: keyword/value mappings to be included in the descriptor
:param list exclude: mandatory keywords to exclude from the descriptor
:param tuple header_template: key/value pairs for mandatory fields before unrecognized content
:param tuple footer_template: key/value pairs for mandatory fields after unrecognized content

:returns: bytes with the requested descriptor content
rj    
)r   r   r   r   r   popr   tuplelistappend
startswithitems	_to_bytesjoin)attrexcludeheader_templatefooter_templateheader_contentfooter_contentr8   templatekeywordvaluev	remainderkr   s                 r0   _descriptor_contentr   *  sw   J $&r.|T!2$+=+=?g"		ii!!--dhhw.FGe	eeT]++A
..GQ/
0 B;wD!!%01'512# #?* )jjlda!eT]##a8aUq%(a88i!Q'(	  
			&	&tyy1Kn1\']	^^	 9s   F8c                     X   S   S   $ r   rH   )lineentriess     r0   _valuer   r  s    	q	!	rA   c                 :    X    Vs/ s H  o"S   PM	     sn$ s  snf r   rH   )r   r   r   s      r0   _valuesr   v  s     '	.u(	..	.s   c                    ^ ^^ UUU 4S jnU$ )Nc                 `   > [        TU5      n[        U TT(       a  T" U5      5        g U5        g r=   )r   setattr)r   r   r   	attributefuncr   s      r0   _parse"_parse_simple_line.<locals>._parse{  s&    7G$EJ	$4;BEBrA   rH   )r   r   r   r   s   ``` r0   _parse_simple_liner   z  s    C 
-rA   c                    ^ ^ UU 4S j$ )Nc                 $   > [        U TTU;   5      $ r=   )r   )r   r   r   r   s     r0   rX   #_parse_if_present.<locals>.<lambda>  s    WZGwDV%WrA   rH   )r   r   s   ``r0   _parse_if_presentr     s	    	WWrA   c                    ^ ^ UU 4S jnU$ )Nc           	      6  > [         R                  " [        R                  R                  R                  ST< S[        < S35      U R                  5       [         R                  5      nS nU(       a  UR                  5       S   nUc  SOUn[        U TU5        g )Nz^(opt )?z(?:[r   r   rA   )r~   searchr   r   r   r   
WHITESPACE	get_bytes	MULTILINEr   r   )r   r   
line_matchresultr   r   r   s        r0   r   !_parse_bytes_line.<locals>._parse  s    499..88X_ak9lmoy  pD  pD  pF  HJ  HT  HT  UJF!!$emsfJ	6*rA   rH   r   r   r   s   `` r0   _parse_bytes_liner    s    + 
-rA   c                    ^ ^^ UUU 4S jnU$ )Nc                    > [        TU5      n [        U5      nT(       d  US:  a  [        T< SU< 35      e[        U TU5        g ! [         a    [        T< SU< 35      ef = f)Nz must have a numeric value: r   z must have a positive value: )r   r   r   r   )r   r   r   int_valallow_negativer   r   s       r0   r   _parse_int_line.<locals>._parse  sh    7G$ENE
g gkguMNNJ	7+  NWeLMMNs   A A$rH   )r   r   r  r   s   ``` r0   _parse_int_liner    s    , 
-rA   c                    ^ ^ UU 4S jnU$ )Nc           	         > [        TU5      n [        U T[        R                  R                  R                  U5      5        g ! [         a    [        ST< ST< SU< 35      ef = f)NzTimestamp on z line wasn't parsable: rj   )r   r   r   r   r   _parse_timestampr   r   r   r   r   r   s      r0   r   %_parse_timestamp_line.<locals>._parse  s[    7G$Ebj)TYY%8%8%I%I%%PQ bQXZ_`aabs   4A "A&rH   r  s   `` r0   _parse_timestamp_liner    s    b 
-rA   c                    ^ ^ UU 4S jnU$ )Nc                    > [        TU5      n[        R                  R                  R	                  US5      (       d  [        T< ST< SU< 35      e[        U TU5        g )N(   z: line had an invalid value (should be 40 hex characters): rj   )r   r   r   	tor_toolsis_hex_digitsr   r   r  s      r0   r   *_parse_forty_character_hex.<locals>._parse  sM    7G$E99,,UB77^egnpuvwwJ	5)rA   rH   r  s   `` r0   _parse_forty_character_hexr    s    * 
-rA   c                    ^ ^ UU 4S jnU$ )Nc           	        > [        TU5      n[        5       n[        TU5       H  u  pE/ nU(       d  M  UR                  S5       H  nSU;   a  UR                  SS5      u  pOU=pUR	                  5       (       a  U	R	                  5       (       d  [        ST< SU< 35      eU[        [        U5      [        U	5      S-   5      -  nM     XcU'   M     [        U T
U5        g )N,-r   z=Protocol values should be a number or number range, but was: rj   )	r   r   _mappings_forsplitisdigitr   ranger   r   )r   r   r   	protocolsr   r   versionsr   	min_value	max_valuer   r   s             r0   r   $_parse_protocol_line.<locals>._parse  s     7G$EIgu-h773<%%<!&S!!4
)Y"'
')  "")*;*;*=*=cjlqrs
sE#i.#i.1*<==   l# .& J	9-rA   rH   r  s   `` r0   _parse_protocol_liner(    s    .6 
-rA   c                     ^ ^^^ UUU U4S jnU$ )Nc                    > UT   S   u  p#nU(       a  UT:w  a  [        ST< ST< SU< 35      e[        U TU5        T(       a  [        U TU5        g g )Nr   r|   z' should be followed by a z block, but was a )r   r   )	r   r   r   
block_typeblock_contentsr   expected_block_typer   value_attributes	        r0   r    _parse_key_block.<locals>._parse  sW    (/(8(;%E~Z+>>PWYlnxyzzJ	>2j/51 rA   rH   )r   r   r-  r.  r   s   ```` r0   _parse_key_blockr0    s    	2 	2 
-rA   c           	   #      #    Uc  gUS:X  a  gUR                  U5       HZ  nSU;  a  [        SU < SU< 35      eUR                  SS5      u  pVU(       a  U(       d  [        SU < SU< SU< 35      eXV4v   M\     g7f)	aE  
Parses an attribute as a series of 'key=value' mappings. Unlike _parse_*
functions this is a helper, returning the attribute value rather than setting
a descriptor field. This way parsers can perform additional validations.

:param str keyword: descriptor field being parsed
:param str value: 'attribute => values' mappings to parse
:param str divider: separator between the key/value mappings
:param bool require_value: validates that values are not empty

:returns: **generator** with the key/value of the map attribute

:raises: **ValueError** if descriptor content is invalid
Nr   =r|   z3' should be a series of 'key=value' pairs but was: r   z	' line's z mapping had a blank value: )r   r   )r   r   require_valuedividerr   r   r   s          r0   r  r    sx       ]
{
{{7#e
%U\^cdee;;sADAQRSUZ[\\
$J $s   A<A>c                     U b/  [        U [        [        R                  R                  45      (       a  U $ U [
        ;   a  [        U 5      " 5       $ [        R                  " U 5      $ r=   )r   boolr   exit_policy
ExitPolicyEMPTY_COLLECTIONtypecopy)defaults    r0   _copyr=    sM    _
7T43C3C3N3N,OPPN""=?99WrA   c                 8   U[         R                  :X  a  U $ U[         R                  :X  aE  [        R                  R
                  R                  U R                  5       R                  5       5      $ U[         R                  :X  aZ  [        R                  R
                  R                  [        R                  " U R                  5       5      R                  S5      5      $ U[         ;  a&  [        SSR                  [         5      < SU< 35      e[!        SU-  5      e)z3
Encodes a hash value with the given HashEncoding.
   =zADigest encodings should be among our DigestEncoding enumeration (z, z), not zRBUG: stem.descriptor._encode_digest should recognize all DigestEncoding, lacked %s)DigestEncodingr   r   r   r   r   r   	hexdigestupperr   base64	b64encodedigestrstripr   r   NotImplementedError)
hash_valuer(   s     r0   _encode_digestrI    s    
 ###>%%%99**:+?+?+A+G+G+IJJ>(((99**6+;+;J<M<M<O+P+W+WX\+]^^~%
gkgpgpq  hA  CK  L  M  M
ru}}
~~rA   c                      ^  \ rS rSrSr0 r0 rSrSS jr\	S 5       r
\	SS j5       r\	SS j5       rS rS	 rS
 rS rS rSS jrS rS rSS jrS rS S jrU 4S jrS rS rS rS rS rS rS rSr U =r!$ )!r   i*  z-
Common parent for all types of descriptors.
Nc                 b    S U l         S U l        Xl        X l        0 U l        S U l        / U l        g r=   )_path_archive_path_raw_contents_lazy_loading_entries_hash_unrecognized_lines)r,   contents	lazy_loads      r0   r1   Descriptor.__init__3  s3    DJD!"DMDJ!DrA   c           	         SU;  a3  U R                   b&  [        [        U R                   SS5      5      SS US'   UR                  SS5      n[	        [        [        R                  " [        R                  R                  R                  U5      5      40 UD65      nU(       a  U$ [        U5      S:X  a  US   $ [        S[        U5      -  5      e)	a  
Provides a :class:`~stem.descriptor.__init__.Descriptor` for the given content.

To parse a descriptor we must know its type. There are three ways to
convey this...

::

  # use a descriptor_type argument
  desc = Descriptor.from_str(content, descriptor_type = 'server-descriptor 1.0')

  # prefixing the content with a "@type" annotation
  desc = Descriptor.from_str('@type server-descriptor 1.0\n' + content)

  # use this method from a subclass
  desc = stem.descriptor.server_descriptor.RelayDescriptor.from_str(content)

.. versionadded:: 1.8.0

:param str,bytes content: string to construct the descriptor from
:param bool multiple: if provided with **True** this provides a list of
  descriptors rather than a single one
:param dict kwargs: additional arguments for :func:`~stem.descriptor.__init__.parse_file`

:returns: :class:`~stem.descriptor.__init__.Descriptor` subclass for the
  given content, or a **list** of descriptors if **multiple = True** is
  provided

:raises:
  * **ValueError** if the contents is malformed and validate is True
  * **TypeError** if we can't match the contents of the file to a descriptor type
  * **IOError** if unable to read from the descriptor_file
r   Nr   r      multipleFzDescriptor.from_str() expected a single descriptor, but had %i instead. Please include 'multiple = True' if you want a list of results instead.)r   strrh   r   r   r   rJ   rK   r   r   r   r   lenr   )clsr8   r   is_multipleresultss        r0   from_strDescriptor.from_str<  s    H &3+C+C+O"%nS5M5MqRS&T"UVWVX"Yf**Z/K:bjj)<)<)F)Fw)OP[TZ[\Gn	W	QZ  i  lo  pw  lx  x  y  yrA   c                 2    [        SU R                  -  5      e)a  
Creates descriptor content with the given attributes. Mandatory fields are
filled with dummy information unless data is supplied. This doesn't yet
create a valid signature.

.. versionadded:: 1.6.0

:param dict attr: keyword/value mappings to be included in the descriptor
:param list exclude: mandatory keywords to exclude from the descriptor, this
  results in an invalid descriptor
:param bool sign: includes cryptographic signatures and digests if True

:returns: **str** with the content of a descriptor

:raises:
  * **ImportError** if cryptography is unavailable and sign is True
  * **NotImplementedError** if not implemented for this descriptor type
z>The create and content methods haven't been implemented for %s)rG  rB   )r[  r   r   signs       r0   r8   Descriptor.contentm  s    . ^adamamm
nnrA   c                 0    U " U R                  XU5      US9$ )aJ  
Creates a descriptor with the given attributes. Mandatory fields are filled
with dummy information unless data is supplied. This doesn't yet create a
valid signature.

.. versionadded:: 1.6.0

:param dict attr: keyword/value mappings to be included in the descriptor
:param list exclude: mandatory keywords to exclude from the descriptor, this
  results in an invalid descriptor
:param bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:param bool sign: includes cryptographic signatures and digests if True

:returns: :class:`~stem.descriptor.Descriptor` subclass

:raises:
  * **ValueError** if the contents is malformed and validate is True
  * **ImportError** if cryptography is unavailable and sign is True
  * **NotImplementedError** if not implemented for this descriptor type
)rw   r8   )r[  r   r   rw   ra  s        r0   createDescriptor.create  s    0 s{{4$/HEErA   c                     U R                   b  [        U R                   SS5      $ [        S[        U 5      R                  -  5      e)a  
Provides the `Tor metrics annotation
<https://metrics.torproject.org/collector.html#relay-descriptors>`_ of this
descriptor type. For example, "@type server-descriptor 1.0" for server
descriptors.

Please note that the version number component is specific to CollecTor,
and for the moment hardcode as 1.0. This may change in the future.

.. versionadded:: 1.8.0

:returns: :class:`~stem.descriptor.TypeAnnotation` with our type information
r   r   z#%s does not have a @type annotation)r   rh   rG  r:  rB   r>   s    r0   type_annotationDescriptor.type_annotation  s@    "   ,D55q!<< ET
H[H[ [\\rA   c                     U R                   $ )z
Provides the absolute path that we loaded this descriptor from.

:returns: **str** with the absolute path of the descriptor source
rL  r>   s    r0   get_pathDescriptor.get_path  s     ::rA   c                     U R                   $ )a7  
If this descriptor came from an archive then provides its path within the
archive. This is only set if the descriptor came from a
:class:`~stem.descriptor.reader.DescriptorReader`, and is **None** if this
descriptor didn't come from an archive.

:returns: **str** with the descriptor's path within the archive
rM  r>   s    r0   get_archive_pathDescriptor.get_archive_path  s     rA   c                 h    [         R                  R                  R                  U R                  5      $ )z
Provides the ASCII **bytes** of the descriptor. This only differs from
**str()** if you're running python 3.x, in which case **str()** provides a
**unicode** string.

:returns: **bytes** for the descriptor's contents
)r   r   r   r   rN  r>   s    r0   r  Descriptor.get_bytes  s%     99((););<<rA   c                     U R                   (       a#  U R                  U R                  S5        SU l         [        U R                  5      $ )a  
Provides a list of lines that were either ignored or had data that we did
not know how to process. This is most common due to new descriptor fields
that this library does not yet know how to process. Patches welcome!

:returns: **list** of lines of unrecognized content
F)rO  r   rP  r   rR  r>   s    r0   get_unrecognized_lines!Descriptor.get_unrecognized_lines  s8     
kk$--' d(())rA   c                 :   Uc  U R                   n[        UR                  5       5       HV  u  pE XC;   a  X4   " X5        M  U H9  u  pgnU< SU< 3n	U(       a  U	SU-  -  n	U R                  R	                  U	5        M;     MX     g! [
         a    U(       a  e  Mp  f = f)a\  
Parses a series of 'keyword => (value, pgp block)' mappings and applies
them as attributes.

:param dict entries: descriptor contents to be applied
:param bool validate: checks the validity of descriptor content if True
:param dict parsers: mapping of lines to the function for parsing it

:raises: **ValueError** if an error occurs in validation
Nrj   z
%s)PARSER_FOR_LINEr   r   rR  r   r   )
r,   r   rw   parser_for_liner   valuesr   r+  r,  r   s
             r0   r   Descriptor._parse  s     ,,o0%

"4
139/e%u-Df~--d$$++D1 4: 1  
 s   B ?BBBc                     Xl         g r=   rk  r,   r   s     r0   r   Descriptor._set_path  s    JrA   c                     Xl         g r=   ro  r}  s     r0   r   Descriptor._set_archive_path  s    rA   c                 *    [        [        U 5      5      $ r=   )rY  r:  )r,   	is_plurals     r0   r)   Descriptor._name  s    tDz?rA   c                    [         R                  R                  5       (       d  [        S5      eSSKJn  SSKJn  SSKJ	n  U" [        U5      U" 5       5      nUR                  5       R                  nUR                  5       R                  n[        U5      n	[        R                  U	SS9n
[!        U	5      n[#        XU5      nU" X5      n UR%                  [&        5      S:w  a  [        S5      e  S
nUR%                  [(        U5      n[*        R,                  " XS-   S S5      n[         R.                  R0                  R3                  UR5                  5       5      $ ! [         a    [        S	5      ef = f! [         a    [        S5      ef = f)a@  
Provides the signed digest we should have given this key and signature.

:param str signing_key: key block used to make this signature
:param str signature: signed digest for this descriptor content

:returns: the digest string encoded in uppercase hex

:raises: ValueError if unable to provide a validly signed digest
z=Generating the signed digest requires the cryptography moduler   default_backend)load_der_public_key)int_to_bytesbig)	byteorderz'Verification failed, identifier missingz#Verification failed, malformed data   z(Verification failed, seperator not foundr   N	hex_codec)r   prereqis_crypto_availabler   cryptography.hazmat.backendsr  ,cryptography.hazmat.primitives.serializationr  cryptography.utilsr  _bytes_for_blockpublic_numbersner   
from_bytesrZ  powindexDIGEST_TYPE_INFODIGEST_SEPARATORcodecsencoder   r   r   rB  )r,   signing_key	signaturer  r  r  keymoduluspublic_exponentsig_as_bytessig_as_long	blocksizedecrypted_intdecrypted_bytesidentifier_offsetseperator_index
digest_hexs                    r0   _digest_for_signature Descriptor._digest_for_signature  sq    ;;**,,VWW<P/
.{;_=N
OC  "$$G((*,,O#I.L...?KL!I g>M #=<O>			/	0A	5BCC 
6
C (--.>@QRo /B/CDkRJ99**:+;+;+=>>  ><==>  CABBCs   $E 1E5 E25Fc                    U R                  5       nSu  pEUbL  UR                  [        R                  R                  R                  U5      5      nUS:X  a  [        SU-  5      eUb[  UR                  [        R                  R                  R                  U5      U5      nUS:X  a  [        SU-  5      eU[        U5      -  nX4U $ )a  
Provides the descriptor content inclusively between two substrings.

:param bytes start: start of the content range to get
:param bytes end: end of the content range to get

:raises: ValueError if either the start or end substring are not within our content
NNz1'%s' is not present within our descriptor content)r  findr   r   r   r   r   rZ  )r,   startendr8   start_index	end_indexs         r0   _content_rangeDescriptor._content_rangeL  s     nnG'KLL!4!4!>!>u!EFk		LuTUU
,,tyy22<<SA;Oi	bLsRSS3s8iy))rA   c           	        >^  UU 4S jnUT R                   ;   aZ  U" U5      (       dM  T R                   U   u  p4T R                  (       a   U" T T R                  5        O[        T U[        U5      5        [        [        T ]+  U5      $ ! [        [        4 aU    T R                   R                  5        H4  u  nu  pgXG:X  d  M  U" U5      (       a  M  [        T U[        U5      5        M6      Nwf = f)Nc                 <   >  [         [        T]  U 5        g!    g= fr"   )superr   __getattribute__)r   	__class__r,   s    r0   has_attr(Descriptor.__getattr__.<locals>.has_attrn  s$    j$06s    )
ATTRIBUTESrO  rP  r   KeyErrorr   r   r=  r  r   r  )	r,   r-   r  r<  parsing_function	attr_nameattr_defaultattr_parserr  s	   `       r0   __getattr__Descriptor.__getattr__i  s    
 tx~~"&//$"7g					<
4
/ 	dE'N+T3D99 H% 	<
 9=8M8M8O4i4,.x	7J7JdIu\':; 9P	<s   
B 5C, C,C,+C,c                     [         R                  R                  5       (       a3  [         R                  R                  R                  U R                  5      $ U R                  $ r=   )r   r  is_python_3r   r   r   rN  r>   s    r0   r?   Descriptor.__str__  sB    {{  YY  ,,T-?-?@@rA   c                     [        U 5      [        U5      :w  a  gU" [        U 5      R                  5       [        U5      R                  5       5      $ )NF)r:  rY  r   )r,   othermethods      r0   _compareDescriptor._compare  s:    DzT%[ #d)//#SZ%5%5%788rA   c                     U R                   c'  [        [        U 5      R                  5       5      U l         U R                   $ r=   )rQ  hashrY  r   r>   s    r0   __hash__Descriptor.__hash__  s-    zzD	)*dj::rA   c                 (    U R                  US 5      $ )Nc                 
    X:H  $ r=   rH   sos     r0   rX   #Descriptor.__eq__.<locals>.<lambda>      QVrA   r  r,   r  s     r0   __eq__Descriptor.__eq__      == 344rA   c                     X:X  + $ r=   rH   r  s     r0   __ne__Descriptor.__ne__  s    rA   c                 (    U R                  US 5      $ )Nc                 
    X:  $ r=   rH   r  s     r0   rX   #Descriptor.__lt__.<locals>.<lambda>  s    QUrA   r  r  s     r0   __lt__Descriptor.__lt__  s    == 233rA   c                 (    U R                  US 5      $ )Nc                 
    X:*  $ r=   rH   r  s     r0   rX   #Descriptor.__le__.<locals>.<lambda>  r  rA   r  r  s     r0   __le__Descriptor.__le__  r  rA   )rM  rP  rQ  rO  rL  rN  rR  )F)NrH   F)NrH   TFr=   r  )"rB   rC   rD   rE   rF   r  rx  r   r1   classmethodr^  r8   re  rh  rl  rp  r  ru  r   r   r   r)   r  r  r  r?   r  r  r  r  r  r  rG   __classcell__)r  s   @r0   r   r   *  s     */" .y .y` o o0 F F2],
	=* ><?|*:":H 9545 5rA   r   c                   <    \ rS rSrSrS rS rS rS rS r	S r
S	rg
)r}   i  z1
File wrapper that normalizes CRLF line endings.
c                 4    Xl         [        USS 5      U l        g )Nr-   )_wrapped_filer   r-   )r,   wrapped_files     r0   r1   NewlineNormalizer.__init__  s    %fd3DIrA   c                 T    U R                   R                  " U6 R                  SS5      $ Ns   
   
)r  readreplacer,   r   s     r0   r  NewlineNormalizer.read  s&    ""D)11'5AArA   c                 T    U R                   R                  " U6 R                  SS5      $ r  )r  r   r  r  s     r0   r   NewlineNormalizer.readline  s&    &&-55guEErA   c                 |    U R                   R                  " U6  Vs/ s H  o"R                  S5      PM     sn$ s  snf )N   )r  	readlinesrF  )r,   r   r   s      r0   r  NewlineNormalizer.readlines  s4    +/+=+=+G+G+NO+N4KK+NOOOs   9c                 4    U R                   R                  " U6 $ r=   )r  r   r  s     r0   r   NewlineNormalizer.seek      ""D))rA   c                 4    U R                   R                  " U6 $ r=   )r  r   r  s     r0   r   NewlineNormalizer.tell  r   rA   )r  r-   N)rB   rC   rD   rE   rF   r1   r  r   r  r   r   rG   rH   rA   r0   r}   r}     s(    4BFP**rA   r}   c                    U(       a  SO/ nSn[         R                  R                  U 5      (       a  U 4n U(       a+  UR                  5       n	U	(       a  Ub  UR	                  U	5        [
        R                  " [        SR                  U 5      -  5      n
 UR                  5       nU(       a  X:  a  OUR                  5       nU(       d  OU
R                  [         R                  R                  R                  U5      5      nU(       aA  UR                  5       S   nU(       d  UR                  U5        OUb  UR	                  U5        OUb  UR	                  U5        M  U(       a  Xx4$ U$ )a  
Reads from the descriptor file until we get to one of the given keywords or reach the
end of the file.

:param str,list keywords: keyword(s) we want to read until
:param file descriptor_file: file with the descriptor content
:param bool inclusive: includes the line with the keyword if True
:param bool ignore_first: doesn't check if the first line read has one of the
  given keywords
:param bool skip: skips buffering content, returning None
:param int end_position: end if we reach this point in the file
:param bool include_ending_keyword: provides the keyword we broke on if **True**

:returns: **list** with the lines until we find one of the keywords, this is
  a two value tuple with the ending keyword if include_ending_keyword is
  **True**
N|r   )r   r   r   r   r   r~   compileSPECIFIC_KEYWORD_LINEr   r   r   r   r   r   r   )keywordsr   	inclusiveignore_firstskipend_positioninclude_ending_keywordr8   ending_keywordr   keyword_matchlast_positionr   r  s                 r0   _read_until_keywordsr    s+   & Db'.	YYx  {H ))+Jg)nnZ **2SXXh5GGH-#((*M5##%D$$TYY%8%8%D%DT%JKJ!((*1-n]+t		nnT/ 	2 $$NrA   c                     SR                  U R                  S5      SS 5      n [        R                  " [        R
                  R                  R                  U 5      5      $ )z
Provides the base64 decoded content of a pgp-style block.

:param str content: block to be decoded

:returns: decoded block content

:raises: **TypeError** if this isn't base64 encoded content
r   r   r   r  )r   r   rC  	b64decoder   r   r   r   rd  s    r0   r  r    sH     GGGMM$'"-.'			$))--77@	AArA   c                 Z   U (       d  g[         R                  U S   5      nU(       a  UR                  5       S   n/ n[        U-  n U (       d"  [	        SU< SSR                  U5      < 35      eU R                  S5      nUR                  U5        XT:X  a  USR                  U5      4$ Me  g)a  
Checks if given contents begins with a pseudo-Open-PGP-style block and, if
so, pops it off and provides it back to the caller.

:param list remaining_contents: lines to be checked for a public key block

:returns: **tuple** of the (block_type, content) or None if it doesn't exist

:raises: **ValueError** if the contents starts with a key block but it's
  malformed (for instance, if it lacks an ending line)
Nr   z+Unterminated pgp style block (looking for 'z'):
r   )PGP_BLOCK_STARTr   r   PGP_BLOCK_ENDr   r   r   r   )remaining_contentsblock_matchr+  block_linesend_liner   s         r0   _get_pseudo_pgp_blockr    s     
%%&8&;<+##%a(JKz)H
S[]a]f]fgr]stuu##A&d		DIIk233  rA   c                    [         R                  R                  5       (       d  [        S5      eSSKJn  SSKJn  SSKJ	n  U cC  UR                  SSU" 5       S9n S	 nX@R                  R                  l        X@R                  l        U R                  5       nS
UR!                  UR"                  R$                  UR&                  R(                  S9R+                  5       -   n[-        XU5      $ )a  
Serializes a signing key if we have one. Otherwise this creates a new signing
key we can use to create descriptors.

.. versionadded:: 1.6.0

:param cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey private_key: private key

:returns: :class:`~stem.descriptor.__init__.SigningKey` that can be used to
  create descriptors

:raises: **ImportError** if the cryptography module is unavailable
(Signing requires the cryptography moduler   r  )serialization)rsai  i   )r  key_sizebackendc                      g)Nr   rH   )r   r   s     r0   no_op!create_signing_key.<locals>.no_op_  s    rA   r  )r(   format)r   r  r  r&   r  r  cryptography.hazmat.primitivesr  )cryptography.hazmat.primitives.asymmetricr  generate_private_key_backend_libEVP_PKEY_CTX_set_signature_mdopenssl_assert
public_keypublic_bytesEncodingPEMPublicFormatPKCS1r   rq   )private_keyr  r  r  r"  r,  rt   s          r0   create_signing_keyr3  ;  s     
	(	(	*	*
@
AA::;**! + K ?D;*/'%%'**11%%))''-- 2  
EG-
 
K]	;;rA   c                    [         R                  R                  5       (       d  [        S5      eSSKJn  SSKJn  [        R                  " UR                  XR                  5       UR                  5       5      5      nU SR                  S/[         R                  R                  R!                  US5      -   S/-   5      -   $ )	a+  
Appends a router signature to a server or extrainfo descriptor.

:param bytes content: descriptor content up through 'router-signature\n'
:param cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey private_key:
  private relay signing key

:returns: **bytes** with the signed descriptor content
r  r   )hashes)paddingr  s   -----BEGIN SIGNATURE-----@   s   -----END SIGNATURE-----
)r   r  r  r&   r%  r5  r&  r6  rC  rD  ra  PKCS1v15r   r   r   r   _split_by_length)r8   r2  r5  r6  r  s        r0   _append_router_signaturer:  n  s     
	(	(	*	*
@
AA3?{//9I9I9KV[[][\)	5::;<tyy?R?R?c?cdmoq?rr  wS  vT  T  U  
U  UrA   c                  <    S[         R                  " SS5      -  S S $ )Nz	Unnamed%ir   l    @ k    randomrandintrH   rA   r0   _random_nicknamer@    s    
q/:
:CR	@@rA   c                  V    S[         R                  " SS-  5      -  R                  5       $ )Nz%040x   r  )r>  	randrangerB  rH   rA   r0   _random_fingerprintrD    s%    
F$$R2X.
.	5	5	77rA   c                      S[         R                  " SS5      [         R                  " SS5      [         R                  " SS5      [         R                  " SS5      4-  $ )Nz%i.%i.%i.%ir      r=  rH   rA   r0   _random_ipv4_addressrG    sI    	&..C0&..C2H&..YZ\_J`bhbpbpqrtwbxy	yyrA   c            
         S[         R                  " SS5      [         R                  " SS5      [         R                  " SS5      [         R                  " SS5      [         R                  " SS	5      [         R                  " SS	5      4-  $ )
Nz%i-%02i-%02i %02i:%02i:%02ii  i  r         r      ;   r=  rH   rA   r0   _random_daterM    s    	&&..t*DfnnUVXZF[]c]k]klmoq]rtz  uC  uC  DE  GI  uJ  LR  LZ  LZ  [\  ^`  La  ci  cq  cq  rs  uw  cx  *y  
y  yrA   c                 F   [         R                  R                  R                  [        R
                  " [        R                  " S5      5      5      nSR                  [         R                  R                  R                  US5      5      nU (       a  SU < SU< SU < S3$ U$ )z>
Provides a random string that can be used for crypto blocks.
   r   r7  z
-----BEGIN z-----
z

-----END z-----)
r   r   r   r   rC  rD  r   urandomr   r9  )r+  random_base64crypto_blobs      r0   _random_crypto_blobrS    sm    
 ))%%11&2B2B2::c?2ST-		$))-->>}bQR+;E{T^__rA   c                    [        U [        5      (       a)  [        R                  R                  R                  U 5      n [        5       n/ nU R                  S5      nU(       Ga  UR                  S5      nU(       d  M"  UR                  S5      (       a  USS n[        R                  U5      nU(       d  U(       d  Mb  [        SU-  5      eUR                  5       u  pU
c  Sn
 [        U5      nU(       a  Uu  pOSu  p U(       a  X;  a   U
R                  S	5        X;   a  UR)                  U	< SU
< 35        O#UR+                  U	/ 5      R)                  XU45        U(       a  GM  U(       a  XE4$ U$ ! [         a    U(       d   GM.  e f = f! [          aQ    SR#                  U
 Vs/ s H  o[$        R&                  ;   a  UOS
PM     Os  snf sn5      n[        SU	< SU< 35      ef = f)a  
Initial breakup of the server descriptor contents to make parsing easier.

A descriptor contains a series of 'keyword lines' which are simply a keyword
followed by an optional value. Lines can also be followed by a signature
block.

To get a sub-listing with just certain keywords use extra_keywords. This can
be useful if we care about their relative ordering with respect to each
other. For instance, we care about the ordering of 'accept' and 'reject'
entries because this influences the resulting exit policy, but for everything
else in server descriptors the order does not matter.

:param str raw_contents: descriptor content provided by the relay
:param bool validate: checks the validity of the descriptor's content if
  True, skips these checks otherwise
:param list extra_keywords: entity keywords to put into a separate listing
  with ordering intact
:param list non_ascii_fields: fields containing non-ascii content

:returns:
  **collections.OrderedDict** with the 'keyword => (value, pgp key) entries'
  mappings. If a extra_keywords was provided then this instead provides a two
  value tuple, the second being a list of those entries.
r   r   zopt    Nz$Line contains invalid characters: %sr   r  ascii?r|   z' line had non-ascii content: rj   )r   bytesr   r   r   r   r   r   r   r   KEYWORD_LINEr   r   r   r  r  UnicodeErrorr   string	printabler   
setdefault)raw_contentsrw   extra_keywordsnon_ascii_fieldsr   extra_entriesremaining_linesr   r  r   r   
block_attrr+  r,  charreplaceds                   r0   _descriptor_componentsrf    s   6 e$$99&&22<@LM'- &&t,/q!D  v!"Xd##D)J=DEE&&(NG}e(9j	%/"
N%/"
N G3VW
  gu56"%,,e-PQs 	v !!N+  	  V77TYZTYDV-=-=%=T3FTYZ['8TUUVs0   $E5 ;E5 F 5F
FG*(!G

	!G*)NrH   rH   rH   r=   )T)Frj   )FFFNF)rH   rH   )YrF   rC  r  collectionsr;  rJ   r   r>  r~   r[  r   stem.prereqr   	stem.utilstem.util.enumstem.util.str_toolsstem.util.systemr   r&   stem.util.ordereddict__all__r   KEYWORD_CHARr   r  rY  r  r  r  setr9  r  DIGEST_PADDINGr  CRYPTO_BLOBr   enumUppercaseEnum
DigestHashr@  DocumentHandlerobjectr   rR   EnumCompression
namedtuplerh   rq   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r(  r0  r  r=  rI  r   r}   r  r  r  r3  r:  r@  rD  rG  rM  rS  rf  stem.descriptor.bandwidth_file$stem.descriptor.extrainfo_descriptorstem.descriptor.hidden_servicestem.descriptor.microdescriptorstem.descriptor.networkstatus!stem.descriptor.server_descriptorstem.descriptor.tordnselrH   rA   r0   <module>r     s  Vp     	 	  	       0%& 
zz|ZPQ/*< **lJWX"CE?    YY^^))


 --
 ))....@6 @F" iinn!![$
FDcde	<  8A  B  C,ww8j
kl	<e=opq	<&:JKLR[++,<>hi R$	''6\] 	 375]l]t]t  LP Zz
 CNLE_P/X">B"5 5D* *2=@B$!H0<fU*A8zy`J & + % & $ ( y,  0//0s    I4 4JJ