
    hĢ                        d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Zddl
ZddlZddlZddlZddlZddlmZmZ 	 ddlmZ ej.                  j0                  j3                  dddd      Zej6                  j4                  j8                  ej6                  j4                  j:                  ej6                  j4                  j<                  ej6                  j4                  j>                  dZ d	Z!d
Z"da#dZ$dZ%d Z&d Z'ddZ(ddZ)d Z*ddZ+d Z,d Z- G d de.      Z/ G d de.      Z0d Z1d Z2d Z3d Z4d Z5ejl                  jn                  Z7ejl                  jp                  Z9ejl                  jt                  Z;y# e$ r ddlZY @w xY w) 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                  .    t         
t               a t         S )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     `/var/www/betterdocs.net/sherlock_api/venv/lib/python3.12/site-packages/stem/descriptor/remote.pyget_instancer      s     !/1	r   c                  6     t               j                  di | S )a  
  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     
0	/	/	=*	==r   c                 8     t               j                  | fi |S )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     t               j                  | fi |S )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     
2	1	1,	M*	MMr   c                 8     t               j                  | fi |S )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                 :     t               j                  | |fi |S )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     t               j                  di | S )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     t               j                  di | S )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     
0	/	/	=*	==r   c            
           e Zd ZdZddej
                  fddddddej                  j                  j                  f
dZ
d ZddZd	 Zd
 ZddZd Zy)Querya  
  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           	      x   |j                  d      st        d|z        |j                  d      rt        j                  g}|d d }n|st        j
                  g}nt        |t              r|g}t        j                  |v r=t        j                  j                         s|j                  t        j                         t        j                  |v r=t        j                  j                         s|j                  t        j                         |st        j
                  g}g }|D ]}  }t        |t        j                  j                         r|j#                  |       9|t$        v r|j#                  t$        |          Zt        d|dt'        |      j(                  d       |r|| _        nt-        |      | _        g | _        |r|D ]  }t        |t0              rDt3        |      dk(  r6| j.                  j#                  t        j4                  |d	   |d
                Wt        |t        j6                  t        j4                  f      r| j.                  j#                  |       t        d|dt'        |      j(                  d       || _        || _        || _        || _        d | _         d | _!        d| _"        d | _#        d | _$        || _%        d | _&        |
| _'        || _(        d | _)        || _*        d | _+        tY        jZ                         | _.        |r| j_                          |	r| ja                  d       y y )N/z%Resources should start with a '/': %sz.z'z' (z)) is not a recognized type of compressionr/   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)selfrN   rG   rI   rO   rP   rQ   rW   ra   blockrY   rZ   r\   new_compressionlegacy_compressionendpoints                   r   __init__zQuery.__init__  s   s#>IJJ %%&k#2h **+k	K	%"m			[	(1N1N1P;++,			[	(1N1N1P;++,",,-
 O) H	&(D(D	E12!6645GHIPbdhi{d|  eF  eF  G  H  	HH ,d3H=dDN V(h&3x=A+=
..

Xa[(1+ F
G4;;"=>
..


)rz  }A  BJ  }K  }T  }T  U  V  VV DM&DDL"8DDLDJDLDDODLDLDM,DDDK"D#,??#4D 
jjl
hhtn r   c                 B   | j                   5  | j                  rt        j                  d| j                  | j
                  | j                  f      | _        | j                  j                  d       | j                  j                          ddd       y# 1 sw Y   yxY w)zI
    Starts downloading the scriptors if we haven't started already.
    NzDescriptor query)nametargetargsT)	r`   r]   r^   Thread_download_descriptorsrP   rW   	setDaemonra   )rc   s    r   ra   zQuery.start  s    
 
	%	% 	(		 	 	("+"2"2#--,,-#
 	))$/%%'	( 	( 	(s   A?BBc                 6    t        | j                  |            S )aS  
    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)rc   suppresss     r   rb   z	Query.run  s    $ 		(#$$r   c              #   f  K   | j                   5  | j                          | j                  j                          | j                  r|r
	 d d d        y | j                  | j
                  |r
	 d d d        y t        d      	 | j                  j                  t              rSt        j                  j                  j                  t        j                  | j
                        | j                         }nit        j                  j"                  t        j                  | j
                        | j                  f| j                   | j$                  d| j&                  }|D ]  }|  	 d d d        y # t        $ r'}|| _        |rY d }~d d d        y | j                  d }~ww xY w# 1 sw Y   y xY ww)NzHBUG: _download_descriptors() finished without either results or an error)rY   )rY   rZ   )r`   ra   r]   joinrS   rR   r7   rG   r6   DETACHED_SIGNATURE_TYPEr<   rA   networkstatus_parse_file_detached_sigsioBytesIOrY   
