
    <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JrJr   SSKJr  \R.                  R0                  R3                  SSSS5      r\R6                  R4                  R8                  \R6                  R4                  R:                  \R6                  R4                  R<                  \R6                  R4                  R>                  S.r S	r!S
r"Sq#Sr$Sr%S r&S r'SS jr(SS jr)S r*SS jr+S r,S r- " S S\.5      r/ " S S\.5      r0S r1S r2S r3S r4S r5\Rl                  Rn                  r7\Rl                  Rp                  r9\Rl                  Rt                  r;g! \ a    SSKr GNDf = f) a  
Module for remotely retrieving descriptors from directory authorities and
mirrors. This is the simplest method for getting current tor descriptor
information...

::

  import stem.descriptor.remote

  for desc in stem.descriptor.remote.get_server_descriptors():
    if desc.exit_policy.is_exiting_allowed():
      print('  %s (%s)' % (desc.nickname, desc.fingerprint))

More custom downloading behavior can be done through the
:class:`~stem.descriptor.remote.DescriptorDownloader` class, which issues
:class:`~stem.descriptor.remote.Query` instances to get you descriptor
content. For example...

::

  from stem.descriptor.remote import DescriptorDownloader

  downloader = DescriptorDownloader(
    use_mirrors = True,
    timeout = 10,
  )

  query = downloader.get_server_descriptors()

  print('Exit Relays:')

  try:
    for desc in query.run():
      if desc.exit_policy.is_exiting_allowed():
        print('  %s (%s)' % (desc.nickname, desc.fingerprint))

    print
    print('Query took %0.2f seconds' % query.runtime)
  except Exception as exc:
    print('Unable to retrieve the server descriptors: %s' % exc)

::

  get_instance - Provides a singleton DescriptorDownloader used for...
    |- their_server_descriptor - provides the server descriptor of the relay we download from
    |- get_server_descriptors - provides present server descriptors
    |- get_extrainfo_descriptors - provides present extrainfo descriptors
    |- get_microdescriptors - provides present microdescriptors with the given digests
    |- get_consensus - provides the present consensus or router status entries
    |- get_bandwidth_file - provides bandwidth heuristics used to make the next consensus
    +- get_detached_signatures - authority signatures used to make the next consensus

  Query - Asynchronous request to download tor descriptors
    |- start - issues the query if it isn't already running
    +- run - blocks until the request is finished and provides the results

  DescriptorDownloader - Configurable class for issuing queries
    |- use_directory_mirrors - use directory mirrors to download future descriptors
    |- their_server_descriptor - provides the server descriptor of the relay we download from
    |- get_server_descriptors - provides present server descriptors
    |- get_extrainfo_descriptors - provides present extrainfo descriptors
    |- get_microdescriptors - provides present microdescriptors with the given digests
    |- get_consensus - provides the present consensus or router status entries
    |- get_vote - provides an authority's vote for the next consensus
    |- get_key_certificates - provides present authority key certificates
    |- get_bandwidth_file - provides bandwidth heuristics used to make the next consensus
    |- get_detached_signatures - authority signatures used to make the next consensus
    +- query - request an arbitrary descriptor resource

.. versionadded:: 1.1.0

.. data:: MAX_FINGERPRINTS

  Maximum number of descriptors that can requested at a time by their
  fingerprints.

.. data:: MAX_MICRODESCRIPTOR_HASHES

  Maximum number of microdescriptors that can requested at a time by their
  hashes.

.. data:: Compression (enum)

  Compression when downloading descriptors.

  .. versionadded:: 1.7.0

  =============== ===========
  Compression     Description
  =============== ===========
  **PLAINTEXT**   Uncompressed data.
  **GZIP**        `GZip compression <https://www.gnu.org/software/gzip/>`_.
  **ZSTD**        `Zstandard compression <https://www.zstd.net>`_, this requires the `zstandard module <https://pypi.org/project/zstandard/>`_.
  **LZMA**        `LZMA compression <https://en.wikipedia.org/wiki/LZMA>`_, this requires the 'lzma module <https://docs.python.org/3/library/lzma.html>`_.
  =============== ===========
    N)log	str_tools)	PLAINTEXTidentity)GZIPgzip)ZSTDx-zstd)LZMA
x-tor-lzma)r   r   r
   r   `   Z   zdetached-signature)tor26Sergec                  0    [         c
  [        5       q [         $ )z
Provides the singleton :class:`~stem.descriptor.remote.DescriptorDownloader`
used for this module's shorthand functions.

.. versionadded:: 1.5.0

:returns: singleton :class:`~stem.descriptor.remote.DescriptorDownloader` instance
)SINGLETON_DOWNLOADERDescriptorDownloader     P/home/james-whalen/.local/lib/python3.13/site-packages/stem/descriptor/remote.pyget_instancer      s     !/1	r   c                  6    [        5       R                  " S0 U D6$ )  
Provides the server descriptor of the relay we're downloading from.

.. versionadded:: 1.7.0

:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the server descriptors
r   )r   their_server_descriptor
query_argss    r   r   r      s     
	/	/	=*	==r   c                 8    [        5       R                  " U 40 UD6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_server_descriptors`
on our singleton instance.

