
    <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  SSKJrJrJrJrJrJrJrJrJrJrJrJrJrJ r J!r!J"r"J#r#J$r$J%r%J&r&J'r'J(r(J)r)J*r*  \RV                  RY                  5       (       a  SSKJ-r-  OSSK.J-r-  Sr/Sr0\Rb                  Rd                  Rg                  SS	S
SS5      r4\Rj                  Rm                  S5      r7\Rj                  Rq                  S5      r9Sr:S r;S^S jr<S r=S r>S r?S r@S rAS rBS rCS rDS rES rFS rG\" SS5      rH\" SS5      rI\!" S S 5      rJ\"" S!S!5      rK\R                  " \ES"S#S$S%5      rM\R                  " \ES&S'S(S)5      rN\" S*S+S, S-9rO\ " S.S/5      rP\ " S0S15      rQ\$" S2S35      rR\ " S4S55      rS\ " S6S75      rT\" S8S95      rU\" S:S:S; S-9rV\" S<S<S= S-9rW\%" S>S?S@5      rX\%" SASBSC5      rY\%" SDSES@5      rZ\%" SFSGSH5      r[\" SISJ5      r\\%" SKSLSMSN5      r]\" SOSP5      r^\" SQSR5      r_\#" SSST5      r`\" SUSUSVSW9ra " SX SY\5      rb " SZ S[\b5      rc " S\ S]\b5      rdg)_a  
Parsing for Tor server descriptors, which contains the infrequently changing
information about a Tor relay (contact information, exit policy, public keys,
etc). This information is provided from a few sources...

* The control port via 'GETINFO desc/\*' queries.

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

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

* Directory authorities and mirrors via their DirPort.

**Module Overview:**

::

  ServerDescriptor - Tor server descriptor.
    |- RelayDescriptor - Server descriptor for a relay.
    |  +- make_router_status_entry - Creates a router status entry for this descriptor.
    |
    |- BridgeDescriptor - Scrubbed server descriptor for a bridge.
    |  |- is_scrubbed - checks if our content has been properly scrubbed
    |  +- get_scrubbing_issues - description of issues with our scrubbing
    |
    |- digest - calculates the upper-case hex digest value for our content
    |- get_annotations - dictionary of content prior to the descriptor entry
    +- get_annotation_lines - lines that provided the annotations

.. data:: BridgeDistribution (enum)

  Preferred method of distributing this relay if a bridge.

  .. versionadded:: 1.6.0

  ===================== ===========
  BridgeDistribution    Description
  ===================== ===========
  **ANY**               No proference, BridgeDB will pick how the bridge is distributed.
  **HTTPS**             Provided via the `web interface <https://bridges.torproject.org>`_.
  **EMAIL**             Provided in response to emails to bridges@torproject.org.
  **MOAT**              Provided in interactive menus within Tor Browser.
  **HYPHAE**            Provided via a cryptographic invitation-based system.
  ===================== ===========
    N)RouterStatusEntryV3)PGP_BLOCK_END
