+
    lHàjËo  ã            
       ó  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
Ht ^ RIHtHtHtHtHtHtHt ^ RIHt ^ RIHt ]P0                  ! ]4      tRVt]! RR04      t]P<                  ]P>                  ,          t R	 R
 lt!R R lt"]! 0 RWm4      t#R R lt$]! RR04      t%RXt&]! ]& U u0 uF  p ]PO                  V 4      kK  	  up ]& U u0 uF  p ]PO                  RV ,           4      kK  	  up ,          ]PN                  ! R4      0,          4      t(]);QJ d    . R RY 4       F  NK  	  5M! R RY 4       4      t*]! R04      t+^t,]PZ                  ! R4      t.]PZ                  ! R4      t/]);QJ d    . R RZ 4       F  NK  	  5M! R RZ 4       4      t0RRus1s2RR[us3s4R R lt5R R lt6R R lt7R R  lt8R! R" lt9R# R$ lt:R% R& lt;R' R( lt<R\R) R* llt=R+ R, lt>R- R. lt?R/ R0 lt@R1 R2 ltAR3 R4 ltBR5 R6 ltCR7 R8 ltDR9 R: ltER; R< ltF ! R= R>]G4      tHR? R@ ltI ! RA RB4      tJ ! RC RD]J4      tK ! RE RF]J4      tLRG RH ltM]RI RJ l4       tNRKR/RL RM lltORKR/RN RO lltPRP RQ ltQRR RS ltRRT RU ltSR# u up i u up i )]uW  URL safety checks â€” blocks requests to private/internal network addresses (SSRF).