.. versionadded:: 1.5.0
)r   get_server_descriptorsfingerprintsr   s     r   r   r      s     
	.	.|	Jz	JJr   c                 8    [        5       R                  " U 40 UD6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_extrainfo_descriptors`
on our singleton instance.

.. versionadded:: 1.5.0
)r   get_extrainfo_descriptorsr   s     r   r"   r"      s     
	1	1,	M*	MMr   c                 8    [        5       R                  " U 40 UD6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_microdescriptors`
on our singleton instance.

.. versionadded:: 1.8.0
)r   get_microdescriptors)hashesr   s     r   r$   r$      s     
	,	,V	Bz	BBr   c                 8    [        5       R                  " X40 UD6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_consensus`
on our singleton instance.

.. versionadded:: 1.5.0
)r   get_consensus)authority_v3identmicrodescriptorr   s      r   r'   r'      s     
	%	%&7	WJ	WWr   c                  6    [        5       R                  " S0 U D6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_bandwidth_file`
on our singleton instance.

.. versionadded:: 1.8.0
r   )r   get_bandwidth_filer   s    r   r+   r+      s     
	*	*	8Z	88r   c                  6    [        5       R                  " S0 U D6$ )z
Shorthand for
:func:`~stem.descriptor.remote.DescriptorDownloader.get_detached_signatures`
on our singleton instance.

.. versionadded:: 1.8.0
r   )r   get_detached_signaturesr   s    r   r-   r-     s     
	/	/	=*	==r   c            
           \ rS rSrSrSS\R                  4SSSSSS\R                  R                  R                  4