Descriptor
DigestHashDigestEncodingcreate_signing_key_descriptor_content_descriptor_components_read_until_keywords_bytes_for_block_value_values_parse_simple_line_parse_int_line_parse_if_present_parse_bytes_line_parse_timestamp_line_parse_forty_character_hex_parse_protocol_line_parse_key_block_append_router_signature_random_nickname_random_ipv4_address_random_date_random_crypto_blob)	lru_cache)router	bandwidth	published	onion-keysigning-keyrouter-signature)identity-ed25519master-key-ed25519platformfingerprinthibernatinguptimecontactread-historywrite-historyeventdnsbridge-distribution-requestfamilycaches-extra-infoextra-info-digesthidden-service-dir	protocolsallow-single-hop-exitstunnelled-dir-serverprotoonion-key-crosscertntor-onion-keyntor-onion-key-crosscertrouter-sig-ed25519)ANYany)HTTPShttps)EMAILemail)MOATmoat)HYPHAEhyphaezreject 1-65535
reject *:*r;   c                     [         R                  R                  R                  [        R
                  " U 5      R                  S5      5      $ )N   =)stemutil	str_tools_to_unicodebase64	b64encoderstripcontents    [/home/james-whalen/.local/lib/python3.13/site-packages/stem/descriptor/server_descriptor.py_truncated_b64encoderQ      s3    				(	()9)9')B)I)I$)O	PP    c              +     #     [        SU 5      n[        [        R                  U5      n[        [        R
                  R                  R                  U5      n[        [        S U5      5      nU(       d6  [        SU 5      n[        R                  " SS5      S   nU[        X`S5      -  nO[        SU S5      nU(       a[  US   R                  S	5      (       a  USS
 n[        R                  SU5      nU(       a  [        XrU40 UD6v   O<[        XrU40 UD6v   O,U(       a$  U(       a  [!        SSR                  U5      -  5      eg
GME  7f)a"  
Iterates over the server descriptors in a file.

:param file descriptor_file: file with descriptor content
:param bool is_bridge: parses the file as being a bridge descriptor
:param bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:param dict kwargs: additional arguments for the descriptor constructor

:returns: iterator for ServerDescriptor instances in the file

:raises:
  * **ValueError** if the contents is malformed and validate is True
  * **IOError** if the file can't be read
Tr   c                     U S:g  $ )N  )xs    rP   <lambda>_parse_file.<locals>.<lambda>   s    RrR   r"       r   router-digests   @typeNrR   z0Content conform to being a server descriptor:
%s
)r   mapbytesstriprG   rH   rI   rJ   listfilterr   split
startswithjoinBridgeDescriptorRelayDescriptor
ValueError)descriptor_file	is_bridgevalidatekwargsannotationsdescriptor_contentblock_end_prefixdescriptor_texts           rP   _parse_filerq      s+    V 	&xAKekk;/Kdii))55{CKv/=>K/0BOT ',,S!4Q701ATXYY/RVW	A		)	)(	3	3/3

3(:;o	+PPPoOOO	kLtyyYdOeeff= 	s   EE	c                    [        SU5      nUR                  5       n[        U5      S:  a  [        SU-  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   S	S
9(       d  [        SUS   -  5      e[        R
                  R                  R                  US   S	S
9(       d  [        SUS   -  5      e[        R
                  R                  R                  US   S	S
9(       d  [        SUS   -  5      eUS   U l        US   U l        [        US   5      U l        US   S:X  a  S O[        US   5      U l        US   S:X  a  S U l        g [        US   5      U l        g )Nr      z,Router line must have five values: router %sr   z,Router line entry isn't a valid nickname: %sr[   z0Router line entry isn't a valid IPv4 address: %s   T)
allow_zeroz#Router line's ORPort is invalid: %s   z&Router line's SocksPort is invalid: %s   z$Router line's DirPort is invalid: %s0)r   rc   lenrh   rG   rH   	tor_toolsis_valid_nickname
connectionis_valid_ipv4_addressis_valid_portnicknameaddressintor_port
socks_portdir_port)
descriptorentriesvaluerouter_comps       rP   _parse_router_liner      s    7
#%+
CeK
LL9900Q@@
CkRSnT
UU9955k!nEE
G+VW.X
YY99--k!n4-P
:[^K
LL99--k!n4-P
=AN
OO99--k!n4-P
;k!nL
MM#A*"1~*;q>**"-a.C"7$SQ=P* +A# 5*3{1~;N*rR   c                    [        SU5      nUR                  5       n[        U5      S:  a  [        SU-  5      eUS   R	                  5       (       d  [        SUS   -  5      eUS   R	                  5       (       d  [        SUS   -  5      eUS   R	                  5       (       d  [        S	US   -  5      e[        US   5      U l        [        US   5      U l        [        US   5      U l        g )
Nr   rv   z3Bandwidth line must have three values: bandwidth %sr   z/Bandwidth line's average rate isn't numeric: %sr[   z-Bandwidth line's burst rate isn't numeric: %srt   z0Bandwidth line's observed rate isn't numeric: %s)	r   rc   ry   rh   isdigitr   average_bandwidthburst_bandwidthobserved_bandwidth)r   r   r   bandwidth_comps       rP   _parse_bandwidth_liner      s     g
&%;;=.1
JUR
SS!$$&&
FXYIZZ
[[!$$&&
D~VWGXX
YY!$$&&
G.YZJ[[
\\!$^A%6!7*">!#45*"%nQ&7"8*rR   c                    [        SS5      " X5        [        SU5      n[        R                  " SU5      nU(       a=  UR	                  5       u  o@l         [        R                  R                  U5      U l	        g g ! [         a     g f = f)Nr%   z^(?:node-)?Tor (\S*).* on (.*)$)r   r   rematchgroupsoperating_systemrG   version_get_versiontor_versionrh   )r   r   r   platform_matchversion_strs        rP   _parse_platform_liner     s~     J
+J@ W
%%88>F./=/D/D/F,K,#||88Ej	 
  
s   $A; ;
BBc                 .   [        SU5      nUR                  SS5      nUR                  S5       H   n[        U5      S:w  d  M  [	        SU-  5      e   [
        R                  R                  R                  U5      (       d  [	        SU-  5      eX0l	        g )Nr&   rZ   rU   rw   z=Fingerprint line should have groupings of four hex digits: %sz6Tor relay fingerprints consist of forty hex digits: %s)
r   replacerc   ry   rh   rG   rH   rz   is_valid_fingerprintr&   )r   r   r   r&   groupings        rP   _parse_fingerprint_liner   .  s     
(%c2&+++c"h
8}VY^^__ # 
			1	1+	>	>
MPUU
VV&rR   c                    [        SU5      nUR                  S5      n[        R                  R                  R                  US   S5      (       d  [        SUS   -  5      eUS   U l        [        U5      S:  a  US   U l	        g S U l	        g )Nr0   rZ   r   (   z1extra-info-digest should be 40 hex characters: %srt   r[   )
r   rc   rG   rH   rz   is_hex_digitsrh   extra_info_digestry   extra_info_sha256_digest)r   r   r   digest_comps       rP   _parse_extrainfo_digest_liner   ?  s    
$g
.%C +				*	*;q>2	>	>
H;WX>Y
ZZ!,Q*:=k:Ja:OA*%UY*%rR   c                 X    [        SU5      nUS;  a  [        SU-  5      eUS:H  U l        g )Nr'   )rx   1z>Hibernating line had an invalid value, must be zero or one: %sr   )r   rh   r'   )r   r   r   s      rP   _parse_hibernating_liner   J  s6     
(%
*
UX]]
^^ C<*rR   c                     [        SU5      n[        R                  " SU5      nU(       d  [        SU-  5      eUR	                  5       u  pEUR                  S5      U l        UR                  S5      U l        g )Nr2   z^Link (.*) Circuit (.*)$z?Protocols line did not match the expected pattern: protocols %srZ   )r   r   r   rh   r   rc   link_protocolscircuit_protocols)r   r   r   protocols_matchlink_versionscircuit_versionss         rP   _parse_protocols_liner   U  sk    
g
&%HH7?/	
VY^^
__$3$:$:$<!-+11#6*!1!7!7!<*rR   c           
         [        SU5      n/ nU GH7  nSU-  nSU;  a  [        SU-  5      eUR                  SS5      u  pg[        R                  R
                  R                  U5      (       d;  [        R                  R
                  R                  USS9(       d  [        SU-  5      e[        R                  R
                  R                  U5      (       d  [        S	U-  5      eUR                  UR                  S
5      R                  S5      [        U5      [        R                  R
                  R                  USS945        GM:     X0l        g )N
or-addresszor-address %s:z#or-address line missing a colon: %sr[   T)allow_bracketsz+or-address line has a malformed address: %sz(or-address line has a malformed port: %s[])r   rh   rsplitrG   rH   r|   r}   is_valid_ipv6_addressr~   appendlstriprM   r   or_addresses)r   r   
all_valuesr   entryliner   ports           rP   _parse_or_address_liner   a  s/   |W-*,eU"D
%<tCDDLLa(MG9955g>>tyyG[G[GqGqry  MQGq  HRDtKLL99--d33ADHII,33C8#d)TYYEYEYEoEopw  KOEo  FP  Q  R   )rR   c                 x   [        X5      n[        R                  R                  R	                  X5      u  pxn	 U	(       a+  U	R                  S5       V
s/ s H  n
[        U
5      PM     nn
O/ n [        XAU5        [        XBU5        [        XCU5        g s  sn
f ! [         a    [        U < SU < SU< 35      ef = f)N,z line has non-numeric values: rZ   )	r   rG   r   extrainfo_descriptor_parse_timestamp_and_intervalrc   r   rh   setattr)keywordhistory_end_attributehistory_interval_attributehistory_values_attributer   r   r   	timestampinterval	remainderr   history_valuess               rP   _parse_history_liner   x  s    

"%#'??#G#G#e#efm#u )yZ090DE0DuE
0DnEnn 
*Y7	*(;	*? F 
 Z
RWX
YYZs#   B B(B +B B !B9c                 2   [        U S5      (       a  U R                  (       aF  [        R                  R                  R                  U R                  S   5      S:X  a  [        U l        O,[        R                  R                  " U R                  6 U l        U ?g g )N_unparsed_exit_policyr   rD   )	hasattrr   rG   rH   rI   rJ   REJECT_ALL_POLICYexit_policy
ExitPolicyr   r   s     rP   _parse_exit_policyr     s{    Z011''DII,?,?,K,KJLlLlmnLo,p  uA  -A0j#//::J<\<\]j( 2rR   c                     [        SSS5      " X5        U R                  (       aC  [        R                  R                  R
                  R                  U R                  5      U l        g g )Nr#   ed25519_certificateED25519 CERT)r   r   rG   r   certificateEd25519Certificatefrom_base64r   s     rP   _parse_identity_ed25519_liner     sO     %'<nMjb##!__88KKWWXbXvXvwJ $rR   r$   ed25519_master_keyed25519_certificate_hashr)   r   r*   read_history_endread_history_intervalread_history_valuesr+   write_history_endwrite_history_intervalwrite_history_valuesipv6-policyexit_policy_v6c                 @    [         R                  R                  U 5      $ N)rG   r   MicroExitPolicyvs    rP   rX   rX     s    _c_o_o__  AB  `CrR   )funcr3   allow_single_hop_exitsr4   allow_tunneled_dir_requestsr5   r2   r1   is_hidden_service_dirr/   extra_info_cacher-   bridge_distributionr.   c                 6    [        U R                  S5      5      $ )NrZ   )setrc   r   s    rP   rX   rX     s    SQRQXQXY\Q]M^rR   r,   c                     U S:H  $ )Nr   rV   r   s    rP   rX   rX     s    STX[S[rR   r    	onion_keyRSA PUBLIC KEYr6   onion_key_crosscert	CROSSCERTr!   signing_keyr"   	signature	SIGNATUREr7   ntor_onion_keyr8   ntor_onion_key_crosscertr   ntor_onion_key_crosscert_signr9   ed25519_signaturerouter-digest-sha256router_digest_sha256r\   _digestr(   T)allow_negativec                     ^  \ rS rSrSr0 SS\4_SS\4_SS\4_SS\4_SS\	4_S	S\4_S
S\4_SS\4_SS\4_SS\
4_SS\
4_SS\
4_SS\4_S\\4_S\\4_S\" 5       \4_SS\4_0 SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_S0 \4_SS\4_S S\4_S!S\4_S"S\4_S#S\4_S$/ \4_S%S\4_S&S\4_ES\4S\4S\4S\4S'.Er 0 S(\_S)\_S\
_S\_S\_S\_S\_S*\_S+\_S\_S\_S,\_S-\_S.\_S/\_S0\_S1\_\\\\\\S2.Er!S=U 4S3 jjr"\#RH                  \%RL                  4S4 jr'\(" 5       S5 5       r)S6 r*S7 r+S8 r,S9 r-S: r.S; r/S<r0U =r1$ )>ServerDescriptori  a-  
Common parent for server descriptors.

:var str nickname: **\*** relay's nickname
:var str fingerprint: identity key fingerprint
:var datetime published: **\*** time in UTC when this descriptor was made

:var str address: **\*** IPv4 address of the relay
:var int or_port: **\*** port used for relaying
:var int socks_port: **\*** port used as client (**deprecated**, always **None**)
:var int dir_port: **\*** port used for descriptor mirroring

:var bytes platform: line with operating system and tor version
:var stem.version.Version tor_version: version of tor
:var str operating_system: operating system
:var int uptime: uptime when published in seconds
:var bytes contact: contact information
:var stem.exit_policy.ExitPolicy exit_policy: **\*** stated exit policy
:var stem.exit_policy.MicroExitPolicy exit_policy_v6: **\*** exit policy for IPv6
:var BridgeDistribution bridge_distribution: **\*** preferred method of providing this relay's
  address if a bridge
:var set family: **\*** nicknames or fingerprints of declared family

:var int average_bandwidth: **\*** average rate it's willing to relay in bytes/s
:var int burst_bandwidth: **\*** burst rate it's willing to relay in bytes/s
:var int observed_bandwidth: **\*** estimated capacity based on usage in bytes/s

:var list link_protocols: link protocols supported by the relay
:var list circuit_protocols: circuit protocols supported by the relay
:var bool is_hidden_service_dir: **\*** indicates if the relay serves hidden
  service descriptors
:var bool hibernating: **\*** hibernating when published
:var bool allow_single_hop_exits: **\*** flag if single hop exiting is allowed
:var bool allow_tunneled_dir_requests: **\*** flag if tunneled directory
  requests are accepted
:var bool extra_info_cache: **\*** flag if a mirror for extra-info documents
:var str extra_info_digest: upper-case hex encoded digest of our extra-info document
:var str extra_info_sha256_digest: base64 encoded sha256 digest of our extra-info document
:var bool eventdns: flag for evdns backend (**deprecated**, always unset)
:var str ntor_onion_key: base64 key used to encrypt EXTEND in the ntor protocol
:var list or_addresses: **\*** alternative for our address/or_port
  attributes, each entry is a tuple of the form (address (**str**), port
  (**int**), is_ipv6 (**bool**))
:var dict protocols: mapping of protocols to their supported versions

**Deprecated**, moved to extra-info descriptor...

:var datetime read_history_end: end of the sampling interval
:var int read_history_interval: seconds per interval
:var list read_history_values: bytes read during each interval

:var datetime write_history_end: end of the sampling interval
:var int write_history_interval: seconds per interval
:var list write_history_values: bytes written during each interval

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

.. versionchanged:: 1.5.0
   Added the allow_tunneled_dir_requests attribute.

.. versionchanged:: 1.6.0
   Added the extra_info_sha256_digest, protocols, and bridge_distribution
   attributes.

.. versionchanged:: 1.7.0
   Added the is_hidden_service_dir attribute.

.. versionchanged:: 1.7.0
   Deprecated the hidden_service_dir field, it's never been populated
   (:spec:`43c2f78`). This field will be removed in Stem 2.0.
r   Nr&   r)   r   r   r   r   r   r   r%   r   r   r(   r   r   r.   r   r   r   r   r   r   Fr'   r   r   r2   r   r   r   r,   r   r   r   r   )r   r   r   r   r   r   r0   r1   r7   r   r*   r+   r   r3   )r4   r5   r/   r-   r.   r,   c                 `  > [         [        U ]  X(       + S9  U(       a  UO/ U l        [	        [
        R                  R                  R                  U5      USSS9u  o@l	        S/U l
        U(       a  U R                  XB5        [        X5        U(       a  U R                  (       ar  U R                  (       aa  U R                  S:  aQ  U R                  [
        R                  R!                  S5      :  a$  [#        SU R                  U R                  4-  5      eU R%                  U5        g	X@l        g	)
a  
Server descriptor constructor, created from an individual relay's
descriptor content (as provided by 'GETINFO desc/*', cached descriptors,
and metrics).

By default this validates the descriptor's content as it's parsed. This
validation can be disables to either improve performance or be accepting of
malformed data.

:param str raw_contents: descriptor content provided by the relay
:param bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:param list annotations: lines that appeared prior to the descriptor

:raises: **ValueError** if the contents is malformed and validate is True
)	lazy_load)acceptreject)r)   r%   )extra_keywordsnon_ascii_fields2r   z0.1.2.7z;Descriptor for version '%s' had a negative uptime value: %iN)superr  __init___annotation_linesr
   rG   rH   rI   rJ   r   hidden_service_dir_parser   r(   r   r   Versionrh   _check_constraints_entries)selfraw_contentsrk   rm   r   	__class__s        rP   r  ServerDescriptor.__init__V  s    $ 

D*<\*R,7[RD +AATATA`A`amAnpx  L`  uL  +M'G'  #eD
kk'$'
 
dkkd&6&6;;?t//4<<3G3G	3RRX\`\l\lnrnyny[zz{
{
g&mrR   c                     [        S5      e)a  
Digest of this descriptor's content. These are referenced by...

  * **Consensus**

    * Referer: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` **digest** attribute
    * Format: **SHA1/BASE64**

.. versionchanged:: 1.8.0
   Added the hash_type and encoding arguments.

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

:returns: **hashlib.HASH** or **str** based on our encoding argument
zRUnsupported Operation: this should be implemented by the ServerDescriptor subclass)NotImplementedErrorr  	hash_typeencodings      rP   digestServerDescriptor.digest  s    $ r
ssrR   c                 x    0 nU R                    H'  nSU;   a  UR                  SS5      u  p4XAU'   M#  SX'   M)     U$ )a$  
Provides content that appeared prior to the descriptor. If this comes from
the cached-descriptors file then this commonly contains content like...

::

  @downloaded-at 2012-03-18 21:18:29
  @source "173.254.216.66"

.. deprecated:: 1.8.0
   Users very rarely read from cached descriptor files any longer. This
   method will be removed in Stem 2.x. If you have some need for us to keep
   this please `let me know
   <https://trac.torproject.org/projects/tor/wiki/doc/stem/bugs>`_.

:returns: **dict** with the key/value pairs in our annotations
rZ   r[   N)r  rc   )r  annotation_dictr   keyr   s        rP   get_annotations ServerDescriptor.get_annotations  sJ    ( O&&	ZZQ'
$ $ ' rR   c                     U R                   $ )aC  
Provides the lines of content that appeared prior to the descriptor. This
is the same as the
:func:`~stem.descriptor.server_descriptor.ServerDescriptor.get_annotations`
results, but with the unparsed lines and ordering retained.

.. deprecated:: 1.8.0
   Users very rarely read from cached descriptor files any longer. This
   method will be removed in Stem 2.x. If you have some need for us to keep
   this please `let me know
   <https://trac.torproject.org/projects/tor/wiki/doc/stem/bugs>`_.

:returns: **list** with the lines of annotation that came before this descriptor
)r  r  s    rP   get_annotation_lines%ServerDescriptor.get_annotation_lines  s      !!!rR   c                    U R                  5        H  nX!;  d  M
  [        SU-  5      e   U R                  5        H)  nX!;   d  M
  [        X   5      S:  d  M  [        SU-  5      e   U R	                  5       nU(       a.  U[        UR                  5       5      S   :w  a  [        SU-  5      eU R                  5       nU(       a.  U[        UR                  5       5      S   :w  a  [        SU-  5      eSUR                  5       ;   aJ  S	UR                  5       ;  a  [        S
5      eS	[        UR                  5       5      SS ;  a  [        S5      eU R                  (       d  [        S5      eg)z
Does a basic check that the entries conform to this descriptor type's
constraints.

:param dict entries: keyword => (value, pgp key) entries

:raises: **ValueError** if an issue arises in validation
z!Descriptor must have a '%s' entryr[   z3The '%s' entry can only appear once in a descriptorr   z'Descriptor must start with a '%s' entryz%Descriptor must end with a '%s' entryr#   r9   zKDescriptor must have router-sig-ed25519 entry to accompany identity-ed25519NzCDescriptor must have 'router-sig-ed25519' as the next-to-last entryz<Descriptor must have at least one 'accept' or 'reject' entry)	_required_fieldsrh   _single_fieldsry   _first_keywordra   keys_last_keywordr   )r  r   r   expected_first_keywordexpected_last_keywords        rP   r  #ServerDescriptor._check_constraints  sM    ((*		<wFGG + &&(		G$4 5 9NQXXYY ) "002"8D<PQR<S"S@CYYZZ ..0!6$w||~:Nr:R!R>AVVWWW\\^+	W\\^	3fggtGLLN';BC'@@^__UVV rR   c                     [         $ r   )REQUIRED_FIELDSr(  s    rP   r.  !ServerDescriptor._required_fields  s    rR   c                     [         [        -   $ r   )r7  SINGLE_FIELDSr(  s    rP   r/  ServerDescriptor._single_fields  s    ]**rR   c                     g)Nr   rV   r(  s    rP   r0  ServerDescriptor._first_keyword  s    rR   c                     g)Nr"   rV   r(  s    rP   r2  ServerDescriptor._last_keyword  s    rR   )r  r  r   r  )FN)2__name__
__module____qualname____firstlineno____doc__r   r   _parse_contact_line_parse_published_liner   r   _parse_uptime_lineDEFAULT_IPV6_EXIT_POLICY_parse_ipv6_policy_lineDEFAULT_BRIDGE_DISTRIBUTION'_parse_bridge_distribution_request_liner   _parse_family_liner   r   _parse_hidden_service_dir_liner   "_parse_allow_single_hop_exits_line_parse_tunneled_dir_server_line_parse_proto_line_parse_caches_extra_info_liner   _parse_eventdns_line_parse_ntor_onion_key_liner   _parse_read_history_line_parse_write_history_line
ATTRIBUTESPARSER_FOR_LINEr  r   SHA1r   HEXr   r   r%  r)  r  r.  r/  r0  r2  __static_attributes____classcell__r  s   @rP   r  r    s   GR-)*-D12- )*- $-.	-
 D,-- ()- ()- 4+,- )*- +,- D./- 34- t'(-  /1HI!-" 79`a#-$ su()%-( $ 56)-* 34+-, 4!67--0 t231-2 $ 563-4 e%CD5-6 E237-8 u&HI9-: "E+J#K;-< "'(=->  =>?-@ $ <=A-B 'C DC-D +,E-F t78G-H R/0I-L 78M-N d$<=O-P !":; 9:#%>?!#<=Y-*^ & $ &	
 * " * 5 8   & 0 ( , .  *!" @#$ <6#J $//43j  *>;M;M t( ; <"$!WL+ rR   r  c                   n  ^  \ rS rSrSrSr\" \R                  40 S\	4S\	4S\
4S\4S\4S\4S\4S\4S\4S\4S.
D6r\" \R"                  40 \	\
\\\\\\S.D6rSU 4S jjr\SS	 j5       r\SS
 j5       r\" 5       \R0                  \R4                  4S j5       rS r\" 5       S 5       rU 4S jrSrU =r $ )rg   i  at  
Server descriptor (`descriptor specification
<https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_)

:var stem.certificate.Ed25519Certificate certificate: ed25519 certificate
:var str ed25519_certificate: base64 encoded ed25519 certificate
:var str ed25519_master_key: base64 encoded master key for our ed25519 certificate
:var str ed25519_signature: signature of this document using ed25519

:var str onion_key: **\*** key used to encrypt EXTEND cells
:var str onion_key_crosscert: signature generated using the onion_key
:var str ntor_onion_key_crosscert: signature generated using the ntor-onion-key
:var str ntor_onion_key_crosscert_sign: sign of the corresponding ed25519 public key
:var str signing_key: **\*** relay's long-term identity key
:var str signature: **\*** signature for this descriptor

**\*** attribute is required when we're parsed with validation

.. versionchanged:: 1.5.0
   Added the ed25519_certificate, ed25519_master_key, ed25519_signature,
   onion_key_crosscert, ntor_onion_key_crosscert, and
   ntor_onion_key_crosscert_sign attributes.

.. versionchanged:: 1.6.0
   Moved from the deprecated `pycrypto
   <https://www.dlitz.net/software/pycrypto/>`_ module to `cryptography
   <https://pypi.org/project/cryptography/>`_ for validating signatures.

.. versionchanged:: 1.6.0
   Added the certificate attribute.

.. deprecated:: 1.6.0
   Our **ed25519_certificate** is deprecated in favor of our new
   **certificate** attribute. The base64 encoded certificate is available via
   the certificate's **encoded** attribute.

.. versionchanged:: 1.6.0
   Added the **skip_crypto_validation** constructor argument.
zserver-descriptorN)
r   r   r   r  r   r   r   r   r   r   )r#   r$   r9   r    r6   r8   r!   r"   c                 ,  > [         [        U ]  XU5        U(       Ga  U R                  (       a  [        R
                  " [        U R                  5      5      R                  5       nXPR                  R                  5       :w  a,  [        SU R                  R                  5       < SU< S35      eU(       Gd  [        R                  R                  5       (       a  U R                  U R                  U R                  5      nX`R!                  5       :w  a"  [        SU< SU R!                  5       < S35      eU R"                  (       a~  [        R                  R                  5       (       a[  U R                  U R$                  U R"                  5      nXpR'                  5       :w  a"  [        SU< SU R'                  5       < S35      e[        R                  R                  SS9(       a.  U R(                  (       a  U R(                  R+                  U 5        g g g g )	NzEFingerprint does not match the hash of our signing key (fingerprint: z, signing key hash: )z:Decrypted digest does not match local digest (calculated: z	, local: zNDecrypted onion-key-crosscert digest does not match local digest (calculated: T)ed25519)r  rg   r  r&   hashlibsha1r   r   	hexdigestlowerrh   rG   prereqis_crypto_available_digest_for_signaturer   r   r   r   _onion_key_crosscert_digestr   rk   )	r  r  rk   rm   skip_crypto_validationkey_hashsigned_digestonion_key_crosscert_digestr  s	           rP   r  RelayDescriptor.__init__G  s   	/4),+N			<< 01A1A BCMMO''--//  @D  @P  @P  @V  @V  @X  Zb  c  d  d#(G(G(I(I2243C3CT^^TKKM)ivx|  yD  yD  yF  G  H  H##(G(G(I(I'+'A'A$..RVRjRj'k
$'+K+K+MM  @Z  \`  \|  \|  \~    @  @		(	(4	(	8T=M=M!!$' >N	8' rR   rV   c           
         U(       a  SnUc  0 nUc  [         nS[        5       < S[        5       < S34S[        5       4S/[	        U5      R                  5        Vs/ s H  n[        UR                  SS5      5      PM      sn-   S[        S	5      4S
[        S	5      4/-   nU(       Ga,  U(       a  S
U;   a  [        S5      eU(       a  SU;   a  [        S5      eUc
  [        5       nSU;  a  [        R                  " [        [        R                  R                   R#                  UR$                  R'                  5       5      5      5      R)                  5       R+                  5       nSR-                  [        R                  R                   R/                  US5      5      US'   UR$                  US
'   [1        XU5      S-   n	[3        XR4                  5      $ [1        XUSS[        S5      445      $ s  snf )NTr   rZ   	 9001 0 0r   )r   z153600 256000 104590r[   r    r   r!   z=Cannot sign the descriptor if a signing-key has been providedr"   zBCannot sign the descriptor if a router-signature has been providedr&   rw   s   
router-signature
)r9   Nr   )r   r   r   r   str
splitlinestuplerc   r   rh   r   ra  rb  r   rG   rH   rI   rJ   public_digestr`   rc  upperre   _split_by_lengthr	   r   private)
clsattrexcludesignr   r   r   base_headerr&   rO   s
             rP   rO   RelayDescriptor.content`  s   d|d%k %5%79M9OPQLN#+
 -0,<,G,G,I	,IDeDJJsA,I		 '(89:)*:;<		K 	-4'XYY&$.]^^		(*	d	"ll#3DII4G4G4S4ST_TmTmTsTsTu4v#wx  C  C  E  K  K  M!hhtyy':':'K'KKYZ'[\]'55d=#D;?BYYg%g/B/BCC $	0=>> 	 	3	s   %G.c           	      <    U " U R                  XXEU5      X4(       + S9$ )N)rk   ri  rN   )rw  rx  ry  rk   rz  r   r   s          rP   createRelayDescriptor.create  s*    s{{4$[IV^  zB  C  CrR   c                 ^   U R                  SSS9nU[        R                  :X  a4  [        R                  R                  [        R                  " U5      U5      $ U[        R                  :X  a4  [        R                  R                  [        R                  " U5      U5      $ [        SU-  5      e)z
Provides the digest of our descriptor's content.

:returns: the digest string encoded in uppercase hex

:raises: ValueError if the digest cannot be calculated
r   z
router-signature
)startendzGServer descriptor digests are only available in sha1 and sha256, not %s)_content_ranger   rX  rG   r   _encode_digestra  rb  SHA256sha256r  )r  r  r  rO   s       rP   r   RelayDescriptor.digest  s     !!(:P!QGJOO#__++GLL,A8LL	j''	'__++GNN7,CXNN ilu uvvrR   c                 P   U R                   (       d  [        S5      eSR                  U R                  [	        [
        R                  " [        R                  R                  R                  U R                   5      5      5      [	        [
        R                  " [        R                  R                  R                  U R                  5       5      5      5      U R                  R                  S5      U R                  [        U R                   5      U R"                  (       a  [        U R"                  5      OS/5      SU R$                  -  U R&                  R)                  5       R+                  SS5      S.nU R,                  (       a  S	U R,                  -  US
'   U R.                  (       a-  U R.                   VVVs/ s H  u  p#oB< SU< 3PM     snnnUS'   U R0                  (       a%  S[	        U R0                  R2                  5      -  US'   [4        R6                  " U5      $ s  snnnf )z
Provides a RouterStatusEntryV3 for this descriptor content.

.. versionadded:: 1.6.0

:returns: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`
  that would be in the consensus
zmServer descriptor lacks a fingerprint. This is an optional field, but required to make a router status entry.rZ   z%Y-%m-%d %H:%M:%Srx   zBandwidth=%iz, r   )rwpzTor %sr   r   az
ed25519 %sid)r&   rh   re   r   rQ   binascii	unhexlifyrG   rH   rI   	_to_bytesr   r   strftimer   rp  r   r   r   r   summaryr   r   r   r   r$  r   r~  )r  rx  addrr   _s        rP   make_router_status_entry(RelayDescriptor.make_router_status_entry  s      G  H  H 88X//		0C0C0M0MdN^N^0_`aX//		0C0C0M0Mdkkm0\]^ 34DLL"mmDMM 	 D222##%--dC8D T---d3i?C?P?PQ?Pmd!dD)?PQd3i"6t7G7G7K7K"LLd4j%%d++ Rs   8H!c                    [         R                  " [        U R                  5      5      R	                  5       nU[
        R                  " [        R                  R                  R                  U R                  5      S-   5      -   n[        R                  R                  R                  [        R                  " U5      R                  5       5      $ )z
Provides the digest of the onion-key-crosscert data. This consists of the
RSA identity key sha1 and ed25519 identity key.

:returns: **unicode** digest encoded in uppercase hex

:raises: ValueError if the digest cannot be calculated
rF   )ra  rb  r   r   r   rK   	b64decoderG   rH   rI   r  r   rJ   r  hexlifyrt  )r  signing_key_digestdatas      rP   rh  +RelayDescriptor._onion_key_crosscert_digest  s     !&6t7G7G&HIPPR 0 01D1D1N1NtOfOf1gjn1n ooD99**8+;+;D+A+G+G+IJJrR   c                    > [         [        U ]  U5        U R                  (       a9  U R                  (       d  [        S5      eU R                  (       d  [        S5      eg g )NzMDescriptor must have a 'onion-key-crosscert' when identity-ed25519 is presentzLDescriptor must have a 'router-sig-ed25519' when identity-ed25519 is present)r  rg   r  r   r   rh   r  )r  r   r  s     rP   r  "RelayDescriptor._check_constraints  sO    	/43G<%%hii%%ghh &  rR   )FNF)NrV   FNN)NrV   TFNN)!r@  rA  rB  rC  rD  TYPE_ANNOTATION_NAMEdictr  rV  r   _parse_master_key_ed25519_line_parse_router_sig_ed25519_line_parse_onion_key_line_parse_onion_key_crosscert_line$_parse_ntor_onion_key_crosscert_line_parse_signing_key_line_parse_router_signature_linerW  r  classmethodrO   r~  r   r   rX  r   rY  r   r  rh  r  rZ  r[  r\  s   @rP   rg   rg     s@   &P -$// 67 ">?!?@ >?-. "AB!%'K L&*,P%Q12454 * )99 	488&: D*4	> 	/(2 *	 *	X C C ;)>;M;M w w$$,L ;K Ki irR   rg   c                       \ rS rSrSrSr\" \R                  40 S\	4S\
4S\4S.D6r\" \R                  40 \	\
\S.D6r\SS j5       r\R                   \R$                  4S	 jrS
 r\" 5       S 5       rS rS rS rSrg)rf   i  a  
Bridge descriptor (`bridge descriptor specification
<https://metrics.torproject.org/collector.html#bridge-descriptors>`_)

:var str ed25519_certificate_hash: sha256 hash of the original identity-ed25519
:var str router_digest_sha256: sha256 digest of this document

.. versionchanged:: 1.5.0
   Added the ed25519_certificate_hash and router_digest_sha256 attributes.
   Also added ntor_onion_key (previously this only belonged to unsanitized
   descriptors).
zbridge-server-descriptorN)r   r  r  )r$   r  r\   rV   c           	          U(       a  [        SU R                  -  5      e[        XS[        5       < S[	        5       < S34SS[        5       4SS45      $ )	NzSigning of %s not implementedr   rZ   ro  )r\   (006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4r   )r   z409600 819200 5120)r  z*:*)r  r@  r	   r   r   r   )rw  rx  ry  rz  s       rP   rO   BridgeDescriptor.content  sV     ?#,, NOOt%5%79M9OPQCLN#)/  rR   c                     U[         R                  :X  a   U[        R                  :X  a  U R                  $ [        SU< SU< 35      e)NzEBridge server descriptor digests are only available as sha1/hex, not /)r   rX  r   rY  r  r  r  s      rP   r   BridgeDescriptor.digest  sD    JOO#N4F4F(F\\py  |D  !E  F  FrR   c                 (    U R                  5       / :H  $ )a$  
Checks if we've been properly scrubbed in accordance with the `bridge
descriptor specification
<https://metrics.torproject.org/collector.html#bridge-descriptors>`_.
Validation is a moving target so this may not be fully up to date.

:returns: **True** if we're scrubbed, **False** otherwise
)get_scrubbing_issuesr(  s    rP   is_scrubbedBridgeDescriptor.is_scrubbed  s     $$&",,rR   c                 6   / nU R                   R                  S5      (       d  UR                  SU R                   -  5        U R                  (       a.  U R                  S:w  a  UR                  SU R                  -  5        U R                   Hn  u  p#nU(       d,  UR                  S5      (       d  UR                  SU-  5        M9  U(       d  MB  UR                  S5      (       a  MZ  UR                  SU-  5        Mp     U R                  5        H  nUR                  S5      (       a  UR                  S	U-  5        M/  UR                  S
5      (       a  UR                  SU-  5        M[  UR                  S5      (       d  Ms  UR                  SU-  5        M     U$ )z
Provides issues with our scrubbing.

:returns: **list** of strings which describe issues we have with our
  scrubbing, this list is empty if we're properly scrubbed
z10.z=Router line's address should be scrubbed to be '10.x.x.x': %ssomebodyzFContact line should be scrubbed to be 'somebody', but instead had '%s'zAor-address line's address should be scrubbed to be '10.x.x.x': %szfd9f:2e19:3bcf::zPor-address line's address should be scrubbed to be 'fd9f:2e19:3bcf::xx:xxxx': %sz
onion-key z;Bridge descriptors should have their onion-key scrubbed: %szsigning-key z=Bridge descriptors should have their signing-key scrubbed: %szrouter-signature z;Bridge descriptors should have their signature scrubbed: %s)r   rd   r   r)   r   get_unrecognized_lines)r  issuesr   r  is_ipv6r   s         rP   r  %BridgeDescriptor.get_scrubbing_issues  sK    F<<""5))mmSVZVbVbbc||
2mm\_c_k_kkl#00GW//66Y\ccd77--.@AA 	hkrrs  1 ++-		&	&SVZZ[??>**UX\\]??.//SVZZ[ . MrR   c                 n    / SQnS/n[        U[         Vs/ s H  o3U;  d  M
  UPM     sn-   5      $ s  snf )N)r    r!   r"   r\   )rr  r7  )r  excluded_fieldsincluded_fieldsfs       rP   r.  !BridgeDescriptor._required_fieldsA  s>    O O #[!?BZA#[[\\#[s   	2
2
c                 0    U R                  5       [        -   $ r   )r.  r:  r(  s    rP   r/  BridgeDescriptor._single_fieldsQ  s      "]22rR   c                     g r   rV   r(  s    rP   r2  BridgeDescriptor._last_keywordT  s    rR   )NrV   F)r@  rA  rB  rC  rD  r  r  r  rV  '_parse_master_key_ed25519_for_hash_line _parse_router_digest_sha256_line_parse_router_digest_linerW  r  rO   r   rX  r   rY  r   r  r   r  r.  r/  r2  rZ  rV   rR   rP   rf   rf     s     4$// !%'N O!#CD/04 * )99 A<.> / 
 
  *>;M;M F
- ;   D] 3rR   rf   )FF)erD  rK   r  	functoolsra  r   stem.descriptor.certificaterG   $stem.descriptor.extrainfo_descriptorstem.exit_policystem.prereqstem.util.connectionstem.util.enumstem.util.str_toolsstem.util.tor_toolsstem.version#stem.descriptor.router_status_entryr   stem.descriptorr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   re  _is_lru_cache_availabler   stem.util.lru_cacher7  r:  rH   enumEnumBridgeDistributionr   r   rH  r   r   rJ  rQ   rq   r   r   r   r   r   r   r   r   r   r   r   r  r  rE  rF  partialrT  rU  rI  rN  rO  rP  rM  rQ  rK  rL  rR  r  r  r  r  rS  r  r  r  r  rG  r  rg   rf   rV   rR   rP   <module>r     s  ,\     	 " +        C      6 ;;&&((!+4 YY^^((   ++;;<LM $$//= # QIXO49(4'"Z(	=).@")x "44HJ^!_ *<=QSm*n ''	9= -k;G $,,-@.Rdf}  @U  V %--.A?Tg  jB  DZ  [ ,]<L  VC  D %67OQi%j ""34JLi"j (+> !23GI`!a  12EGY Z *<=Z\q*r ''(C^_ )*jI[\ (kCST "23HJ_al"m *=-IYZ /0BKQ\] /0@BRS '78RTnp~  A`  (a $!34HJ]!^ #56LNd#e  6	R  %Xx$O }z }@
]i& ]i@r' rrR   