``security.allow_private_urls: true`` disables private-IP blocking (DNS that resolves public
names to private ranges); cloud metadata hostnames/IPs are **always** blocked. A local TUN proxy
that answers DNS with a fake-ip block (Mihomo/Clash fake-ip, Surge enhanced) declares that block
in ``security.fake_ip_ranges`` so its sentinel answers are dialable instead of looking private;
the list is empty by default, so the sentinel stays blocked for everyone else. DNS rebinding
(TOCTOU) is closed for Hermes-owned httpx paths by ``create_ssrf_safe_[async_]client()``, which
re-apply the policy at TCP connect and dial the validated IP while preserving Host/SNI. Redirect
bypass is mitigated by response hooks re-validating each target (``redirect_target_from_response``).
N)Úcontextmanager)ÚAnyÚOptional)Ú	parse_qslÚquoteÚunquoteÚurljoinÚurlparseÚurlsplitÚ
urlunsplit)Úget_hermes_home_override)Úis_truthy_valueÚhttpÚhttpsc                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úbool)Úformats   "Ú5/home/ubuntu/.hermes/hermes-agent/tools/url_safety.pyÚ__annotate__r   "   s   € ÷ ;ñ ;œdñ ;ó    c                  óz   € \         ;QJ d     R  \         4       F  '       g   K   R# 	  R# ! R  \         4       4      # )c              3   ó`   "  € T F$  p\         P                  P                  V4      x € K&  	  R # 5i©N)ÚosÚenvironÚget)Ú.0Úvs   & r   Ú	<genexpr>Ú'_proxy_is_configured.<locals>.<genexpr>#   s    é € Ð:©/ QŒr�z‰z�~‰~˜a× Ð «/ùs   ‚,.TF)ÚanyÚ_PROXY_ENV_VARS© r   r   Ú_proxy_is_configuredr'   "   s+   € ß‹3Ñ:­/Ó:�3Œ3Ð:Š3Ð:ˆ3Ñ:­/Ó:Ó:Ð:r   c                ó0   € V ^8„  d   QhR\         R\         /# ©r   Úurlr   )Ústr)r   s   "r   r   r   &   s   € ÷ gñ g¤3ð g¬3ñ gr   c                óÆ  € \        V \        4      '       g   V # V P                  4       pV'       g   V# \        P                  ! RRV4      p \        V4      pTP                  P                  4       \        9  d   T# TP                  TP                  rCT'       d:    TP                  R4      P                  R4      pYT8w  d   TP                  YE^4      pRp\!        TP                  T\#        TP$                  TR7      \#        TP&                  TR,           R7      \#        TP(                  TR,           R7      34      #   \         d    Tu # i ; i  \         d    Tp L£i ; i)u  ASCII-safe HTTP URL for Hermes-owned URL tools (IRI -> URI, e.g. ``https://wttr.in/KÃ¶ln``).
Preserves URL syntax and existing percent escapes while IDNA-encoding the host and
percent-encoding non-ASCII path/query/fragment text. URL tool inputs only â€” never shell commands.z ^([A-Za-z][A-Za-z0-9+.-]*://)\s+z\1ÚidnaÚasciiz/%:@!$&'()*+,;=)ÚsafeÚ?)Ú
isinstancer+   ÚstripÚreÚsubr
   Ú
ValueErrorÚschemeÚlowerÚ_HTTP_SCHEMESÚnetlocÚhostnameÚencodeÚdecodeÚUnicodeErrorÚreplacer   r   ÚpathÚqueryÚfragment)r*   ÚrawÚparsedr9   r:   Ú
ascii_hostr/   s   &      r   Únormalize_url_for_requestrE   &   s0  € ô �cœ3×ÒØˆ
Ø
�)‰)‹+€CßØˆ
ô �&Š&Ð4°e¸SÓ
A€CðÜ˜#“ˆð ‡}�}×ÑÓ¤MÔ1Øˆ
Ø—}‘} f§o¡oˆHßð	"Ø!Ÿ™¨Ó0×7Ñ7¸Ó@ˆJð Ô!Ø—^‘^ H¸!Ó<ˆFØ€DÜ�v—}‘} f¬e°F·K±KÀdÔ.KÜ˜VŸ\™\°°sµ
Ô;¼UÀ6Ç?Á?ÐY]Ð`cÕYcÔ=dðfó gð gøô ô ØŠ
ðûô ô 	"Ø!ŠJð	"ús$   ÁD= Â E Ä=EÅEÅE ÅE c                óF   € V ^8„  d   QhR\         R\        \         ,          /# r)   )r+   r   )r   s   "r   r   r   P   s"   € ÷ [ñ [¤Cð [¬H´S­Mñ [r   c                óV  € \        V \        4      '       d   RV 9  d   R#  \        V P                  4       4      pTP
                  P                  4       \        9  g   TP                  '       g   R# \        R \        TP                  RR7       4       R4      #   \         d     R# i ; i)a  First credential-named query parameter in ``url`` (with a value), if any. Checked before
handing URLs to third-party fetch/browser backends: catches opaque magic links, OAuth codes,
signed-URL signatures and custom ``?token=...`` values that prefix-based redaction misses.r0   Nc              3   ó†   "  € T F7  w  rV'       g   K  \        V4      P                  4       \        9   g   K3  Vx € K9  	  R # 5ir   )r   r7   Ú_SENSITIVE_QUERY_PARAM_NAMES)r    ÚkeyÚvalues   &  r   r"   Ú-sensitive_query_param_name.<locals>.<genexpr>\   s:   é € ð TÑ'V™˜Üô Ü% c›l×0Ñ0Ó2Ô6RÑR÷ ’Ó'Vùs   ‚A“A·
AT)Úkeep_blank_values)r1   r+   r
   r2   r5   r6   r7   r8   r@   Únextr   )r*   rC   s   & r   Úsensitive_query_param_namerO   P   s‘   € ô �cœ3×Ò 3¨c¤>ÙðÜ˜#Ÿ)™)›+Ó&ˆð ‡}�}×ÑÓ¤MÔ1¸¿¿¸ÙÜñ T¤y°·±ÐQUÕ'Vó TØUYó[ð [øô	 ô Úðús   ¡B ÂB(Â'B(zmetadata.google.internalzmetadata.googz::ffff:zfd00:ec2::254c              #   óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5ir   ©Ú	ipaddressÚ
ip_network©r    Úns   & r   r"   r"   q   s    é € Ð oÑBn¸Q¤×!5Ò!5°a×!8Ð!8ÓBnùó   ‚#%zmultimedia.nt.qq.com.cnú100.64.0.0/10z::ffff:0:0:0/96c              #   óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5ir   rQ   rT   s   & r   r"   r"   …   s(   é € ð 'ñ IÀ1¤y×';Ò';¸A×'>Ð'>ó IùrV   Fc                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   �   s   € ÷ 
!ñ 
!¤Dñ 
!r   c                 ól   € \        4       e   \        4       # \        '       g   R\        4       uss\        # )u�  True when the user has opted out of private-IP blocking. Priority: ``HERMES_ALLOW_PRIVATE_URLS``
env, ``security.allow_private_urls``, legacy ``browser.allow_private_urls``. Profile-scoped turns
(``get_hermes_home_override()`` set) bypass the process-global cache â€” a multiplex gateway serves
several profiles in one process; the first profile's opt-out must not disable blocking for later ones.T)r   Ú_resolve_allow_private_urlsÚ_allow_private_resolvedÚ_cached_allow_privater&   r   r   Ú_global_allow_private_urlsr^   �   s4   € ô  Ó!Ò-Ü*Ó,Ð,ß"Ó"Ø9=Ô?ZÓ?\Ð6ÐÐ!6Ü Ð r   c                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   �   s   € ÷ ñ ¤Tñ r   c                 ó€  € \         P                  ! RR4      P                  4       P                  4       p V R9   d   R# V R	9   d   R#  ^ RIHp V! 4       pR
 FR  pVP                  V/ 4      p\        V\        4      '       g   K-  \        VP                  R4      RR7      '       g   KQ   R# 	  R#   \         d     R# i ; i)zFResolve the effective private-URL toggle from the active config scope.ÚHERMES_ALLOW_PRIVATE_URLSÚ TF©Úread_raw_configÚallow_private_urls)Údefault>   Ú1ÚyesÚtrue>   Ú0ÚnoÚfalse)ÚsecurityÚbrowser)r   Úgetenvr2   r7   Úhermes_cli.configrd   r   r1   Údictr   Ú	Exception)Úenv_valrd   ÚcfgÚsectionÚblocks        r   r[   r[   �   sª   € ä�iŠiÐ3°RÓ8×>Ñ>Ó@×FÑFÓH€GØÐ&Ô&ÙØÐ&Ô&ÙðÝ5ÙÓˆÛ.ˆGØ—G‘G˜G RÓ(ˆEÜ˜%¤×&Ô&¬?¸5¿9¹9ÐEYÓ;ZÐdi×+jÕ+jÚñ /ñ øô ô ØÙðús$   Á7B. ÂB. Â'B. Â*B. Â.B=Â<B=c                ó   € V ^8„  d   QhRR/# )r   r   Nr&   )r   s   "r   r   r   °   s   € ÷  ñ   Dñ  r   c                 ó   € R;s ;ssRsR# )uI   Reset the cached toggle and the cached fake-ip ranges â€” only for tests.FNr&   )r\   r]   Ú_fake_ip_resolvedÚ_cached_fake_ip_rangesr&   r   r   Ú_reset_allow_private_cacher{   °   s   € ð KPÐOÐÐOÐ3Ð6GØÒr   c                ó$   € V ^8„  d   QhR\         /# r   ©Útuple)r   s   "r   r   r   ·   s   € ÷ ñ ¤ñ r   c                 ó”  a€  ^ RI Hp  V ! 4       P                  R/ 4      p\        V\        4      '       d   VP                  R4      MRp\        T\        4      '       d   T.M\        T\        \        34      '       d   TMR
p. pT Fz  p \        P                  ! \        T4      P                  4       RR7      o\        T3R l\          4       R4      pTe   \        P                  R	YV4       Ki  TP#                  S4       K|  	  \        T4      #   \
         d    R
u # i ; i  \         d    \        P                  RT4        KÀ  i ; i)a  CIDR blocks this host's local proxy answers DNS with (``security.fake_ip_ranges``).

A TUN proxy in fake-ip mode answers every non-filtered name with an address from its own
block; that answer is the proxy's sentinel, not an internal host's, so treating it as a
private target blocks every outbound fetch on such a host (web_extract, platform attachment
downloads, the browser relay). Empty by default: no host gets the exemption unless it
declares one, and the sentinel range keeps the ordinary private-address verdict otherwise.
rc   rm   Úfake_ip_rangesNF)Ústrictz6Ignoring unparseable security.fake_ip_ranges entry: %rc              3   ó’   <"  € T F<  qP                   SP                   8X  g   K  SP                  V4      '       g   K8  Vx € K>  	  R # 5ir   )ÚversionÚoverlaps)r    ÚrÚnets   & €r   r"   Ú*_resolve_fake_ip_ranges.<locals>.<genexpr>Î   s6   øé € ÐpÑ!?˜AÇ9Á9ÐPS×P[ÑP[ÑC[”aÐ`c×`lÑ`lÐmn×`o—a’aÓ!?ùs   ƒA¤A½
AzNIgnoring security.fake_ip_ranges entry %r: it overlaps %s, which stays blockedr&   )rp   rd   r   r1   rq   rr   r+   Úlistr~   rR   rS   r2   r5   ÚloggerÚwarningrN   Ú_FAKE_IP_UNDECLARABLE_NETWORKSÚappend)rd   rv   rB   ÚentriesÚnetworksÚentryÚclashr†   s          @r   Ú_resolve_fake_ip_rangesr‘   ·   s  ø€ ðÝ5ÙÓ!×%Ñ% j°"Ó5ˆÜ-7¸¼t×-DÒ-Dˆe�i‰iÐ(Ô)È$ˆô " #¤s×+Ò+ˆs‰e¼
À3ÌÌuÈ×8VÒ8V±Ð\^€GØ€HÛˆð	Ü×&Ò&¤s¨5£z×'7Ñ'7Ó'9À%ÔHˆCô ÔpÕ!?ÓpÐrvÓwˆØÒÜ�N‰NÐkÐmrÔzÙØ�‰˜Öñ ô �‹?Ðøô ô ØŠ	ðûô ô 	Ü�N‰NÐSÐUZÔ[Úð	ús(   ƒ2D ¶D Â
/D"ÄDÄDÄ"!EÅEc                ó$   € V ^8„  d   QhR\         /# r   r}   )r   s   "r   r   r   Ö   s   € ÷ "ñ "¤ñ "r   c                 ól   € \        4       e   \        4       # \        '       g   R\        4       uss\        # )z®Process-lifetime cache with the same profile-scope bypass as ``_global_allow_private_urls``:
a multiplex gateway must not apply the first profile's declaration to later ones.T)r   r‘   ry   rz   r&   r   r   Ú_global_fake_ip_rangesr”   Ö   s4   € ô  Ó!Ò-Ü&Ó(Ð(ßÓØ48Ô:QÓ:SÐ1ÐÐ1Ü!Ð!r   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r   Úhostr   )r   r+   )r   s   "r   r   r   á   s   € ÷ 4ñ 4œh¤s�mð 4´ñ 4r   c                 óp   € T ;'       g    R P                  4       P                  4       P                  R4      # )rb   Ú.)r2   r7   Úrstrip)r–   s   &r   Ú_normalize_hostnamerš   á   s+   € Ø�JˆJ�B×ÑÓ×%Ñ%Ó'×.Ñ.¨sÓ3Ð3r   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   r:   r   )r+   r   Ú
_IPAddress)r   s   "r   r   r   å   s   € ÷ ñ œð ¤¬Õ 4ñ r   c                óT   €  \         P                  ! V 4      #   \         d     R# i ; i)z/IP object for a literal-IP hostname, else None.N)rR   Ú
ip_addressr5   )r:   s   &r   Ú	_parse_iprŸ   å   s*   € ðÜ×#Ò# HÓ-Ð-øÜô Úðús   ‚ ˜'¦'c                ó$   € V ^8„  d   QhR\         /# )r   Ú	addr_info©r   )r   s   "r   r   r   í   s   € ÷ -ñ -¤#ñ -r   c              #  óŠ   "  € V  F8  w  p  r#V^ ,          pVP                  R4      ^ ,          pWE\        V4      3x € K:  	  R# 5i)u¹   Yield ``(raw, ip_str, ip)`` per getaddrinfo answer. ``ip_str`` has any IPv6 scope ID
(``%eth0``) stripped; ``ip`` is None when still unparseable â€” each caller decides skip/fail/raise.Ú%N)ÚsplitrŸ   )r¡   Ú_familyÚ_ÚsockaddrrB   Úip_strs   &     r   Ú_iter_resolved_ipsrª   í   sE   é € ó '0Ñ"ˆ��A�qØ�q�kˆØ—‘˜3“ Õ"ˆØœ9 VÓ,Ð,Ô,ó '0ùs   ‚AAc                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   r:   Úport)r+   r   Úint)r   s   "r   r   r   ö   s"   € ÷ Tñ Tœ3ð T¤h¬s¥mñ Tr   c                 ój   € \         P                  ! W\         P                  \         P                  4      # r   )ÚsocketÚgetaddrinfoÚ	AF_UNSPECÚSOCK_STREAM)r:   r¬   s   &&r   Ú_getaddrinfor³   ö   s#   € Ü×Ò˜h¬f×.>Ñ.>Ä×@RÑ@RÓSÐSr   c                ó0   € V ^8„  d   QhR\         R\         /# ©r   Úipr   )rœ   )r   s   "r   r   r   ú   s   € ÷ 
ñ 
”zð 
¤jñ 
r   c                óÜ   € \        V \        P                  4      '       dL   V P                  e   V P                  # V \        9   d'   \        P
                  ! \        V 4      R,          4      # V # )uV  The IPv4 address an IPv6 wrapper stands for â€” IPv4-mapped (``::ffff:x.x.x.x``) or
IPv4-translated (``::ffff:0:x.x.x.x``); *ip* unchanged otherwise. ``ipaddress`` reads both
wrappers as distinct IPv6 addresses, so every classification must see through them, or a
resolver's sentinel / a cloud-metadata answer arrives as unrelated IPv6 space.l   ÿÿ )r1   rR   ÚIPv6AddressÚipv4_mappedÚ_IPV4_TRANSLATED_NETWORKÚIPv4Addressr­   ©r¶   s   &r   Ú_embedded_ipv4r½   ú   sS   € ô
 �"”i×+Ñ+×,Ò,Ø�>‰>Ò%Ø—>‘>Ð!ØÔ)Ô)Ü×(Ò(¬¨R«°:Õ)=Ó>Ð>Ø€Ir   c                ó0   € V ^8„  d   QhR\         R\        /# rµ   ©rœ   r   )r   s   "r   r   r     s   € ÷ [ñ [œjð [¬Tñ [r   c                 óÀ   a € \        S 4      o S \        9   ;'       gC    \        ;QJ d#    V 3R  l\         4       F  '       g   K   R# 	  R# ! V 3R  l\         4       4      # )c              3   ó.   <"  € T F
  pSV9   x € K  	  R # 5ir   r&   ©r    r†   r¶   s   & €r   r"   Ú(_is_always_blocked_ip.<locals>.<genexpr>	  s   øé € Ð+ZÑAY¸#¨B°#®IÓAYùó   ƒTF)r½   Ú_ALWAYS_BLOCKED_IPSr$   Ú_ALWAYS_BLOCKED_NETWORKSr¼   s   fr   Ú_is_always_blocked_iprÇ     sF   ø€ Ü	˜Ó	€BØÔ$Ñ$×ZÐZ¯«Ô+ZÕAYÓ+Z¯¬ÐZªÐZ¨Ô+ZÕAYÓ+ZÓ(ZÐZr   c                ó0   € V ^8„  d   QhR\         R\        /# rµ   r¿   )r   s   "r   r   r     s   € ÷ >ñ >œZð >¬Dñ >r   c                ó®   a € \        S 4      o \        ;QJ d'    V 3R l\        4        4       F  '       g   K   R# 	  R# ! V 3R l\        4        4       4      # )a  True when *ip* falls in a block declared in ``security.fake_ip_ranges``. The dial still goes
to the local proxy, which resolves and connects to the real target, so a declared block grants
no reach an attacker lacks through the proxy's own DNS; undeclared ranges keep the private verdict.c              3   ó.   <"  € T F
  pSV9   x € K  	  R # 5ir   r&   rÂ   s   & €r   r"   Ú'_is_declared_fake_ip.<locals>.<genexpr>  s   øé € Ð=Ñ$<˜Sˆr�SŽyÓ$<ùrÄ   TF)r½   r$   r”   r¼   s   fr   Ú_is_declared_fake_iprÌ     s@   ø€ ô 
˜Ó	€Bß‹3Ô=Ô$:Ô$<Ó=�3Œ3Ð=Š3Ð=ˆ3Ô=Ô$:Ô$<Ó=Ó=Ð=r   c                ó0   € V ^8„  d   QhR\         R\        /# rµ   r¿   )r   s   "r   r   r     s   € ÷ Mñ M”zð M¤dñ Mr   c                ó  € \        V 4      p V P                  ;'       gn    V P                  ;'       gZ    V P                  ;'       gF    V P                  ;'       g2    V P
                  ;'       g    V P                  ;'       g
    V \        9   # )z<Return True if the IP should be blocked for SSRF protection.)r½   Ú
is_privateÚis_loopbackÚis_link_localÚis_reservedÚis_multicastÚis_unspecifiedÚ_CGNAT_NETWORKr¼   s   &r   Ú_is_blocked_iprÖ     s�   € ô 
˜Ó	€BØ�M‰M÷ Lð L˜RŸ^™^÷ Lð L¨r×/?Ñ/?÷ Lð LÀ2Ç>Á>÷ Lð LØ�‰÷Lð LØ"$×"3Ñ"3÷Lð LØ79¼^Ñ7KðMr   c                ó0   € V ^8„  d   QhR\         R\        /# r)   ©r+   r   )r   s   "r   r   r     s   € ÷ $ñ $œsð $¤tñ $r   c                óv  €  \        \        V 4      P                  4      pV'       g   R# V\        9   d   \        P                  RV4       R# \        V4      pVe,   \        V4      '       d   \        P                  RV4       R# R#  \        V4      p\        T4       FL  w  rEpTf   \        P                  RYA4       K"  \        T4      '       g   K5  \        P                  RY4        R# 	  R#   \        P                   d     R# i ; i  \         d"   p\        P                  RY4        Rp?R# Rp?ii ; i)	u½  True when the URL targets the always-blocked floor (cloud metadata) â€” only the sentinel
hostnames/IPs, regardless of backend, routing, or ``allow_private_urls``. For callers that
deliberately bypass the full check (e.g. hybrid cloud browser routing private URLs to a local
sidecar) but must still enforce the floor. False for ordinary private/loopback URLs, DNS
failures and parse errors (the caller's ordinary fail-closed path handles those).Fz?Blocked request to internal hostname (always-blocked floor): %sTNzDBlocked request to cloud metadata address (always-blocked floor): %su>   Unparseable IP address %r for hostname %s â€” skipping addresszJBlocked request to cloud metadata address (always-blocked floor): %s -> %sz&is_always_blocked_url error for %s: %s)rš   r	   r:   Ú_BLOCKED_HOSTNAMESr‰   rŠ   rŸ   rÇ   r³   r¯   Úgaierrorrª   rr   Údebug)r*   r:   r¶   r¡   rB   r©   ÚresolvedÚexcs   &       r   Úis_always_blocked_urlrß     s  € ðÜ&¤x°£}×'=Ñ'=Ó>ˆßÙØÔ)Ô)Ü�N‰NÐ\Ð^fÔgÙÜ�xÓ ˆØŠ>Ü$ R×(Ò(Ü—‘ÐeÐgoÔpÙÙð	Ü$ XÓ.ˆIô &8¸	Ö%BÑ!ˆC˜ØÒÜ—‘Ð_ÐadÔoÙÜ$ X×.Ô.Ü—‘Ø`Ðbjôò ñ &Cñ øô �‰ô 	Úð	ûô ô ä�‰Ð=¸sÔHÝûðúsR   ‚&D ª!D Á6D ÂC0 Â;D ÃD Ã,D Ã0D	ÄD ÄD	Ä	D ÄD8ÄD3Ä3D8c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   r:   r6   r   rØ   )r   s   "r   r   r   D  s&   € ÷ Gñ G¬Cð G¼ð GÄñ Gr   c                ó.   € VR8H  ;'       d
    V \         9   # )zGReturn True when a trusted HTTPS hostname may bypass IP-class blocking.r   )Ú_TRUSTED_PRIVATE_IP_HOSTS)r:   r6   s   &&r   Ú_allows_private_ip_resolutionrã   D  s   € à�WÑ×FÐF Ô-FÑ!FÐFr   c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r   r¶   Úallow_privater   )rœ   r   r   r+   )r   s   "r   r   r   I  s%   € ÷ ñ ¤*ð ¼Tð ÄhÌsÅmñ r   c                ó„   € \        V 4      '       d   R# V'       g%   \        V 4      '       d   \        V 4      '       g   R# R# )z·Why a resolved answer must be rejected, or None if it may be dialed. The metadata floor