parse_filerZ   r\   )rc   rs   resultsdescexcs        r   rr   z
Query._run  s    		%	% ,
jjl
""$	
, , jj<<, , ef
f	 !!,,-DEoo33MMjj& N G
 oo00jj&"" !%!6!6	
 G  dJI, ,L  	$*U, ,X 


	M, ,se   F1:F%		F1F%-	F16F%C&E2)	F12	F";	FF%	F1FF""F%%F.*F1c              #   @   K   | j                  d      D ]  }|  y w)NT)rr   )rc   r}   s     r   __iter__zQuery.__iter__I  s"     		$ js   c                    |s| j                   st        j                  t        j                  j
                  j                         j                         D cg c]  }|j                  t        vs| c}      }t        j                  |j                  |j                        S t        j                  | j                         S c c}w )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
    )rI   randomchoicer<   	directory	Authority
from_cachevaluesnicknameDIR_PORT_BLACKLISTrL   addressdir_port)rc   use_authorityauthpickeds       r   _pick_endpointzQuery._pick_endpointM  s     DNN}}t~~/G/G/R/R/T/[/[/]  Jtaeanan  wI  bId  J  Kf\\&..&//::]]4>>** Js   C.Cc                    	 t        j                          | _        | j                  |dk(  xr | j                        }t	        |t
        j                        rYd|j                  d|j                  d| j                  d}t        || j                  | j                        \  | _        | _        nt	        |t
        j                        rud|j                  |j                  | j                  j                  d      fz  | _        | j                   }t#        | j                   | j                  |      \  | _        | _        n$t%        d	|d
t'        |      j(                        t        j                          | j                  z
  | _        t-        j.                  d|| j*                  fz         d| _        y #  t1        j2                         d   }|$|t        j                          | j                  z
  z  }|dkD  rJ||dkD  rCt-        j4                  d| j                   ||fz         | j7                  |dz
  |      cY d| _        S t-        j4                  d| j                   d|       || _        Y xY w# d| _        w xY w)Nr   )r   zORPort :z (resource )zhttp://%s:%i/%sr1   z1BUG: endpoints can only be ORPorts or DirPorts, 'z' was a z'Descriptors retrieved from %s in %0.2fsr4   zCUnable to download descriptors from '%s' (%i retries remaining): %sTz%Unable to download descriptors from 'z': )timerV   r   rQ   r:   r<   rM   r   portrN   _download_from_orportrO   rR   r[   rL   lstriprU   _download_from_dirportr7   rE   rF   rX   r   tracesysexc_infodebugrn   rT   rS   )rc   rP   rW   rg   downloaded_fromr~   s         r   rn   zQuery._download_descriptors_  s    		do$$W\5adFaFa$bh	Hdkk	*:B:J:JHMM[_[h[hi+@4K[K[]a]j]j+k(d(h--1A1A8==RVR_R_RfRfgjRk0ll+++A$BSBSUYUeUegn+o(d(\dfjksftf}f}~YY[4??2dl	ii9_dll<[[\ dlLLN1c		499;00	1'/Wq[		W[_[l[lnuwzZ{{|))'A+w??
 dl 			DDUDUWZ[\
dls%   F,F6 6BI2;I5 ,I20I5 5	I>F)rF   
__module____qualname____doc__r9   r   r<   rA   DocumentHandlerENTRIESrh   ra   rb   rr   r   r   rn   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                   b    e Zd ZdZddZd Zd ZddZddZd Z	dd	Z
d
 ZddZd Zd Zd Zy)r   a  
  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                 &   || _         d | _        |rS	 t        j                         }| j                          t	        j
                  dt        j                         |z
  z         y y # t        $ r"}t	        j
                  d|z         Y d }~y d }~ww xY w)Nz)Retrieved directory mirrors (took %0.2fs)z(Unable to retrieve directory mirrors: %s)_default_args