S jrS rSS	 jrS
 rS rSS jrS rSrg)Queryi  a(  
Asynchronous request for descriptor content from a directory authority or
mirror. These can either be made through the
:class:`~stem.descriptor.remote.DescriptorDownloader` or directly for more
advanced usage.

To block on the response and get results either call
:func:`~stem.descriptor.remote.Query.run` or iterate over the Query. The
:func:`~stem.descriptor.remote.Query.run` method pass along any errors that
arise...

::

  from stem.descriptor.remote import Query

  query = Query(
    '/tor/server/all',
    timeout = 30,
  )

  print('Current relays:')

  try:
    for desc in Query('/tor/server/all', 'server-descriptor 1.0').run():
      print(desc.fingerprint)
  except Exception as exc:
    print('Unable to retrieve the server descriptors: %s' % exc)

... while iterating fails silently...

::

  print('Current relays:')

  for desc in Query('/tor/server/all', 'server-descriptor 1.0'):
    print(desc.fingerprint)

In either case exceptions are available via our 'error' attribute.

Tor provides quite a few different descriptor resources via its directory
protocol (see section 4.2 and later of the `dir-spec
<https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_).
Commonly useful ones include...

=============================================== ===========
Resource                                        Description
=============================================== ===========
/tor/server/all                                 all present server descriptors
/tor/server/fp/<fp1>+<fp2>+<fp3>                server descriptors with the given fingerprints
/tor/extra/all                                  all present extrainfo descriptors
/tor/extra/fp/<fp1>+<fp2>+<fp3>                 extrainfo descriptors with the given fingerprints
/tor/micro/d/<hash1>-<hash2>                    microdescriptors with the given hashes
/tor/status-vote/current/consensus              present consensus
/tor/status-vote/current/consensus-microdesc    present microdescriptor consensus
/tor/status-vote/next/bandwidth                 bandwidth authority heuristics for the next consenus
/tor/status-vote/next/consensus-signatures      detached signature, used for making the next consenus
/tor/keys/all                                   key certificates for the authorities
/tor/keys/fp/<v3ident1>+<v3ident2>              key certificates for specific authorities
=============================================== ===========

**ZSTD** compression requires `zstandard
<https://pypi.org/project/zstandard/>`_, and **LZMA** requires the `lzma
module <https://docs.python.org/3/library/lzma.html>`_.

For legacy reasons if our resource has a '.z' suffix then our **compression**
argument is overwritten with Compression.GZIP.

.. versionchanged:: 1.7.0
   Added support for downloading from ORPorts.

.. versionchanged:: 1.7.0
   Added the compression argument.

.. versionchanged:: 1.7.0
   Added the reply_headers attribute.

   The class this provides changed between Python versions. In python2
   this was called httplib.HTTPMessage, whereas in python3 the class was
   renamed to http.client.HTTPMessage.

.. versionchanged:: 1.7.0
   Endpoints are now expected to be :class:`~stem.DirPort` or
   :class:`~stem.ORPort` instances. Usage of tuples for this
   argument is deprecated and will be removed in the future.

.. versionchanged:: 1.7.0
   Avoid downloading from tor26. This directory authority throttles its
   DirPort to such an extent that requests either time out or take on the
   order of minutes.

.. versionchanged:: 1.7.0
   Avoid downloading from Bifroest. This is the bridge authority so it
   doesn't vote in the consensus, and apparently times out frequently.

.. versionchanged:: 1.8.0
   Serge has replaced Bifroest as our bridge authority. Avoiding descriptor
   downloads from it instead.

.. versionchanged:: 1.8.0
   Defaulting to gzip compression rather than plaintext downloads.

.. versionchanged:: 1.8.0
   Using :class:`~stem.descriptor.__init__.Compression` for our compression
   argument, usage of strings or this module's Compression enum is deprecated
   and will be removed in stem 2.x.

:var str resource: resource being fetched, such as '/tor/server/all'
:var str descriptor_type: type of descriptors being fetched (for options see
  :func:`~stem.descriptor.__init__.parse_file`), this is guessed from the
  resource if **None**

:var list endpoints: :class:`~stem.DirPort` or :class:`~stem.ORPort` of the
  authority or mirror we're querying, this uses authorities if undefined
:var list compression: list of :data:`stem.descriptor.Compression`
  we're willing to accept, when none are mutually supported downloads fall
  back to Compression.PLAINTEXT
:var int retries: number of times to attempt the request if downloading it
  fails
:var bool fall_back_to_authority: when retrying request issues the last
  request to a directory authority if **True**

:var str content: downloaded descriptor content
:var Exception error: exception if a problem occured
:var bool is_done: flag that indicates if our request has finished

:var float start_time: unix timestamp when we first started running
:var http.client.HTTPMessage reply_headers: headers provided in the response,
  **None** if we haven't yet made our request
:var float runtime: time our query took, this is **None** if it's not yet
  finished

:var bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:var stem.descriptor.__init__.DocumentHandler document_handler: method in
  which to parse a :class:`~stem.descriptor.networkstatus.NetworkStatusDocument`
:var dict kwargs: additional arguments for the descriptor constructor

Following are only applicable when downloading from a
:class:`~stem.DirPort`...

:var float timeout: duration before we'll time out our request
:var str download_url: last url used to download the descriptor, this is
  unset until we've actually made a download attempt

:param bool start: start making the request when constructed (default is **True**)
:param bool block: only return after the request has been completed, this is
  the same as running **query.run(True)** (default is **False**)
N   FTc           	         UR                  S5      (       d  [        SU-  5      eUR                  S5      (       a  [        R                  /nUS S nOU(       d  [        R
                  /nO[        U[        5      (       a  U/n[        R                  U;   aB  [        R                  R                  5       (       d  UR                  [        R                  5        [        R                  U;   aB  [        R                  R                  5       (       d  UR                  [        R                  5        U(       d  [        R
                  /n/ nU H  n[        U[        R                  R                   5      (       a  UR#                  U5        M?  U[$        ;   a  UR#                  [$        U   5        Mc  [        SU< S['        U5      R(                  < S35      e   U(       a  X l        O[-        U5      U l        / U l        U(       a  U H  n[        U[0        5      (       aG  [3        U5      S:X  a8  U R.                  R#                  [        R4                  " US	   US
   5      5        M_  [        U[        R6                  [        R4                  45      (       a  U R.                  R#                  U5        M  [        SU< S['        U5      R(                  < S35      e   Xl        Xl        XPl        X`l        S U l         S U l!        SU l"        S U l#        S U l$        Xpl%        S U l&        Xl'        Xl(        S U l)        Xl*        S U l+        [X        RZ                  " 5       U l.        U(       a  U R_                  5         U	(       a  U Ra                  S5        g g )N/z%Resources should start with a '/': %sz.z'z' (z)) is not a recognized type of compressionr0   r      zEEndpoints must be an stem.ORPort, stem.DirPort, or two value tuple. 'z' is a .FT)1
startswith
ValueErrorendswithCompressionr   r   
isinstancestrr	   stemprereqis_zstd_availableremover   is_lzma_available
descriptor_CompressionappendCOMPRESSION_MIGRATIONtype__name__descriptor_type_guess_descriptor_type	endpointstuplelenDirPortORPortresourcecompressionretriesfall_back_to_authoritycontenterroris_donedownload_url
start_timetimeoutruntimevalidatedocument_handlerreply_headerskwargs_downloader_thread	threadingRLock_downloader_thread_lockstartrun)selfrO   rH   rJ   rP   rQ   rR   rX   rb   blockrZ   r[   r]   new_compressionlegacy_compressionendpoints                   r   __init__Query.__init__  s   s##>IJJ %%&k#2h **+k	K	%	%"m			[	(1N1N1P1P;++,			[	(1N1N1P1P;++,",,-
 O)	&(D(D	E	E12!6645GHIPbdhi{d|  eF  eF  G  H  	H * ,3H=dDN(h&&3x=A+=
..

Xa[(1+ F
G4;;"=>>
..


)rz  }A  BJ  }K  }T  }T  U  V  V   M&L"8DLDJDLDDOLDLM,DK"D#,??#4D 
jjl
hhtn r   c                 J   U R                      U R                  cp  [        R                  " SU R                  U R
                  U R                  4S9U l        U R                  R                  S5        U R                  R                  5         SSS5        g! , (       d  f       g= f)zA
Starts downloading the scriptors if we haven't started already.
NzDescriptor query)nametargetargsT)	ra   r^   r_   Thread_download_descriptorsrQ   rX   	setDaemonrb   )rd   s    r   rb   Query.start  s|    
 
	%	%		 	 	("+"2"2#--,,-#
 	))$/%%' 
&	%	%s   A>B
B"c                 6    [        U R                  U5      5      $ )a'  
Blocks until our request is complete then provides the descriptors. If we
haven't yet started our request then this does so.

:param bool suppress: avoids raising exceptions if **True**

:returns: list for the requested :class:`~stem.descriptor.__init__.Descriptor` instances

:raises:
  Using the iterator can fail with the following if **suppress** is
  **False**...

    * **ValueError** if the descriptor contents is malformed
    * :class:`~stem.DownloadTimeout` if our request timed out
    * :class:`~stem.DownloadFailed` if our request fails
)list_run)rd   suppresss     r   rc   	Query.run  s    $ 		(#$$r   c              #     #    U R                      U R                  5         U R                  R                  5         U R                  (       a  U(       a
   S S S 5        g U R                  eU R
                  c  U(       a
   S S S 5        g [        S5      e U R                  R                  [        5      (       aQ  [        R                  R                  R                  [        R                  " U R
                  5      U R                   S9nOk[        R                  R"                  " [        R                  " U R
                  5      U R                  4U R                   U R$                  S.U R&                  D6nU H  nUv   M	      S S S 5        g ! [         a+  nX@l        U(       a   S nAS S S 5        g U R                  eS nAff = f! , (       d  f       g = f7f)NzHBUG: _download_descriptors() finished without either results or an error)rZ   )rZ   r[   )ra   rb   r^   joinrT   rS   r8   rH   r7   DETACHED_SIGNATURE_TYPEr=   rB   networkstatus_parse_file_detached_sigsioBytesIOrZ   
parse_filer[   r]   )rd   rv   resultsdescexcs        r   ru   
Query._run  sq    		%	%
jjl
""$	
 
&	% jj<< 
&	% ef
f	 !!,,-DEEoo33MMjj& N G
 oo00jj&"" !%!6!6	
 G dJ I 
&	%L  	*U 
&	%X 


	M 
&	%sf   GAG	G!G=	GGC-F	 	G	
F>F9 G$	G-F99F>>G
GGc              #   D   #    U R                  S5       H  nUv   M	     g 7f)NT)ru   )rd   r   s     r   __iter__Query.__iter__I  s     		$j  s    c                    U(       d  U R                   (       d  [        R                  " [        R                  R
                  R                  5       R                  5        Vs/ s H  o"R                  [        ;  d  M  UPM     sn5      n[        R                  " UR                  UR                  5      $ [        R                  " U R                   5      $ s  snf )a  
Provides an endpoint to query. If we have multiple endpoints then one
is picked at random.

:param bool use_authority: ignores our endpoints and uses a directory
  authority instead

:returns: :class:`stem.Endpoint` for the location to be downloaded
  from by this request
)rJ   randomchoicer=   	directory	Authority
from_cachevaluesnicknameDIR_PORT_BLACKLISTrM   addressdir_port)rd   use_authorityauthpickeds       r   _pick_endpointQuery._pick_endpointM  s     DNN}}t~~/G/G/R/R/T/[/[/]  J/]tanan  wI  bId/]  J  Kf\\&..&//::]]4>>** Js   !C<Cc                 6    [         R                   " 5       U l        U R                  US:H  =(       a    U R                  S9n[	        U[
        R                  5      (       a[  SUR                  < SUR                  < SU R                  < S3n[        X0R                  U R                  5      u  U l        U l        O[	        U[
        R                  5      (       au  SUR                  UR                  U R                  R                  S5      4-  U l        U R                   n[#        U R                   U R                  U5      u  U l        U l        O&[%        S	U< S
['        U5      R(                  < 35      e[         R                   " 5       U R                  -
  U l        [,        R.                  " SX@R*                  4-  5        SU l        g !   [0        R2                  " 5       S   nUb%  U[         R                   " 5       U R                  -
  -  nUS:  aL  Ub  US:  aC  [,        R4                  " SU R                   X4-  5        U R7                  US-
  U5      s SU l        $ [,        R4                  " SU R                   < SU< 35        XPl         N= f! SU l        f = f)Nr   )r   zORPort :z (resource )zhttp://%s:%i/%sr2   z1BUG: endpoints can only be ORPorts or DirPorts, 'z' was a z'Descriptors retrieved from %s in %0.2fsr5   zCUnable to download descriptors from '%s' (%i retries remaining): %sTz%Unable to download descriptors from 'z': )timerW   r   rR   r;   r=   rN   r   portrO   _download_from_orportrP   rS   r\   rM   lstriprV   _download_from_dirportr8   rF   rG   rY   r   tracesysexc_infodebugrp   rU   rT   )rd   rQ   rX   rh   downloaded_fromr   s         r   rp   Query._download_descriptors_  s   		do$$W\5adFaFa$bh	Hdkk	*	*:B:J:JHMM[_[h[hi+@K[K[]a]j]j+k(d(h---1A1A8==RVR_R_RfRfgjRk0ll+++A$BSBSUYUeUegn+o(d(\dfjksftf}f}~YY[4??2dl	ii9_ll<[[\ dlLLN1c		499;00	1'/Wq[		W[_[l[lnuZ{{|))'A+w??
 dl 			DDUDUWZ[\
dls%   F>G BJJ .J
J 	J)r^   ra   rP   rS   rH   r[   rV   rJ   rT   rR   rU   r]   r\   rO   rQ   rY   rW   rX   rZ   F)rG   
__module____qualname____firstlineno____doc__r:   r   r=   rB   DocumentHandlerENTRIESri   rb   rc   ru   r   r   rp   __static_attributes__r   r   r   r/   r/     s    Sj 264XcXhXhWjvw  SX  dh  rv  @E  RW  lp  l{  l{  lK  lK  lS  lS M^( %(-^+$r   r/   c                   t    \ rS rSrSrSS jrS rS rSS jrSS jr	S	 r
SS
 jrS rSS jrS rS rS rSrg)r   i  av  
Configurable class that issues :class:`~stem.descriptor.remote.Query`
instances on your behalf.

:param bool use_mirrors: downloads the present consensus and uses the directory
  mirrors to fetch future requests, this fails silently if the consensus
  cannot be downloaded
:param default_args: default arguments for the
  :class:`~stem.descriptor.remote.Query` constructor
c                 8   X l         S U l        U(       aV   [        R                  " 5       nU R                  5         [        R
                  " S[        R                  " 5       U-
  -  5        g g ! [         a#  n[        R
                  " SU-  5         S nAg S nAff = f)Nz)Retrieved directory mirrors (took %0.2fs)z(Unable to retrieve directory mirrors: %s)_default_args
_endpointsr   use_directory_mirrorsr   r   	Exception)rd   use_mirrorsdefault_argsrW   r   s        r   ri   DescriptorDownloader.__init__  sz    %DODYY[
""$		=zAYZ[	 
  D		<sBCCDs   AA, ,
B6BBc                    [         R                  R                  R                  5       R	                  5        Vs/ s H  oR
                  [        ;  d  M  UPM     nn[        U Vs/ s H  o3R                  UR                  4PM     sn5      n[        U R                  [         R                  R                  R                  S9R                  5       5      S   nUR                   R	                  5        Hg  n[         R"                  R$                  UR&                  ;   d  M-  UR                  (       d  M@  UR)                  UR                  UR                  45        Mi     [        U5      U l        U$ s  snf s  snf )a*  
Downloads the present consensus and configures ourselves to use directory
mirrors, in addition to authorities.

:returns: :class:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3`
  from which we got the directory mirrors

:raises: **Exception** if unable to determine the directory mirrors
)r[   r   )r=   r   r   r   r   r   r   setr   r   rt   r'   rB   r   DOCUMENTrc   routersFlagV2DIRflagsaddr   )rd   r   directoriesr   new_endpoints	consensusr   s          r   r   *DescriptorDownloader.use_directory_mirrors  s    %)NN$<$<$G$G$I$P$P$R~$RDVcVck}V}4$RK~R]^R]Y++Y-?-?@R]^_MT''4??;Z;Z;c;c'dhhjklmnI!!((*	DJJ	&4===4<<78 + =)DO ^s   E/E/%!E4c                 &    U R                   " S0 UD6$ )r   )z/tor/server/authorityqueryrd   r   s     r   r   ,DescriptorDownloader.their_server_descriptor  s     ::<<<r   Nc                     Sn[        U[        5      (       a  U/nU(       a9  [        U5      [        :  a  [	        S[        -  5      eSSR                  U5      -  nU R                  " U40 UD6$ )aR  
Provides the server descriptors with the given fingerprints. If no
fingerprints are provided then this returns all descriptors known
by the relay.

:param str,list fingerprints: fingerprint or list of fingerprints to be
  retrieved, gets all descriptors if **None**
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the server descriptors

:raises: **ValueError** if we request more than 96 descriptors by their
  fingerprints (this is due to a limit on the url length by squid proxies).
z/tor/server/allJUnable to request more than %i descriptors at a time by their fingerprintsz/tor/server/fp/%s+r;   r<   rL   MAX_FINGERPRINTSr8   ry   r   rd   r    r   rO   s       r   r   +DescriptorDownloader.get_server_descriptors  sg    " !H,$$"^l	\	-	-ehxxyy$sxx'==h::h-*--r   c                     Sn[        U[        5      (       a  U/nU(       a9  [        U5      [        :  a  [	        S[        -  5      eSSR                  U5      -  nU R                  " U40 UD6$ )a^  
Provides the extrainfo descriptors with the given fingerprints. If no
fingerprints are provided then this returns all descriptors in the present
consensus.

:param str,list fingerprints: fingerprint or list of fingerprints to be
  retrieved, gets all descriptors if **None**
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the extrainfo descriptors

:raises: **ValueError** if we request more than 96 descriptors by their
  fingerprints (this is due to a limit on the url length by squid proxies).
z/tor/extra/allr   z/tor/extra/fp/%sr   r   r   s       r   r"   .DescriptorDownloader.get_extrainfo_descriptors  sg    "  H,$$"^l	\	-	-ehxxyy#chh|&<<h::h-*--r   c                     [        U[        5      (       a  U/n[        U5      [        :  a  [	        S[        -  5      eU R
                  " SSR                  U5      -  40 UD6$ )a  
Provides the microdescriptors with the given hashes. To get these see the
**microdescriptor_digest** attribute of
:class:`~stem.descriptor.router_status_entry.RouterStatusEntryMicroV3`.
Note that these are only provided via the **microdescriptor consensus**.
For exampe...

::

  >>> import stem.descriptor.remote
  >>> consensus = stem.descriptor.remote.get_consensus(microdescriptor = True).run()
  >>> my_router_status_entry = list(filter(lambda desc: desc.nickname == 'caersidi', consensus))[0]
  >>> print(my_router_status_entry.microdescriptor_digest)
  IQI5X2A5p0WVN/MgwncqOaHF2f0HEGFEaxSON+uKRhU

  >>> my_microdescriptor = stem.descriptor.remote.get_microdescriptors([my_router_status_entry.microdescriptor_digest]).run()[0]
  >>> print(my_microdescriptor)
  onion-key
  -----BEGIN RSA PUBLIC KEY-----
  MIGJAoGBAOJo9yyVgG8ksEHQibqPIEbLieI6rh1EACRPiDiV21YObb+9QEHaR3Cf
  FNAzDbGhbvADLBB7EzuViL8w+eXQUOaIsJRdymh/wuUJ78bv5oEIJhthKq/Uqa4P
  wKHXSZixwAHfy8NASTX3kxu9dAHWU3Owb+4W4lR2hYM0ZpoYYkThAgMBAAE=
  -----END RSA PUBLIC KEY-----
  ntor-onion-key kWOHNd+2uBlMpcIUbbpFLiq/rry66Ep6MlwmNpwzcBg=
  id ed25519 xE/GeYImYAIB0RbzJXFL8kDLpDrj/ydCuCdvOgC4F/4

:param str,list hashes: microdescriptor hash or list of hashes to be
  retrieved
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the microdescriptors

:raises: **ValueError** if we request more than 92 microdescriptors by their
  hashes (this is due to a limit on the url length by squid proxies).
zIUnable to request more than %i microdescriptors at a time by their hashesz/tor/micro/d/%s-)r;   r<   rL   MAX_MICRODESCRIPTOR_HASHESr8   r   ry   )rd   r%   r   s      r   r$   )DescriptorDownloader.get_microdescriptors  sa    L &#xf
6{//be  A  A::'#((6*::IjIIr   c                    U(       a  SnOSnU(       a  USU-  -  nU R                   " U40 UD6nUR                  (       a  UR                  [        R                  R
                  R                  :X  ap  [        R                  R                  5       (       aM  [        UR                  5       5      S   nU R                  " S0 UD6R                  5       nUR                  U5        U$ )al  
Provides the present router status entries.

.. versionchanged:: 1.5.0
   Added the microdescriptor argument.

:param str authority_v3ident: fingerprint of the authority key for which
  to get the consensus, see `'v3ident' in tor's config.c
  <https://gitweb.torproject.org/tor.git/tree/src/or/config.c>`_
  for the values.
:param bool microdescriptor: provides the microdescriptor consensus if
  **True**, standard consensus otherwise
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the router status
  entries
z,/tor/status-vote/current/consensus-microdescz"/tor/status-vote/current/consensusz/%sr   r   )r   rZ   r[   r=   rB   r   r   r>   is_crypto_availablert   rc   get_key_certificatesvalidate_signatures)rd   r(   r)   r   rO   consensus_queryr   	key_certss           r   r'   "DescriptorDownloader.get_consensus+  s    ( ?h5h%+++hjj8Z8O
 O$D$DHgHgHpHp$puy  vA  vA  vU  vU  vW  vW**,-a0i++9j9==?i##I.r   c                 p    SnSU;  a  UR                   UR                  4/US'   U R                  " U40 UD6$ )aJ  
Provides the present vote for a given directory authority.

:param stem.directory.Authority authority: authority for which to retrieve a vote for
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the router status
  entries
z"/tor/status-vote/current/authorityrh   rJ   )r   r   r   )rd   	authorityr   rO   s       r   get_voteDescriptorDownloader.get_voteS  sC     4H#"+"3"3Y5G5G!H Ij::h-*--r   c                     Sn[        U[        5      (       a  U/nU(       a9  [        U5      [        :  a  [	        S[        -  5      eSSR                  U5      -  nU R                  " U40 UD6$ )a  
Provides the key certificates for authorities with the given fingerprints.
If no fingerprints are provided then this returns all present key
certificates.

:param str authority_v3idents: fingerprint or list of fingerprints of the
  authority keys, see `'v3ident' in tor's config.c
  <https://gitweb.torproject.org/tor.git/tree/src/or/config.c#n819>`_
  for the values.
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the key certificates

:raises: **ValueError** if we request more than 96 key certificates by
  their identity fingerprints (this is due to a limit on the url length by
  squid proxies).
z/tor/keys/allzXUnable to request more than %i key certificates at a time by their identity fingerprintsz/tor/keys/fp/%sr   r   )rd   authority_v3identsr   rO   s       r   r   )DescriptorDownloader.get_key_certificatesf  sy    ( H$c**./		 #3	3s  wG  G  H  	H"SXX.@%AAh::h-*--r   c                 &    U R                   " S0 UD6$ )a(  
Provides the bandwidth authority heuristics used to make the next
consensus.

.. versionadded:: 1.8.0

:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the bandwidth
  authority heuristics
)z/tor/status-vote/next/bandwidthr   r   s     r   r+   'DescriptorDownloader.get_bandwidth_file  s     ::F:FFr   c                 &    U R                   " S0 UD6$ )a  
Provides the detached signatures that will be used to make the next
consensus. Please note that **these are only available during minutes 55-60
each hour**. If requested during minutes 0-55 tor will not service these
requests, and this will fail with a 404.

For example...

::

  import stem.descriptor.remote

  detached_sigs = stem.descriptor.remote.get_detached_signatures().run()[0]

  for i, sig in enumerate(detached_sigs.signatures):
    print('Signature %i is from %s' % (i + 1, sig.identity))

**When available (minutes 55-60 of the hour)**

::

  % python demo.py
  Signature 1 is from 0232AF901C31A04EE9848595AF9BB7620D4C5B2E
  Signature 2 is from 14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4
  Signature 3 is from 23D15D965BC35114467363C165C4F724B64B4F66
  ...

**When unavailable (minutes 0-55 of the hour)**

::

  % python demo.py
  Traceback (most recent call last):
    File "demo.py", line 3, in
      detached_sigs = stem.descriptor.remote.get_detached_signatures().run()[0]
    File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 533, in run
      return list(self._run(suppress))
    File "/home/atagar/Desktop/stem/stem/descriptor/remote.py", line 544, in _run
      raise self.error
  stem.DownloadFailed: Failed to download from http://154.35.175.225:80/tor/status-vote/next/consensus-signatures (HTTPError): Not found

.. versionadded:: 1.8.0

:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the detached
  signatures
)z*/tor/status-vote/next/consensus-signaturesr   r   s     r   r-   ,DescriptorDownloader.get_detached_signatures  s    f ::QjQQr   c                     [        U R                  5      nUR                  U5        SU;  a  U R                  US'   [	        U40 UD6$ )aF  
Issues a request for the given resource.

.. versionchanged:: 1.7.0
   The **fall_back_to_authority** default when using this method is now
   **False**, like the :class:`~stem.descriptor.Query` class.

:param str resource: resource being fetched, such as '/tor/server/all'
:param query_args: additional arguments for the
  :class:`~stem.descriptor.remote.Query` constructor

:returns: :class:`~stem.descriptor.remote.Query` for the descriptors

:raises: **ValueError** if resource is clearly invalid or the descriptor
  type can't be determined when 'descriptor_type' is **None**
rJ   )dictr   updater   r/   )rd   rO   r   rn   s       r   r   DescriptorDownloader.query  sF    $ ""#DKK
$//d;"T""r   )r   r   r   NNF)rG   r   r   r   r   ri   r   r   r   r"   r$   r'   r   r   r+   r-   r   r   r   r   r   r   r     sK    	D4=.<.<,J\&P.&.BG 3Rj#r   r   c                    U R                   (       a  U R                   OS/n[        R                  R                  R	                  U R
                  U R                  U5       nUR                  5        nSR                  SU-  SSR                  [        S U5      5      -  S[        R                  -  45      S-   nUR                  US	S
9nUR                  SS	5      u  pU	R                  SS	5      u  pUR                  S5      (       d-  [        R                  " S[        R                   " U5      -  5      e0 n[        R                   " U
5      R#                  5        H:  nSU;  a  [        R                  " SU-  5      eUR                  SS	5      u  pXU'   M<     [%        XR'                  S5      5      U4sSSS5        sSSS5        $ ! , (       d  f       O= f SSS5        g! , (       d  f       g= f)a	  
Downloads descriptors from the given orport. Payload is just like an http
response (headers and all)...

::

  HTTP/1.0 200 OK
  Date: Mon, 23 Apr 2018 18:43:47 GMT
  Content-Type: text/plain
  X-Your-Address-Is: 216.161.254.25
  Content-Encoding: identity
  Expires: Wed, 25 Apr 2018 18:43:47 GMT

  router dannenberg 193.23.244.244 443 0 80
  identity-ed25519
  ... rest of the descriptor content...

:param stem.ORPort endpoint: endpoint to download from
:param list compression: compression methods for the request
:param str resource: descriptor resource to download

:returns: two value tuple of the form (data, reply_headers)

:raises:
  * :class:`stem.ProtocolError` if not a valid descriptor response
  * :class:`stem.SocketError` if unable to establish a connection
   z
zGET %s HTTP/1.0zAccept-Encoding: %s, c                     U R                   $ r   encodingcs    r   <lambda>'_download_from_orport.<locals>.<lambda>
  s    

r   zUser-Agent: %sz

r5   )	stream_ids   
s   

s
   HTTP/1.0 2z5Response should begin with HTTP success, but was '%s'z: z'%s' is not a HTTP header:

%sContent-EncodingN)link_protocolsr=   clientRelayconnectr   r   create_circuitry   map
USER_AGENTr   splitr7   ProtocolErrorr   _to_unicode
splitlines_decompressget)rh   rP   rO   r   relaycircrequestresponse
first_linedataheader_data	body_dataheaderslinekeyvalues                   r   r   r     s   : /7.E.E8**A3.{{  !1!18==.QUZ				4H$		#.BK*P QQ4??* 	 	g Q7h!3j#zz+q9k""=11  !X[d[p[pq{[|!|}}g''4??A$t""#E#LM
MZZa(
 B KK0B$CDgM/ 
 	 RQ			 RQQs%    G"1EG4	G"
G	G""
G0c                     [         R                  " [         R                  " U SR                  [	        S U5      5      [
        R                  S.S9US9n[        UR                  5       UR                  R!                  S
5      5      UR                  4$ ! [        R                   a3  n[
        R                  " X[        R                  " 5       S   U5      eSnAf  [        R                  " 5       SS	 u  pE[
        R                  " XU5      e= f)a  
Downloads descriptors from the given url.

:param str url: dirport url from which to download from
:param list compression: compression methods for the request
:param float timeout: duration before we'll time out our request

:returns: two value tuple of the form (data, reply_headers)

:raises:
  * :class:`~stem.DownloadTimeout` if our request timed out
  * :class:`~stem.DownloadFailed` if our request fails
r   c                     U R                   $ r   r   r   s    r   r   (_download_from_dirport.<locals>.<lambda>5  s    QZZr   )zAccept-Encodingz
User-Agent)r  )rX   r0   Nr5   r   r   )urlliburlopenRequestry   r   r=   r   socketrX   DownloadTimeoutr   r   DownloadFailedr  readr  r  )urlrP   rX   r  r   
stacktraces         r   r   r   !  s    4~~nn!YYs+?'MN
 	H  
X]]_h&6&6&:&:;M&N	OQYQaQa	aa 
 E


s):G
DD4llnQq)OC


c

33s   AB D(.C6Dc                    US:X  a3  [         R                  R                  R                  R	                  U 5      $ [         R                  R                   H%  nXR
                  :X  d  M  UR	                  U 5      s  $    [        SU-  5      e)a$  
Decompresses descriptor data.

Tor doesn't include compression headers. As such when using gzip we
need to include '32' for automatic header detection...

  https://stackoverflow.com/questions/3122145/zlib-error-error-3-while-decompressing-incorrect-header-check/22310760#22310760

... and with zstd we need to use the streaming API.

:param bytes data: data we received
:param str encoding: 'Content-Encoding' header of the response

:raises:
  * **ValueError** if encoding is unrecognized
  * **ImportError** if missing the decompression module
deflatez('%s' isn't a recognized type of encoding)r=   rB   r:   r   
decompressr   r8   )r
  r   rP   s      r   r  r  D  sq    & ??&&++66t<<__00k'''##D)) 1 	=HIIr   c                 x   U R                  S5      (       a  gU R                  S5      (       a  gU R                  S5      (       a  gU R                  S5      (       a  gU R                  S	5      (       a  U R                  S
5      (       d  U R                  S5      (       a  gU R                  S5      (       a  gU R                  S5      (       a	  S[        -  $ [        R                  R
                  R                  U R                  S5      S   5      (       a  gU R                  S5      (       a  g[        SU -  5      e)Nz/tor/server/zserver-descriptor 1.0z/tor/extra/zextra-info 1.0z/tor/micro/zmicrodescriptor 1.0z
/tor/keys/zdir-key-certificate-3 1.0z/tor/status-vote/z
/consensusz
/authorityznetwork-status-consensus-3 1.0z/consensus-microdescz(network-status-microdesc-consensus-3 1.0z/consensus-signaturesz%s 1.0r2   z
/bandwidthzbandwidth-file 1.0z0Unable to determine the descriptor type for '%s')	r7   r9   rz   r=   util	tor_toolsis_valid_fingerprintr   r8   )rO   s    r   rI   rI   a  s    (("=))=)) <((&.// &&(*;*;L*I*I-			1	2	27			2	3	3///				1	1(..2Eb2I	J	J-			<	(	(!EPQQr   c                  *    [         R                  5       $ )au  
Provides cached Tor directory authority information. The directory
information hardcoded into Tor and occasionally changes, so the information
this provides might not necessarily match your version of tor.

.. deprecated:: 1.7.0
   Use stem.directory.Authority.from_cache() instead.

:returns: **dict** of **str** nicknames to :class:`~stem.directory.Authority` instances
)DirectoryAuthorityr   r   r   r   get_authoritiesr'    s     
	&	&	((r   r   r   )<r   r}   r   r  r   r_   r   r=   stem.clientstem.descriptorstem.descriptor.networkstatusstem.directorystem.prereqstem.util.enumstem.util.tor_tools	stem.utilr   r   urllib.requestr  r  ImportErrorurllib2r"  enumEnumr:   rB   r   r   r	   r   rE   r   r   r   rz   r   r   r   r   r"   r$   r'   r+   r-   objectr/   r   r   r   r  rI   r'  r   	Directoryr   r&  FallbackFallbackDirectoryr   r   r   <module>r9     s  _B 
   
      $     $! iinn!!	 oo))33
//
%
%
*
*OO'',,++00	      /  ( $>	K	N	C	X	9	>lF l^d#6 d#N7Nt bFJ:R<)" NN$$	^^-- NN++ q   s   F 
FF