ignores ``allow_private``; ordinary private/internal classes are blocked only when it is False.zcloud metadata addresszprivate/internal addressN)rÇ   rÖ   rÌ   )r¶   rå   s   &&r   Ú_resolved_ip_block_reasonrç   I  s0   € ô ˜R× Ò Ù'ßœ^¨B×/Ò/Ô8LÈR×8PÒ8PÙ)Ùr   c                ó0   € V ^8„  d   QhR\         R\        /# r)   rØ   )r   s   "r   r   r   S  s   € ÷ 3ñ 3”Sð 3œTñ 3r   c                ó  €  \        V 4      p\        VP                  4      pVP                  ;'       g    RP	                  4       P                  4       pV\        9  d#   \        P                  RT;'       g    R4       R# V'       g   R# V\        9   d   \        P                  RV4       R# \        4       p\        W#4      pT;'       g    Tp \        V4      p\%        T4       FL  w  r‰p
T
f   \        P                  R
Y‚4        R# \'        Y¦4      pTf   K4  \        P                  RY²T	4        R# 	  T'       d   \        P#                  RT4       R# T'       d   \        P#                  RT4       R#   \        P                   dQ    \        T4      f*   \!        4       '       d   \        P#                  RT4        R# \        P                  R	T4        R# i ; i  \(         d"   p\        P                  RY4        Rp?R# Rp?ii ; i)a  True if the URL target is not a private/internal address. Resolves the hostname and checks
every answer; fails closed on DNS errors and unexpected exceptions. ``allow_private_urls``
skips private-IP blocking, but cloud metadata endpoints remain blocked regardless.rb   u.   Blocked request â€” unsupported URL scheme: %sz<empty>Fz(Blocked request to internal hostname: %sNu]   DNS resolution failed for %s â€” proxy configured, allowing through for proxy-side resolutionTu1   Blocked request â€” DNS resolution failed for: %su=   Blocked request â€” unparseable IP address %r for hostname %szBlocked request to %s: %s -> %szKAllowing private/internal resolution (security.allow_private_urls=true): %szAAllowing trusted hostname despite private/internal resolution: %su5   Blocked request â€” URL safety check error for %s: %s)r	   rš   r:   r6   r2   r7   r8   r‰   rŠ   rÚ   r^   rã   r³   r¯   rÛ   rŸ   r'   rÜ   rª   rç   rr   )r*   rC   r:   r6   Úallow_all_privateÚallow_private_iprå   r¡   rB   r©   r¶   ÚreasonrÞ   s   &            r   Úis_safe_urlrí   S  sµ  € ð/Ü˜#“ˆÜ& v§¡Ó7ˆØ—-‘-×%Ð% 2×,Ñ,Ó.×4Ñ4Ó6ˆØœÔ&Ü�N‰NÐKÈV×M`ÐM`ÐW`ÔaÙßÙð Ô)Ô)Ü�N‰NÐEÀxÔPÙÜ6Ó8ÐÜ8¸ÓJÐØ)×=Ð=Ð-=ˆð	Ü$ XÓ.ˆIô  2°)Ö<‰OˆC˜ØŠzÜ—‘Ð^Ð`cÔnÚÜ.¨rÓAˆFØÔ!Ü—‘Ð@À&ÐTZÔ[Úñ  =÷ Ü�L‰LÐfÐhpÔqñ ÷ Ü�L‰LÐ\Ð^fÔgÙøô1 �‰ô 	ô
 ˜Ó"Ò*Ô/C×/EÒ/EÜ—‘ØsØôò Ü�N‰NÐNÐPXÔYÚð	ûô2 ô ä�‰ÐNÐPSÔYÝûðúsŠ   ‚2G µAG Á8G ÂG Â!G Â.!G ÃE6 Ã,G Ä	G ÄG Ä4	G Ä>G ÅG ÅG Å6AGÆ>G ÇGÇG ÇGÇG ÇH