_endpointsr   use_directory_mirrorsr   r   	Exception)rc   use_mirrorsdefault_argsrV   r~   s        r   rh   zDescriptorDownloader.__init__  s|    %DDODYY[
""$		=zAYZ[	 
  D		<sBCCDs   AA% %	B.BBc                    t         j                  j                  j                         j	                         D cg c]  }|j
                  t        vs| }}t        |D cg c]  }|j                  |j                  f c}      }t        | j                  t         j                  j                  j                        j                               d   }|j                   j	                         D ]]  }t         j"                  j$                  |j&                  v s*|j                  s7|j)                  |j                  |j                  f       _ t        |      | _        |S c c}w c c}w )aB  
    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
    )rZ   r   )r<   r   r   r   r   r   r   setr   r   rq   r&   rA   r   DOCUMENTrb   routersFlagV2DIRflagsaddr   )rc   r   directoriesr   new_endpoints	consensusr}   s          r   r   z*DescriptorDownloader.use_directory_mirrors  s    %)NN$<$<$G$G$I$P$P$R~DVZVcVck}V}4~K~R]^Y)++Y-?-?@^_MT''4??;Z;Z;c;c'dhhjklmnI!!((* 9	DJJ	&4==4<<789 =)DO ^s   E E  E%c                 &     | j                   di |S )a)  
    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
    )z/tor/server/authorityqueryrc   r   s     r   r   z,DescriptorDownloader.their_server_descriptor  s     4::<<<r   Nc                     d}t        |t              r|g}|r8t        |      t        kD  rt	        dt        z        ddj                  |      z  } | j                  |fi |S )a~  
    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;   rK   MAX_FINGERPRINTSr7   ru   r   rc   r   r   rN   s       r   r   z+DescriptorDownloader.get_server_descriptors  sf    " !H,$"^l	\	-	-ehxxyy$sxx'==h4::h-*--r   c                     d}t        |t              r|g}|r8t        |      t        kD  rt	        dt        z        ddj                  |      z  } | j                  |fi |S )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!   z.DescriptorDownloader.get_extrainfo_descriptors  sf    "  H,$"^l	\	-	-ehxxyy#chh|&<<h4::h-*--r   c                     t        |t              r|g}t        |      t        kD  rt	        dt        z         | j
                  ddj                  |      z  fi |S )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;   rK   MAX_MICRODESCRIPTOR_HASHESr7   r   ru   )rc   r$   r   s      r   r#   z)DescriptorDownloader.get_microdescriptors  s`    L &#xf
6{//be  A  A4::'#((6*::IjIIr   c                    |rd}nd}|r|d|z  z  } | j                   |fi |}|j                  r|j                  t        j                  j
                  j                  k(  rkt        j                  j                         rMt        |j                               d   } | j                  di |j                         }|j                  |       |S )a  
    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   rY   rZ   r<   rA   r   r   r=   is_crypto_availablerq   rb   get_key_certificatesvalidate_signatures)rc   r'   r(   r   rN   consensus_queryr   	key_certss           r   r&   z"DescriptorDownloader.get_consensus+  s    ( ?h5h%+++h djj8Z8O
 O$D$DHgHgHpHp$puy  vA  vA  vU  vU  vW**,-a0i+$++9j9==?i##I.r   c                 l    d}d|vr|j                   |j                  fg|d<    | j                  |fi |S )af  
    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/authorityrg   rI   )r   r   r   )rc   	authorityr   rN   s       r   get_votezDescriptorDownloader.get_voteS  sE     4H#"+"3"3Y5G5G!H Ij4::h-*--r   c                     d}t        |t              r|g}|r8t        |      t        kD  rt	        dt        z        ddj                  |      z  } | j                  |fi |S )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   )rc   authority_v3identsr   rN   s       r   r   z)DescriptorDownloader.get_key_certificatesf  sx    ( H$c*./		 #3	3s  wG  G  H  	H"SXX.@%AAh4::h-*--r   c                 &     | j                   di |S )aH  
    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*   z'DescriptorDownloader.get_bandwidth_file  s     4::F:FFr   c                 &     | j                   di |S )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,   z,DescriptorDownloader.get_detached_signatures  s    f 4::QjQQr   c                     t        | j                        }|j                  |       d|vr| j                  |d<   t	        |fi |S )ar  
    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**
    rI   )dictr   updater   r.   )rc   rN   r   rl   s       r   r   zDescriptorDownloader.query  sF    $ ""#DKK