Ç)HÈH
c                ó0   € V ^8„  d   QhR\         R\        /# r)   rØ   )r   s   "r   r   r   ‰  s   € ÷ 5ñ 5¤ð 5¬ñ 5r   c              ƒ  óT   "  € \         P                  ! \        V 4      G Rj  x€L
 #  L5i)zB:func:`is_safe_url` with the blocking DNS work off the event loop.N)ÚasyncioÚ	to_threadrí   )r*   s   &r   Úasync_is_safe_urlrò   ‰  s   é € ä×"Ò"¤;°Ó4×4Ð4Ñ4ùs   ‚(¡&¢(c                   ó   € ] tR tRtRtRtR# )ÚSSRFConnectionBlockediŽ  zGRaised when connect-time DNS resolution violates the URL safety policy.r&   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r&   r   r   rô   rô   Ž  s   † ÝQr   rô   c          	      ó^   € V ^8„  d   QhR\         R\        R\         R\        \         ,          /# )r   r–   r¬   r6   r   ©r+   r­   rˆ   )r   s   "r   r   r   ’  s,   € ÷ ñ ¤Sð ´ð ¼Sð ÄTÌ#ÅYñ r   c           	     ód  € \        V 4      pV'       g   \        R4      hV\        9   d   \        RV 24      h\        4       ;'       g    \	        W24      p \        W14      p. p\        T4       F|  w  r‰p
T
f!   \        RT: RT 24      \        T	: R24      h\        Y¤4      pTe   \        RT R	T R
T	 24      hY—9  g   KU  \        T4      \        8  g   Kk  TP                  T	4       K~  	  T'       g   \        RT 24      hT#   \        P                   d   p\        RT 24      ThRp?ii ; i)zÿResolve and validate *host* at TCP-connect time; return dialable IP strings. Closes the
DNS-rebinding gap between pre-flight validation and connect for direct httpx clients. The
result is capped at ``_MAX_SSRF_CONNECT_IPS``, but EVERY answer is validated.z#Blocked request with empty hostnamez&Blocked request to internal hostname: z-Blocked request - DNS resolution failed for: Nz)Blocked request - unparseable IP address z for hostname z. does not appear to be an IPv4 or IPv6 addresszBlocked request to z during connect: z -> z/Blocked request - DNS returned no results for: )rš   rô   rÚ   r^   rã   r³   r¯   rÛ   rª   r5   rç   ÚlenÚ_MAX_SSRF_CONNECT_IPSrŒ   )r–   r¬   r6   r:   rå   r¡   rÞ   Úsafe_ipsrB   r©   r¶   rì   s   &&&         r   Ú_resolved_http_connect_ipsr  ’  sS  € ô # 4Ó(€HßÜ#Ð$IÓJÐJØÔ%Ô%Ü#Ð&LÈXÈJÐ$WÓXÐXÜ.Ó0×cÐcÔ4QÐRZÓ4c€MðiÜ  Ó0ˆ	ð €HÜ-¨iÖ8‰ˆ�RØŠ:Ü'Ø;¸C¹7À.ÐQYÐPZÐ[óä ¡
Ð*XÐYÓZð[ô +¨2Ó=ˆØÒÜ'Ð*=¸f¸XÐEVÐW_ÐV`Ð`dÐekÐdlÐ(mÓnÐnØÖ!¤c¨(£mÔ6KÖ&KØ�O‰O˜FÖ#ñ 9÷ Ü#Ð&UÐV^ÐU_Ð$`ÓaÐaØ€Oøô �?‰?ô iÜ#Ð&SÐT\ÐS]Ð$^Ó_ÐehÐhûðiús   ÁD ÄD/ÄD*Ä*D/c                   ó–   a € ] tR tRt o RtV 3R lR ltV 3R lR lt]V 3R lR l4       t]V 3R	 lR
 l4       t	RV 3R lR llt
RtV tR# )Ú_SSRFGuardedBackendBasei°  a	  httpcore backend that re-resolves + validates at connect time and dials a vetted IP.
Host/SNI stay on the original hostname; Unix sockets are refused outright. Candidate IPs are
tried in order and the last connect error is re-raised so callers see the real failure.c                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r   ÚbackendÚschemes_by_origin_varr¢   )r   Ú__classdict__s   "€r   r   Ú$_SSRFGuardedBackendBase.__annotate__µ  s   ø€ ÷ <ñ <¡ð <¹Cñ <r   c                ó   € Wn         W n        R # r   ©Ú_backendÚ_schemes_by_origin_var)Úselfr  r  s   &&&r   Ú__init__Ú _SSRFGuardedBackendBase.__init__µ  s   € ØŒØ&;Ö#r   c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[ ,          /# )r   r–   r¬   r   rü   )r   r  s   "€r   r   r  ¹  s&   ø€ ÷ >ñ >¡ð >©Cð >±D¹µIñ >r   c                ó–   € V P                   P                  / 4      P                  W34      ;'       g    VR 8X  d   RMRp\        WV4      # )i»  r   r   )r  r   r  )r  r–   r¬   r6   s   &&& r   Ú_connect_ipsÚ$_SSRFGuardedBackendBase._connect_ips¹  sF   € Ø×,Ñ,×0Ñ0°Ó4×8Ñ8¸$¸ÓF×nÐnÐVZÐ^aÔVaÉ7ÐgmˆÜ)¨$°fÓ=Ð=r   c                ó    <€ V ^8„  d   QhRS[ /# r   r}   )r   r  s   "€r   r   r  ¾  s   ø€ ÷ @ñ @™Uñ @r   c                 ó:   € ^ RI p V P                  V P                  3# )é    N)ÚhttpcoreÚConnectErrorÚConnectTimeout)r  s    r   Ú_connect_errorsÚ'_SSRFGuardedBackendBase._connect_errors½  s   € ãØ×%Ñ% x×'>Ñ'>Ð?Ð?r   c                ó:   <€ V ^8„  d   QhRS[ RS[R,          RS[/# )r   r–   Úlast_excNr   )r+   rr   )r   r  s   "€r   r   r  Ã  s,   ø€ ÷ bñ b™Sð b©I¸Õ,<ð bÁñ br   c                ó*   € Ve   V# \        RV  24      # )Nz2Blocked request - DNS returned no usable IPs for: ©rô   )r–   r  s   &&r   Ú_no_usable_ipsÚ&_SSRFGuardedBackendBase._no_usable_ipsÂ  s"   € àÒØˆOÜ$Ð'YÐZ^ÐY_Ð%`ÓaÐar   Nc                ó@   <€ V ^8„  d   QhRS[ RS[R,          RS[RS[/# ©r   r?   ÚtimeoutNÚsocket_optionsr   ©r+   Úfloatr   )r   r  s   "€r   r   r  È  s5   ø€ ÷ ]ñ ]©ð ]±e¸dµlð ]Ñ[^ð ]Ñjmñ ]r   c                ó   € \        R 4      h©z5Blocked Unix socket connection in SSRF-safe transportr  ©r  r?   r$  r%  s   &&&&r   Úconnect_unix_socketÚ+_SSRFGuardedBackendBase.connect_unix_socketÈ  s   € Ü#Ð$[Ó\Ð\r   r
  ©NN)rõ   rö   r÷   rø   rù   r  r  Ústaticmethodr  r   r+  rú   Ú__classdictcell__)r  s   @r   r  r  °  s]   ø‡ € ñ_÷<ð <÷>ð >ð ÷@ó ð@ð ÷bó ðb÷
]÷ ]ð ]r   r  c                   ó|   a a€ ] tR tRt oV3R lV 3R lltRV3R lR lltRV3R lR lltV3R lR	 ltR
tVt	V ;t
# )Ú_SSRFGuardedAsyncNetworkBackendiÌ  c                ó    <€ V ^8„  d   QhRS[ /# ©r   r  r¢   )r   r  s   "€r   r   Ú,_SSRFGuardedAsyncNetworkBackend.__annotate__Í  ó   ø€ ÷ ?ñ ?©cñ ?r   c                ó>   <€ ^ RI Hp \        SV `  V! 4       V4       R# )r  )ÚAutoBackendN)Úhttpcore._backends.autor7  Úsuperr  )r  r  r7  Ú	__class__s   && €r   r  Ú(_SSRFGuardedAsyncNetworkBackend.__init__Í  ó   ø€ Ý7Ü‰Ñ™›Ð(=Ö>r   c                óZ   <€ V ^8„  d   QhRS[ RS[RS[R,          RS[ R,          RS[RS[/# ©r   r–   r¬   r$  NÚlocal_addressr%  r   ©r+   r­   r'  r   )r   r  s   "€r   r   r4  Ñ  sB   ø€ ÷ 	2ñ 	2¡cð 	2±ð 	2¹uÀt½|ð 	2Ù),¨t­ð	2ÙLOð	2Ù[^ñ	2r   c           	   ƒ  ó0  "  € R p\         P                  ! V P                  W4      G R j  x€L
  F*  p V P                  P	                  WrW4VR7      G R j  x€L
 u # 	  V P                  W4      h LC L  T P                  4        d   pTp R p?K`  R p?ii ; i5i©N)r$  r?  r%  )rð   rñ   r  r  Úconnect_tcpr  r   ©	r  r–   r¬   r$  r?  r%  r  r¶   rÞ   s	   &&&&&&   r   rC  Ú+_SSRFGuardedAsyncNetworkBackend.connect_tcpÑ  s›   é € à%)ˆÜ×)Ò)¨$×*;Ñ*;¸TÓH×HÒHˆBðØ!Ÿ]™]×6Ñ6Ø gÐ[ið 7ó k÷ kò kñ Ið ×!Ñ! $Ó1Ð1ñ Iñkøà×'Ñ'Ó)ô Ø–ûðüsJ   ‚'B©A-ªB²!A1ÁA/ÁA1ÁBÁ/A1Á1BÂBÂBÂBÂBc                ó@   <€ V ^8„  d   QhRS[ RS[R,          RS[RS[/# r#  r&  )r   r  s   "€r   r   r4  Ü  s5   ø€ ÷ ]ñ ]©cð ]¹EÀD½Lð ]Ñadð ]Ñpsñ ]r   c              ƒ  ó    "  € \        R 4      h5ir)  r  r*  s   &&&&r   r+  Ú3_SSRFGuardedAsyncNetworkBackend.connect_unix_socketÜ  s   é € Ü#Ð$[Ó\Ð\ùs   ‚c                ó$   <€ V ^8„  d   QhRS[ RR/# ©r   Úsecondsr   N©r'  )r   r  s   "€r   r   r4  ß  s   ø€ ÷ +ñ +¡5ð +¨Tñ +r   c              ƒ  óX   "  € V P                   P                  V4      G R j  x€L
  R #  L5ir   ©r  Úsleep©r  rK  s   &&r   rO  Ú%_SSRFGuardedAsyncNetworkBackend.sleepß  s   é € Ø�m‰m×!Ñ! 'Ó*×*Ô*ùs   ‚*¡(¢*r&   ©NNNr-  )rõ   rö   r÷   rø   r  rC  r+  rO  rú   r/  Ú__classcell__©r:  r  s   @@r   r1  r1  Ì  s4   ù‡ € ÷?ó ?÷	2ò 	2÷]ò ]÷+÷ +ð +r   r1  c                   óf   a a€ ] tR tRt oV3R lV 3R lltR	V3R lR lltV3R lR ltRtVtV ;t	# )