$//d;"T""r   r   NNF)rF   r   r   r   rh   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                    | j                   r| j                   ndg}t        j                  j                  j	                  | j
                  | j                  |      5 }|j                         5 }dj                  d|z  ddj                  t        d |            z  dt        j                  z  f      dz   }|j                  |d	
      }|j                  dd	      \  }}	|	j                  dd	      \  }
}|j                  d      s+t        j                  dt        j                   |      z        i }t        j                   |
      j#                         D ]8  }d|vrt        j                  d|z        |j                  dd	      \  }}|||<   : t%        ||j'                  d            |fcddd       cddd       S # 1 sw Y   nxY w	 ddd       y# 1 sw Y   yxY w)a1  
  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                     | j                   S r   encodingcs    r   <lambda>z'_download_from_orport.<locals>.<lambda>
  s
    

 r   zUser-Agent: %sz

r4   )	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_circuitru   map
USER_AGENTr   splitr6   ProtocolErrorr   _to_unicode
splitlines_decompressget)rg   rO   rN   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==.Q NUZ				 N4H$		#.BK*P QQ4??* 	 	g Q7h!3j$#zz+q9k9""=1  !X[d[p[pq{[|!|}}g''4??A $t""#E#LM
MZZa(
U GKK0B$CDgM/N NN NN N NN N Ns%   G,D>F=*	G=G	GGc                 "   	 t        j                  t        j                  | dj                  t	        d |            t
        j                  d      |      }t        |j                         |j                  j!                  d
            |j                  fS # t        j                  $ r2}t        j                  | |t        j                         d   |      d}~w t        j                         dd	 \  }}t        j                  | ||      xY w)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                     | j                   S r   r   r   s    r   r   z(_download_from_dirport.<locals>.<lambda>5  s
    QZZ r   )zAccept-Encodingz
User-Agent)r   )rW   r/   Nr4   r   r   )urlliburlopenRequestru   r   r<   r   socketrW   DownloadTimeoutr   r   DownloadFailedr   readr   r   )urlrO   rW   r   r~   
stacktraces         r   r   r   !  s    4~~nn!YYs+?'MN
 	H  
X]]_h&6&6&:&:;M&N	OQYQaQa	aa 
 E


sC):G
DD4llnQq)OC


c3

33s   AB D+-C6Dc                    |dk(  r3t         j                  j                  j                  j	                  |       S t         j                  j                  D ]$  }||j
                  k(  s|j	                  |       c S  t        d|z        )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<   rA   r9   r   
decompressr   r7   )r   r   rO   s      r   r   r   D  sx    & ??&&++66t<<__00 *k;'''##D))* 	=HIIr   c                 
   | j                  d      ry| j                  d      ry| j                  d      ry| j                  d      ry| j                  d	      r| j                  d
      s| j                  d      ry| j                  d      ry| j                  d      r	dt        z  S t        j                  j
                  j                  | j                  d      d         ry| j                  d      ryt        d| z        )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.0r1   z
/bandwidthzbandwidth-file 1.0z0Unable to determine the descriptor type for '%s')	r6   r8   rv   r<   util	tor_toolsis_valid_fingerprintr   r7   )rN   s    r   rH   rH   a  s     ("=)=) <(&./ &(*;*;L*I-			1	27			2	3///				1	1(..2Eb2I	J-			<	(!EPQQr   c                  *    t         j                         S )a  
  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   ry   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Enumr9   rA   r   r   r	   r   rD   r   r   r   rv   r   r   r   r   r!   r#   r&   r*   r,   objectr.   r   r   r   r   rH   r  r   	Directoryr   r  FallbackFallbackDirectoryr   r   r   <module>r!     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   E> >	F
F