Ú_SSRFGuardedNetworkBackendiã  c                ó    <€ V ^8„  d   QhRS[ /# r3  r¢   )r   r  s   "€r   r   Ú'_SSRFGuardedNetworkBackend.__annotate__ä  r5  r   c                ó>   <€ ^ RI Hp \        SV `  V! 4       V4       R# )r  )ÚSyncBackendN)Úhttpcore._backends.syncrZ  r9  r  )r  r  rZ  r:  s   && €r   r  Ú#_SSRFGuardedNetworkBackend.__init__ä  r<  r   c                óZ   <€ V ^8„  d   QhRS[ RS[RS[R,          RS[ R,          RS[RS[/# r>  r@  )r   r  s   "€r   r   rX  è  sB   ø€ ÷ 	2ñ 	2¡ð 	2©3ð 	2¹À½ð 	2Ù#&¨¥:ð	2ÙFIð	2ÙUXñ	2r   c           	     óà   € R pV P                  W4       F"  p V P                  P                  WrW4VR7      u # 	  V P	                  W4      h  T P                  4        d   pTp R p?KT  R p?ii ; irB  )r  r  rC  r  r   rD  s	   &&&&&&   r   rC  Ú&_SSRFGuardedNetworkBackend.connect_tcpè  sz   € à%)ˆØ×#Ñ# DÖ/ˆBðØ—}‘}×0Ñ0Ø gÐ[ið 1ó kò kñ 0ð ×!Ñ! $Ó1Ð1øð ×'Ñ'Ó)ô Ø–ûðús   ˜AÁA-Á A(Á(A-c                ó$   <€ V ^8„  d   QhRS[ RR/# rJ  rL  )r   r  s   "€r   r   rX  ó  s   ø€ ÷ %ñ %™Uð % tñ %r   c                ó<   € V P                   P                  V4       R # r   rN  rP  s   &&r   rO  Ú _SSRFGuardedNetworkBackend.sleepó  s   € Ø�‰×Ñ˜GÖ$r   r&   rR  )
rõ   rö   r÷   rø   r  rC  rO  rú   r/  rS  rT  s   @@r   rV  rV  ã  s(   ù‡ € ÷?ó ?÷	2ò 	2÷%÷ %ð %r   rV  c                ót   € V ^8„  d   QhR\         R\        \        \        \        3,          \        3,          /# ©r   Úrequestr   )r   rq   r~   r+   r­   )r   s   "r   r   r   ÷  s0   € ÷ cñ c¤Cð c¬D´´s¼C°xµÄ#Ð1EÕ,Fñ cr   c                 óÀ   € V P                   P                  V P                   P                  V P                   P                  r2pV'       d   Ve   V\        9   d   W3V/# / # r   )r*   r–   r¬   r6   r8   )re  r–   r¬   r6   s   &   r   Ú_origin_scheme_contextrg  ÷  sL   € Ø Ÿ™×)Ñ)¨7¯;©;×+;Ñ+;¸W¿[¹[×=OÑ=O�€Dß%)¨dÒ.>À6Ì]ÔCZˆTˆL˜&Ð!ÐbÐ`bÐbr   c                ó0   € V ^8„  d   QhR\         R\         /# )r   r  re  r¢   )r   s   "r   r   r   ý  s   € ÷ +ñ +¬ð +´sñ +r   c              #  óš   "  € V P                  \        V4      4      p Rx € V P                  V4       R#   T P                  T4       i ; i5i)zUExpose the request's origin scheme to the connect-time backend for this request only.N)Úsetrg  Úreset)r  re  Útokens   && r   Ú_origin_scoperm  ü  sB   é € ð "×%Ñ%Ô&<¸WÓ&EÓF€Eð+Ûà×#Ñ# EÖ*øÐ×#Ñ# EÕ*üs   ‚Až5 ¢AµAÁAÚis_asyncc                ó@   € V ^8„  d   QhR\         R\         R\        RR/# )r   Ú	transportr  rn  r   N©r   r   )r   s   "r   r   r     s*   € ÷ *ñ *´ð *ÌCð *Ô^bð *Ðosñ *r   c               óê  aa
€ V e   \        V R/ 4      M/ pV e   VP                  RR4      '       d   R# V'       d   RMRpVP                  R4      pVe   \        VR4      '       g   \        R	V R
24      hV'       d   \        M\
        pV! S4      Vn        V'       d   RMRp\        WR4      o
S
f   \        R	V R
24      hR V
V3R llpR V
V3R llp	\        YV'       d   TMT	4       RV n        R# )zºSwap the transport's pool network backend for the SSRF-guarded one (idempotent). Only the
direct transport is guarded; proxy mounts delegate final-target resolution to the trusted proxy.NÚ__dict__Ú_hermes_ssrf_guardedFzasync httpx transportzhttpx transportÚ_poolÚ_network_backendzUnsupported z cannot be made SSRF-safeÚhandle_async_requestÚhandle_requestc                ó0   € V ^8„  d   QhR\         R\         /# rd  r¢   )r   s   "r   r   Ú6_install_ssrf_guard_on_transport.<locals>.__annotate__  s   € ÷ )ñ )¤Sð )¬Sñ )r   c              “   ó–   <"  € \        SV 4      ;_uu_ 4        S! V 4      G R j  x€L
 uuR R R 4       #  L  + '       g   i     R # ; i5ir   ©rm  ©re  Úhandler  s   &€€r   Úguarded_asyncÚ7_install_ssrf_guard_on_transport.<locals>.guarded_async  s4   øé € ÜÐ0°'×:Õ:Ù ›×(÷ ;Ò:Ù(÷ ;×:Ð:üs%   ƒA	˜5¤3¥5¨A	³5µA	Á 	A	c                ó0   € V ^8„  d   QhR\         R\         /# rd  r¢   )r   s   "r   r   rz    s   € ÷ #ñ #œcð #¤cñ #r   c                 óz   <€ \        SV 4      ;_uu_ 4        S! V 4      uuR R R 4       #   + '       g   i     R # ; ir   r|  r}  s   &€€r   Úguarded_syncÚ6_install_ssrf_guard_on_transport.<locals>.guarded_sync  s'   ø€ ÜÐ0°'×:Õ:Ù˜'“?÷ ;×:×:Ó:ús   –)©:	T)	Úgetattrr   Úhasattrrô   r1  rV  rv  Úsetattrrt  )rp  r  rn  ÚstateÚlabelÚpoolÚbackend_clsÚmethod_namer  rƒ  r~  s   &f$       @r   Ú _install_ssrf_guard_on_transportr�    sê   ù€ ð 3<Ò2GŒG�I˜z¨2Ô.ÈR€EØÒ˜EŸI™IÐ&<¸e×DÒDÙß'/Ñ#Ð5F€EØ�9‰9�WÓ€DØ‚|œ7 4Ð);×<Ò<Ü# l°5°'Ð9RÐ$SÓTÐTß5=Õ1ÔC]€KÙ'Ð(=Ó>€DÔß,4Ñ(Ð:J€KÜ�Y¨TÓ2€FØ‚~Ü# l°5°'Ð9RÐ$SÓTÐT÷)ñ )÷#ñ #ô ˆI·X¡MÀ<ÔPØ%)€IÖ"r   c                ó4   € V ^8„  d   QhR\         R\        RR/# )r   Úclientrn  r   Nrq  )r   s   "r   r   r   "  s&   € ÷ pñ p¬#ð p¼Dð pÈTñ pr   c               ó”   € ^ RI pV'       d   RMRp\        \        V R/ 4      P                  R4      VP	                  V4      VR7       R# )zTGuard ``client._transport`` only; ``_mounts`` (env/explicit proxies) stay untouched.NÚ hermes_ssrf_async_origin_schemesÚhermes_ssrf_origin_schemesrs  Ú
_transport©rn  )Úcontextvarsr�  r…  r   Ú
ContextVar)r�  rn  r•  Úvar_names   &$  r   Ú_install_ssrf_guard_on_clientr˜  "  sA   € ãß5=Ñ1ÐC_€HÜ$Ü�˜
 BÓ'×+Ñ+¨LÓ9¸;×;QÑ;QÐRZÓ;[Ðfn÷pr   c                ó0   € V ^8„  d   QhR\         R\         /# ©r   Úkwargsr   r¢   )r   s   "r   r   r   *  s   € ÷ ñ ¬Cð ´Cñ r   c                 óL   € ^ RI pVP                  ! R/ V B p\        VRR7       V# )zý``httpx.AsyncClient`` with connect-time SSRF validation: direct HTTP(S) connections are
resolved, validated, and dialed by IP while the hostname is preserved for Host, SNI, and
certificate verification. Proxied requests delegate resolution to the proxy.NTr”  r&   )ÚhttpxÚAsyncClientr˜  ©r›  r�  r�  s   ,  r   Úcreate_ssrf_safe_async_clientr   *  s)   € ó Ø×ÒÑ( Ñ(€FÜ! &°4Õ8Ø€Mr   c                ó0   € V ^8„  d   QhR\         R\         /# rš  r¢   )r   s   "r   r   r   4  s   € ÷ ñ ¤cð ¬cñ r   c                 óH   € ^ RI pVP                  ! R/ V B p\        V4       V# )z=Create an ``httpx.Client`` with connect-time SSRF validation.Nr&   )r�  ÚClientr˜  rŸ  s   ,  r   Úcreate_ssrf_safe_clientr¤  4  s#   € ãØ�\Š\Ñ#˜FÑ#€FÜ! &Ô)Ø€Mr   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Úresponser   )r   r   r+   )r   s   "r   r   r   <  s   € ÷ 
;ñ 
;¬Cð 
;´H¼SµMñ 
;r   c           	     ó2  € \        V RR4      '       g   R# \        V R/ 4      ;'       g    / P                  R4      pV'       d*   \        \        \        V RR4      4      \        V4      4      # \        V RR4      pV'       d   \        VP                  4      # R# )	u  Redirect target visible from inside an httpx response hook. ``response.next_request`` is
frequently ``None`` inside hooks (populated later by the follower), which would make an SSRF
redirect guard silently never fire â€” so resolve from ``Location`` first, then ``next_request``.Úis_redirectFNÚheadersÚlocationr*   rb   Únext_request)r…  r   r   r+   r*   )r¦  rª  r«  s   &  r   Úredirect_target_from_responser¬  <  s   € ô �8˜]¨E×2Ò2ÙÜ˜ )¨RÓ0×6Ð6°B×;Ñ;¸JÓG€HßÜ”sœ7 8¨U°BÓ7Ó8¼#¸h»-ÓHÐHÜ˜8 ^°TÓ:€Lß$0Œ3ˆ|×ÑÓ Ð:°dÐ:r   )ÚHTTPS_PROXYÚhttps_proxyÚ
HTTP_PROXYÚ
http_proxyÚ	ALL_PROXYÚ	all_proxy>   Újwtrl  ÚapikeyÚpasswdÚsecretÚapi_keyÚpasswordÚ	signatureÚ
auth_tokenÚ
credentialÚ
session_idÚcredentialsÚaccess_tokenÚauthorizationÚclient_secretÚawsaccesskeyidÚx_amz_signatureÚx_amz_security_tokenúx-amz-signatureúx-amz-security-token)z169.254.169.254z169.254.170.2z169.254.169.253z100.100.100.200)ú169.254.0.0/16z::ffff:169.254.0.0/112)z
0.0.0.0/32z127.0.0.0/8z
10.0.0.0/8z172.16.0.0/12z192.168.0.0/16rÆ  rW   z::/128z::1/128zfc00::/7z	fe80::/10r&   r   )Trù   rR   Úloggingr   r¯   rð   r3   Ú
contextlibr   Útypingr   r   Úurllib.parser   r   r   r   r	   r
   r   Úhermes_constantsr   Úutilsr   Ú	getLoggerrõ   r‰   r%   Ú	frozensetr8   r»   r¸   rœ   r'   rE   rI   rO   rÚ   Ú_METADATA_V4rž   rÅ   r~   rÆ   râ   rÿ   rS   rÕ   rº   r‹   r\   r]   ry   rz   r^   r[   r{   r‘   r”   rš   rŸ   rª   r³   r½   rÇ   rÌ   rÖ   rß   rã   rç   rí   rò   r5   rô   r  r  r1  rV  rg  rm  r�  r˜  r   r¤  r¬  r¼   s   0r   Ú<module>rÐ     s¬  ðñ
ó Û Û 	Û Û Û 	Ý %ß  ß [× [Ñ [å 5Ý !à	×	Ò	˜8Ó	$€ð g€Ù˜6 7Ð+Ó,€Ø×"Ñ" Y×%:Ñ%:Õ:€
õ;õgñF  )ò */ó  0Ð õ[ñ" Ð :¸OÐLÓMÐ ð€ñ  Ù(4Ó5© "€Y×Ñ˜"Ö©Ñ5Ù6BÓC±l°€y×Ñ˜I¨�NÖ+±lÑCõDà×Ò˜OÓ,Ð-õ.óÐ ÷ !˜5Ñ oÑBnÓ oŸ5™5Ñ oÑBnÓ oÓoÐ ñ &Ð'@Ð&AÓBÐ ØÐ ð ×%Ò% oÓ6€ð
 %×/Ò/Ð0AÓBÐ ÷ "' ñ 'ñ Ió '§¡ñ 'ñ Ió 'ó "Ð ð 27¸Ð .Ð Ð.Ø,1°2Ð )Ð Ð)õ
!õõ& õõ>"õ4õõ-÷Tõ
õ[õ
>õMõ$õNGõ
õ3õl5ô
R˜Jô Rõ÷<]ñ ]ô8+Ð&=ô +ô.%Ð!8ô %õ(cð
 ô+ó ð+ð*Ðej÷ *ð8pÀ5÷ põõ÷
;ùòa 6ùÚCs   Â0I7Ã!I<
