Ë
    ãß²jåx  ã            
       óP  — 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mZ ddl	m
Z
mZ ddlmZmZmZmZmZmZmZ ddlmZ ddlmZ  ej0                  e«      ZdZ ed	d
h«      Zej<                  ej>                  z  Z de!fd„Z"de#de#fd„Z$ eh d£«      Z%de#dee#   fd„Z& eddh«      Z'dZ( ee(D � ch c]  }  ejR                  | «      ’Œ c} e(D � ch c]  }  ejR                  d| z   «      ’Œ c} z   ejR                  d«      hz  «      Z* e+d„ dD «       «      Z, edh«      Z-dZ. ej^                  d«      Z0 ej^                  d«      Z1 e+d„ dD «       «      Z2d\  a3a4d\  a5a6de!fd „Z7de!fd!„Z8dUd"„Z9de+fd#„Z:de+fd$„Z;d%ee#   de#fd&„Z<d'e#dee    fd(„Z=d)e
fd*„Z>dVd'e#d+ee?   fd,„Z@d-e de fd.„ZAd-e de!fd/„ZBd-e de!fd0„ZCd-e de!fd1„ZDde#de!fd2„ZEd'e#d3e#de!fd4„ZFd-e d5e!dee#   fd6„ZGde#de!fd7„ZHde#de!fd8„ZI G d9„ d:eJ«      ZKd%e#d+e?d3e#deLe#   fd;„ZM G d<„ d=«      ZN G d>„ d?eN«      ZO G d@„ dAeN«      ZPdBe
deQe+e#e?f   e#f   fdC„ZRedDe
dBe
fdE„«       ZSdFdGœdHe
dDe
dIe!ddfdJ„ZTdFdGœdKe
dIe!ddfdL„ZUdMe
de
fdN„ZVdMe
de
fdO„ZWdPe
dee#   fdQ„ZXde#de!fdR„ZYdMe
de
fdS„ZZdMe
de
fdT„Z[yc c} w c c} w )WuW  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)ÚHTTPS_PROXYÚhttps_proxyÚ
HTTP_PROXYÚ
http_proxyÚ	ALL_PROXYÚ	all_proxyÚhttpÚhttpsÚreturnc                  ó.   — t        d„ t        D «       «      S )Nc              3   óZ   K  — | ]#  }t         j                  j                  |«      –— Œ% y ­w©N)ÚosÚenvironÚget)Ú.0Úvs     ú5/home/ubuntu/.hermes/hermes-agent/tools/url_safety.pyú	<genexpr>z'_proxy_is_configured.<locals>.<genexpr>#   s   è ø€ Ò: QŒr�z‰z�~‰~˜a× Ñ:ùs   ‚)+)ÚanyÚ_PROXY_ENV_VARS© ó    r    Ú_proxy_is_configuredr&   "   s   € ÜÑ:¬/Ô:Ó:Ð:r%   Úurlc                 ó„  — t        | t        «      s| S | j                  «       }|s|S t        j                  dd|«      }	 t        |«      }|j                  j                  «       t        vr|S |j                  |j                  }}|r9	 |j                  d«      j                  d«      }||k7  r|j                  ||d«      }d}t!        |j                  |t#        |j$                  |¬«      t#        |j&                  |dz   ¬«      t#        |j(                  |dz   ¬«      f«      S # t        $ r |cY S w xY w# t        $ r |}Y Œ—w xY w)	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Úasciié   z/%:@!$&'()*+,;=)Úsafeú?)Ú
isinstanceÚstrÚstripÚreÚsubr   Ú
ValueErrorÚschemeÚlowerÚ_HTTP_SCHEMESÚnetlocÚhostnameÚencodeÚdecodeÚUnicodeErrorÚreplacer   r   ÚpathÚqueryÚfragment)r'   ÚrawÚparsedr7   r8   Ú
ascii_hostr,   s          r    Únormalize_url_for_requestrC   &   s3  € ô �cœ3ÔØˆ
Ø
�)‰)‹+€CÙØˆ
ô �&‰&Ð4°e¸SÓ
A€CðÜ˜#“ˆð ‡}�}×ÑÓ¤MÑ1Øˆ
Ø—}‘} f§o¡oˆH€FÙð	"Ø!Ÿ™¨Ó0×7Ñ7¸Ó@ˆJð ˜Ò!Ø—^‘^ H¨j¸!Ó<ˆFØ€DÜ�v—}‘} f¬e°F·K±KÀdÔ.KÜ˜VŸ\™\°°s±
Ô;¼UÀ6Ç?Á?ÐY]Ð`cÑYcÔ=dðfó gð gøô ò ØŠ
ðûô ò 	"Ø!ŠJð	"ús#   ¿D  Â D1 Ä D.Ä-D.Ä1D?Ä>D?>   úx-amz-signatureúx-amz-security-tokenÚjwtÚtokenÚ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_tokenc                 ó(  — t        | t        «      rd| vry	 t        | j                  «       «      }|j
                  j                  «       t        vs|j                  syt        d„ t        |j                  d¬«      D «       d«      S # t        $ r Y yw xY w)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.r-   Nc              3   óh   K  — | ]*  \  }}|r#t        |«      j                  «       t        v r|–— Œ, y ­wr   )r   r5   Ú_SENSITIVE_QUERY_PARAM_NAMES)r   ÚkeyÚvalues      r    r!   z-sensitive_query_param_name.<locals>.<genexpr>\   s5   è ø€ ò T™˜˜eÙœg c›l×0Ñ0Ó2Ô6RÑRô ñ Tùs   ‚02T)Úkeep_blank_values)r.   r/   r   r0   r3   r4   r5   r6   r>   Únextr   )r'   rA   s     r    Úsensitive_query_param_namer_   P   sŒ   € ô �cœ3Ô 3¨c¡>ØðÜ˜#Ÿ)™)›+Ó&ˆð ‡}�}×ÑÓ¤MÑ1¸¿ºØÜñ T¤y°·±ÐQUÔ'Vô TØUYó[ð [øô	 ò Ùðús   —B Â	BÂBzmetadata.google.internalzmetadata.goog)z169.254.169.254z169.254.170.2z169.254.169.253z100.100.100.200z::ffff:zfd00:ec2::254c              #   óF   K  — | ]  }t        j                  |«      –— Œ y ­wr   ©Ú	ipaddressÚ
ip_network©r   Úns     r    r!   r!   q   s   è ø€ Ò o¸Q¤×!5Ñ!5°a×!8Ñ oùó   ‚!)ú169.254.0.0/16z::ffff:169.254.0.0/112zmultimedia.nt.qq.com.cné   ú100.64.0.0/10z::ffff:0:0:0/96c              #   óF   K  — | ]  }t        j                  |«      –— Œ y ­wr   ra   rd   s     r    r!   r!   …   s   è ø€ ò 'À1¤y×';Ñ';¸A×'>ñ 'ùrf   )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/16rg   ri   z::/128z::1/128zfc00::/7z	fe80::/10)FF)Fr$   c                  ó\   — t        «       �
t        «       S t        sdt        «       caat        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_urlsro   �   s1   € ô  Ó!Ð-Ü*Ó,Ð,Ý"Ø9=Ô?ZÓ?\Ð6ÐÐ!6Ü Ð r%   c                  óH  — t        j                  dd«      j                  «       j                  «       } | dv ry| dv ry	 ddlm}  |«       }d	D ]C  }|j                  |i «      }t        |t        «      sŒ&t        |j                  d
«      d¬«      sŒC y 	 y# t        $ r Y yw xY w)zFResolve the effective private-URL toggle from the active config scope.ÚHERMES_ALLOW_PRIVATE_URLSÚ >   Ú1ÚyesÚtrueT>   Ú0ÚnoÚfalseFr   ©Úread_raw_config)ÚsecurityÚbrowserÚallow_private_urls)Údefault)r   Úgetenvr0   r5   Úhermes_cli.configrz   r   r.   Údictr   Ú	Exception)Úenv_valrz   ÚcfgÚsectionÚblocks        r    rl   rl   �   s©   € ä�i‰iÐ3°RÓ8×>Ñ>Ó@×FÑFÓH€GØÐ&Ñ&ØØÐ&Ñ&ØðÝ5ÙÓˆØ.ò 	ˆGØ—G‘G˜G RÓ(ˆEÜ˜%¤Õ&¬?¸5¿9¹9ÐEYÓ;ZÐdiÖ+jÙñ	ð øô ò ØØðús#   ¾4B Á3B ÂB ÂB Â	B!Â B!c                  ó   — dxa xaaday)uI   Reset the cached toggle and the cached fake-ip ranges â€” only for tests.Fr$   N)rm   rn   Ú_fake_ip_resolvedÚ_cached_fake_ip_rangesr$   r%   r    Ú_reset_allow_private_cacherŠ   °   s   € ð KPÐOÐÐOÐ3Ð6GØÑr%   c                  óV  ‡— 	 ddl m}   | «       j                  di «      }t        |t        «      r|j                  d«      nd}t        |t        «      r|gnt        |t        t        f«      r|nd}g }|D ]u  }	 t        j                  t        |«      j                  «       d¬«      Št        ˆfd
„t         D «       d«      }|�t        j                  d||«       Œe|j#                  ‰«       Œw t        |«      S # t
        $ r Y yw xY w# t        $ r t        j                  d	|«       Y Œ³w xY w)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.
    r   ry   r{   Úfake_ip_rangesNr$   F)Ústrictz6Ignoring unparseable security.fake_ip_ranges entry: %rc              3   óz   •K  — | ]2  }|j                   ‰j                   k(  sŒ‰j                  |«      sŒ/|–— Œ4 y ­wr   )ÚversionÚoverlaps)r   ÚrÚnets     €r    r!   z*_resolve_fake_ip_ranges.<locals>.<genexpr>Î   s2   øè ø€ Òp˜AÀ1Ç9Á9ÐPS×P[ÑP[ÓC[Ð`c×`lÑ`lÐmnÕ`o”aÑpùs   ƒ;¢;´;zNIgnoring security.fake_ip_ranges entry %r: it overlaps %s, which stays blocked)r€   rz   r   r.   r�   r‚   r/   ÚlistÚtuplerb   rc   r0   r3   ÚloggerÚwarningr^   Ú_FAKE_IP_UNDECLARABLE_NETWORKSÚappend)rz   r†   r@   ÚentriesÚnetworksÚentryÚclashr’   s          @r    Ú_resolve_fake_ip_rangesr�   ·   s  ø€ ðÝ5ÙÓ!×%Ñ% j°"Ó5ˆÜ-7¸¼tÔ-Dˆe�i‰iÐ(Ô)È$ˆô " #¤sÔ+ˆs‰e¼
À3ÌÌuÈÔ8V±Ð\^€GØ€HØò 
ˆð	Ü×&Ñ&¤s¨5£z×'7Ñ'7Ó'9À%ÔHˆCô ÓpÔ!?ÔpÐrvÓwˆØÐÜ�N‰NÐkÐmrÐtyÔzØØ�‰˜Õð
ô �‹?Ðøô ò Ùðûô ò 	Ü�N‰NÐSÐUZÔ[Ùð	ús$   ƒA C7 Á8.DÃ7	DÄDÄD(Ä'D(c                  ó\   — t        «       �
t        «       S t        sdt        «       caat        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�   rˆ   r‰   r$   r%   r    Ú_global_fake_ip_rangesrŸ   Ö   s1   € ô  Ó!Ð-Ü&Ó(Ð(ÝØ48Ô:QÓ:SÐ1ÐÐ1Ü!Ð!r%   Úhostc                 ód   — | xs dj                  «       j                  «       j                  d«      S )Nrr   ú.)r0   r5   Úrstrip)r    s    r    Ú_normalize_hostnamer¤   á   s)   € ØŠJ�B×ÑÓ×%Ñ%Ó'×.Ñ.¨sÓ3Ð3r%   r8   c                 óL   — 	 t        j                  | «      S # t        $ r Y yw xY w)z/IP object for a literal-IP hostname, else None.N)rb   Ú
ip_addressr3   )r8   s    r    Ú	_parse_ipr§   å   s*   € ðÜ×#Ñ# HÓ-Ð-øÜò Ùðús   ‚ —	#¢#Ú	addr_infoc              #   óx   K  — | D ]1  \  }}}}}|d   }|j                  d«      d   }||t        |«      f–— Œ3 y­w)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.r   ú%N)Úsplitr§   )r¨   Ú_familyÚ_Úsockaddrr@   Úip_strs         r    Ú_iter_resolved_ipsr°   í   sO   è ø€ ð '0ò -Ñ"ˆ��A�q˜(Ø�q‰kˆØ—‘˜3“ Ñ"ˆØ�6œ9 VÓ,Ð,Ó,ñ-ùs   ‚8:Úportc                 ój   — t        j                  | |t         j                  t         j                  «      S r   )ÚsocketÚgetaddrinfoÚ	AF_UNSPECÚSOCK_STREAM)r8   r±   s     r    Ú_getaddrinfor·   ö   s%   € Ü×Ñ˜h¨¬f×.>Ñ.>Ä×@RÑ@RÓSÐSr%   Úipc                 ó¼   — t        | t        j                  «      rA| j                  �| j                  S | t        v r!t        j
                  t        | «      dz  «      S | S )ub  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   ÿÿ )r.   rb   ÚIPv6AddressÚipv4_mappedÚ_IPV4_TRANSLATED_NETWORKÚIPv4AddressÚint©r¸   s    r    Ú_embedded_ipv4rÀ   ú   sP   € ô
 �"”i×+Ñ+Ô,Ø�>‰>Ð%Ø—>‘>Ð!ØÔ)Ñ)Ü×(Ñ(¬¨R«°:Ñ)=Ó>Ð>Ø€Ir%   c                 ó^   ‡ — t        ‰ «      Š ‰ t        v xs t        ˆ fd„t        D «       «      S )Nc              3   ó&   •K  — | ]  }‰|v –— Œ
 y ­wr   r$   ©r   r’   r¸   s     €r    r!   z(_is_always_blocked_ip.<locals>.<genexpr>	  s   øè ø€ Ò+Z¸#¨B°#¬IÑ+Zùó   ƒ)rÀ   Ú_ALWAYS_BLOCKED_IPSr"   Ú_ALWAYS_BLOCKED_NETWORKSr¿   s   `r    Ú_is_always_blocked_iprÇ     s*   ø€ Ü	˜Ó	€BØÔ$Ð$ÒZ¬Ó+ZÔAYÔ+ZÓ(ZÐZr%   c                 óR   ‡ — t        ‰ «      Š t        ˆ fd„t        «       D «       «      S )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   ó&   •K  — | ]  }‰|v –— Œ
 y ­wr   r$   rÃ   s     €r    r!   z'_is_declared_fake_ip.<locals>.<genexpr>  s   øè ø€ Ò=˜Sˆr�SŒyÑ=ùrÄ   )rÀ   r"   rŸ   r¿   s   `r    Ú_is_declared_fake_iprÊ     s$   ø€ ô 
˜Ó	€BÜÓ=Ô$:Ó$<Ô=Ó=Ð=r%   c                 óÐ   — t        | «      } | j                  xsN | j                  xs@ | j                  xs2 | j                  xs$ | j
                  xs | j                  xs | t        v S )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Ó     sk   € ô 
˜Ó	€BØ�M‰Mò L˜RŸ^™^ò L¨r×/?Ñ/?ò LÀ2Ç>Á>ò LØ�‰òLØ"$×"3Ñ"3òLØ79¼^Ð7KðMr%   c                 ó.  — 	 t        t        | «      j                  «      }|sy|t        v rt        j                  d|«       yt        |«      }|�#t        |«      rt        j                  d|«       yy	 t        |«      }t        |«      D ]D  \  }}}|€t        j                  d||«       Œ!t        |«      sŒ-t        j                  d||«        y y# t        j                  $ r Y yw xY w# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)	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
   r8   Ú_BLOCKED_HOSTNAMESr•   r–   r§   rÇ   r·   r³   Úgaierrorr°   r‚   Údebug)r'   r8   r¸   r¨   r@   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ÐfnÔoØÜ$ XÕ.Ü—‘Ø`ÐbjÐlrôñ ð	ð øô �‰ò 	Ùð	ûô ò ä�‰Ð=¸sÀCÔHÜûðúsR   ‚ C* £C* Á.C* Á3C Á>7C* Â6C* ÃC* ÃC'Ã$C* Ã&C'Ã'C* Ã*	DÃ3DÄDr4   c                 ó    — |dk(  xr | t         v S )zGReturn True when a trusted HTTPS hostname may bypass IP-class blocking.r   )Ú_TRUSTED_PRIVATE_IP_HOSTS)r8   r4   s     r    Ú_allows_private_ip_resolutionrÝ   D  s   € à�WÑÒF Ô-FÐ!FÐFr%   Úallow_privatec                 óN   — t        | «      ry|st        | «      rt        | «      syy)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  s'   € ô ˜RÔ Ø'Ùœ^¨BÔ/Ô8LÈRÔ8PØ)Ør%   c                 óš  — 	 t        | «      }t        |j                  «      }|j                  xs dj	                  «       j                  «       }|t        vrt        j                  d|xs d«       y|sy|t        v rt        j                  d|«       yt        «       }t        ||«      }|xs |}	 t        |«      }t%        |«      D ]I  \  }}	}
|
€t        j                  d
||«        yt'        |
|«      }|€Œ1t        j                  d|||	«        y |rt        j#                  d|«       y|rt        j#                  d|«       y# t        j                  $ rF t        |«      €"t!        «       rt        j#                  d|«       Y yt        j                  d	|«       Y yw xY w# t(        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)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.rr   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¤   r8   r4   r0   r5   r6   r•   r–   rÕ   ro   rÝ   r·   r³   rÖ   r§   r&   r×   r°   rà   r‚   )r'   rA   r8   r4   Úallow_all_privateÚallow_private_iprÞ   r¨   r@   r¯   r¸   ÚreasonrÙ   s                r    Úis_safe_urlrå   S  s¼  € ð/Ü˜#“ˆÜ& v§¡Ó7ˆØ—-‘-Ò% 2×,Ñ,Ó.×4Ñ4Ó6ˆØœÑ&Ü�N‰NÐKÈVÒM`ÐW`ÔaØÙØð Ô)Ñ)Ü�N‰NÐEÀxÔPØÜ6Ó8ÐÜ8¸À6ÓJÐØ)Ò=Ð-=ˆð	Ü$ XÓ.ˆIô  2°)Ó<ò 	‰OˆC�˜ØˆzÜ—‘Ð^Ð`cÐemÔnÙÜ.¨r°=ÓAˆFØÑ!Ü—‘Ð@À&È(ÐTZÔ[Ùð	ñ Ü�L‰LÐfÐhpÔqð ñ Ü�L‰LÐ\Ð^fÔgØøô1 �‰ò 	ô
 ˜Ó"Ð*Ô/CÔ/EÜ—‘ØsØôñ Ü�N‰NÐNÐPXÔYÙð	ûô2 ò ä�‰ÐNÐPSÐUXÔYÜûðúsr   ‚A.F  Á1F  Á4F  ÂF  Â0E Â;,F  Ã(F  Ã7F  ÄF  Ä+F  Å>FÆF  ÆFÆF  ÆFÆF  Æ 	G
Æ)GÇG
c              ƒ   óR   K  — t        j                  t        | «      ƒ d{  –—† S 7 Œ­w)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                   ó   — e Zd ZdZy)ÚSSRFConnectionBlockedzGRaised when connect-time DNS resolution violates the URL safety policy.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r$   r%   r    rì   rì   Ž  s   „ ÚQr%   rì   c           	      ó"  — t        | «      }|st        d«      ‚|t        v rt        d|› �«      ‚t        «       xs t	        ||«      }	 t        ||«      }g }t        |«      D ]q  \  }}	}
|
€t        d|›d|› �«      t        |	›d�«      ‚t        |
|«      }|�t        d|› d	|› d
|	› �«      ‚|	|vsŒNt        |«      t        k  sŒa|j                  |	«       Œs |st        d|› �«      ‚|S # t        j                  $ r}t        d|› �«      |‚d}~ww xY w)a  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Õ   ro   rÝ   r·   r³   rÖ   r°   r3   rà   ÚlenÚ_MAX_SSRF_CONNECT_IPSr˜   )r    r±   r4   r8   rÞ   r¨   rÙ   Úsafe_ipsr@   r¯   r¸   rä   s               r    Ú_resolved_http_connect_ipsrõ   ’  s`  € ô # 4Ó(€HÙÜ#Ð$IÓJÐJØÔ%Ñ%Ü#Ð&LÈXÈJÐ$WÓXÐXÜ.Ó0ÒcÔ4QÐRZÐ\bÓ4c€MðiÜ  ¨4Ó0ˆ	ð €HÜ-¨iÓ8ò 	$‰ˆˆV�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Õ#ð	$ñ Ü#Ð&UÐV^ÐU_Ð$`ÓaÐaØ€Oøô �?‰?ò iÜ#Ð&SÐT\ÐS]Ð$^Ó_ÐehÐhûðiús   ÁC' Ã'DÃ:D	Ä	Dc            	       ó”   — e Zd ZdZdedefd„Zdededee   fd„Z	e
defd	„«       Ze
ded
edz  defd„«       Zddededz  dedefd„Zy)Ú_SSRFGuardedBackendBasea  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.ÚbackendÚschemes_by_origin_varc                 ó    — || _         || _        y r   )Ú_backendÚ_schemes_by_origin_var)Úselfrø   rù   s      r    Ú__init__z _SSRFGuardedBackendBase.__init__µ  s   € ØˆŒØ&;ˆÕ#r%   r    r±   r   c                 óŠ   — | j                   j                  i «      j                  ||f«      xs	 |dk(  rdnd}t        |||«      S )Ni»  r   r   )rü   r   rõ   )rý   r    r±   r4   s       r    Ú_connect_ipsz$_SSRFGuardedBackendBase._connect_ips¹  sG   € Ø×,Ñ,×0Ñ0°Ó4×8Ñ8¸$À¸ÓFÒnÐVZÐ^aÒVaÉ7ÐgmˆÜ)¨$°°fÓ=Ð=r%   c                  ó:   — dd l } | j                  | j                  fS )Nr   )ÚhttpcoreÚConnectErrorÚConnectTimeout)r  s    r    Ú_connect_errorsz'_SSRFGuardedBackendBase._connect_errors½  s   € ãØ×%Ñ% x×'>Ñ'>Ð?Ð?r%   Úlast_excNc                 ó&   — |�|S t        d| › �«      S )Nz2Blocked request - DNS returned no usable IPs for: ©rì   )r    r  s     r    Ú_no_usable_ipsz&_SSRFGuardedBackendBase._no_usable_ipsÂ  s"   € àÐØˆOÜ$Ð'YÐZ^ÐY_Ð%`ÓaÐar%   r=   ÚtimeoutÚsocket_optionsc                 ó   — t        d«      ‚©Nz5Blocked Unix socket connection in SSRF-safe transportr  ©rý   r=   r
  r  s       r    Úconnect_unix_socketz+_SSRFGuardedBackendBase.connect_unix_socketÈ  s   € Ü#Ð$[Ó\Ð\r%   ©NN)rí   rî   rï   rð   r   rþ   r/   r¾   r“   r   Ústaticmethodr”   r  r‚   r	  Úfloatr  r$   r%   r    r÷   r÷   °  s¶   „ ñ_ð< ð <¸Có <ð> ð >¨Cð >°D¸±Ió >ð ð@˜Uò @ó ð@ð ðb˜Sð b¨I¸Ñ,<ð bÀò bó ðbñ
]¨ð ]°e¸d±lð ]Ð[^ð ]Ðjmô ]r%   r÷   c                   ó†   ‡ — e Zd Zdefˆ fd„Z	 	 ddedededz  dedz  ded	efd
„Zddededz  ded	efd„Z	ded	dfd„Z
ˆ xZS )Ú_SSRFGuardedAsyncNetworkBackendrù   c                 ó<   •— ddl m} t        ‰| �   |«       |«       y )Nr   )ÚAutoBackend)Úhttpcore._backends.autor  Úsuperrþ   )rý   rù   r  Ú	__class__s      €r    rþ   z(_SSRFGuardedAsyncNetworkBackend.__init__Í  ó   ø€ Ý7Ü‰Ñ™›Ð(=Õ>r%   Nr    r±   r
  Úlocal_addressr  r   c              ƒ   ó.  K  — d }t        j                  | j                  ||«      ƒ d {  –—† D ],  }	 | j                  j	                  |||||¬«      ƒ d {  –—† c S  | j                  ||«      ‚7 ŒE7 Œ# | j                  «       $ r}|}Y d }~Œ_d }~ww xY w­w©N)r
  r  r  )rç   rè   r   rû   Úconnect_tcpr  r	  ©	rý   r    r±   r
  r  r  r  r¸   rÙ   s	            r    r  z+_SSRFGuardedAsyncNetworkBackend.connect_tcpÑ  s¦   è ø€ à%)ˆÜ×)Ñ)¨$×*;Ñ*;¸TÀ4ÓH×Hò 	ˆBðØ!Ÿ]™]×6Ñ6Ø˜ g¸]Ð[ið 7ó k÷ kò kð	ð ×!Ñ! $¨Ó1Ð1ð Iøðkùà×'Ñ'Ó)ò Ø•ûðüsJ   ‚'B©A/ªB²#A3ÁA1ÁA3ÁBÁ1A3Á3BÂBÂBÂBÂBr=   c              ƒ   ó    K  — t        d«      ‚­wr  r  r  s       r    r  z3_SSRFGuardedAsyncNetworkBackend.connect_unix_socketÜ  s   è ø€ Ü#Ð$[Ó\Ð\ùs   ‚Úsecondsc              ƒ   óV   K  — | j                   j                  |«      ƒ d {  –—†  y 7 Œ­wr   ©rû   Úsleep©rý   r!  s     r    r$  z%_SSRFGuardedAsyncNetworkBackend.sleepß  s   è ø€ Ø�m‰m×!Ñ! 'Ó*×*Ò*ús   ‚)¡'¢)©NNNr  )rí   rî   rï   r   rþ   r/   r¾   r  r  r  r$  Ú__classcell__©r  s   @r    r  r  Ì  s’   ø„ ð?¨cõ ?ð OSØRVñ	2 cð 	2°ð 	2¸uÀt¹|ð 	2Ø),¨t©ð	2ØLOð	2Ø[^ó	2ñ]¨cð ]¸EÀD¹Lð ]Ðadð ]Ðpsó ]ð+ 5ð +¨T÷ +r%   r  c                   óf   ‡ — e Zd Zdefˆ fd„Z	 	 ddedededz  dedz  ded	efd
„Zded	dfd„Z	ˆ xZ
S )Ú_SSRFGuardedNetworkBackendrù   c                 ó<   •— ddl m} t        ‰| �   |«       |«       y )Nr   )ÚSyncBackend)Úhttpcore._backends.syncr,  r  rþ   )rý   rù   r,  r  s      €r    rþ   z#_SSRFGuardedNetworkBackend.__init__ä  r  r%   Nr    r±   r
  r  r  r   c                 óà   — d }| j                  ||«      D ]$  }	 | j                  j                  |||||¬«      c S  | j	                  ||«      ‚# | j                  «       $ r}|}Y d }~ŒSd }~ww xY wr  )r   rû   r  r  r	  r  s	            r    r  z&_SSRFGuardedNetworkBackend.connect_tcpè  s‡   € à%)ˆØ×#Ñ# D¨$Ó/ò 	ˆBðØ—}‘}×0Ñ0Ø˜ g¸]Ð[ið 1ó kò kð	ð ×!Ñ! $¨Ó1Ð1øð ×'Ñ'Ó)ò Ø•ûðús   ™AÁA-Á!A(Á(A-r!  c                 ó:   — | j                   j                  |«       y r   r#  r%  s     r    r$  z _SSRFGuardedNetworkBackend.sleepó  s   € Ø�‰×Ñ˜GÕ$r%   r&  )rí   rî   rï   r   rþ   r/   r¾   r  r  r$  r'  r(  s   @r    r*  r*  ã  sf   ø„ ð?¨cõ ?ð IMØLPñ	2 ð 	2¨3ð 	2¸À¹ð 	2Ø#&¨¡:ð	2ØFIð	2ØUXó	2ð%˜Uð % t÷ %r%   r*  Úrequestc                 ó®   — | j                   j                  | j                   j                  | j                   j                  }}}|r|�|t        v r||f|iS i S r   )r'   r    r±   r4   r6   )r0  r    r±   r4   s       r    Ú_origin_scheme_contextr2  ÷  sP   € Ø Ÿ™×)Ñ)¨7¯;©;×+;Ñ+;¸W¿[¹[×=OÑ=O�ˆ$€DÙ%)¨dÐ.>À6Ì]ÑCZˆT�4ˆL˜&Ð!ÐbÐ`bÐbr%   rù   c              #   ó˜   K  — | j                  t        |«      «      }	 d–— | j                  |«       y# | j                  |«       w xY w­w)zUExpose the request's origin scheme to the connect-time backend for this request only.N)Úsetr2  Úreset)rù   r0  rG   s      r    Ú_origin_scoper6  ü  sC   è ø€ ð "×%Ñ%Ô&<¸WÓ&EÓF€Eð+Ûà×#Ñ# EÕ*øÐ×#Ñ# EÕ*üs   ‚A
ž4 ¢A
´AÁA
F©Úis_asyncÚ	transportr8  c                ó¶  ‡‡
— | �t        | di «      ni }| �|j                  dd«      ry|rdnd}|j                  d«      }|�t        |d«      st        d	|› d
�«      ‚|rt        nt
        } |‰«      |_        |rdnd}t        | |d«      Š
‰
€t        d	|› d
�«      ‚dt        dt        fˆ
ˆfd„}dt        dt        fˆ
ˆfd„}	t        | ||r|n|	«       d| _	        y)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_requestr0  r   c              “   ót   •K  — t        ‰| «      5   ‰| «      ƒ d {  –—† cd d d «       S 7 Œ# 1 sw Y   y xY w­wr   ©r6  ©r0  Úhandlerù   s    €€r    Úguarded_asyncz7_install_ssrf_guard_on_transport.<locals>.guarded_async  s9   øè ø€ ÜÐ0°'Ó:ñ 	)Ù ›×(÷	)ñ 	)Ø(ø÷	)ð 	)üs    ƒ8�,œ*�, 
8ª,¬5±8c                 óX   •— t        ‰| «      5   ‰| «      cd d d «       S # 1 sw Y   y xY wr   rB  rC  s    €€r    Úguarded_syncz6_install_ssrf_guard_on_transport.<locals>.guarded_sync  s*   ø€ ÜÐ0°'Ó:ñ 	#Ù˜'“?÷	#÷ 	#ò 	#ús   Ž  )T)
Úgetattrr   Úhasattrrì   r  r*  r>  r   Úsetattrr<  )r9  rù   r8  ÚstateÚlabelÚpoolÚbackend_clsÚmethod_namerE  rG  rD  s    `        @r    Ú _install_ssrf_guard_on_transportrP    sú   ù€ ð 3<Ð2GŒG�I˜z¨2Ô.ÈR€EØÐ˜EŸI™IÐ&<¸eÔ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ð)¤Sð )¬Sö )ð#œcð #¤cö #ô ˆI�{±X¡MÀ<ÔPØ%)€IÕ"r%   Úclientc                ó†   — ddl }|rdnd}t        t        | di «      j                  d«      |j	                  |«      |¬«       y)zTGuard ``client._transport`` only; ``_mounts`` (env/explicit proxies) stay untouched.r   NÚ hermes_ssrf_async_origin_schemesÚhermes_ssrf_origin_schemesr;  Ú
_transportr7  )ÚcontextvarsrP  rH  r   Ú
ContextVar)rQ  r8  rV  Úvar_names       r    Ú_install_ssrf_guard_on_clientrY  "  sA   € ãÙ5=Ñ1ÐC_€HÜ$Ü�˜
 BÓ'×+Ñ+¨LÓ9¸;×;QÑ;QÐRZÓ;[Ðfnöpr%   Úkwargsc                  óL   — ddl } |j                  di | ¤Ž}t        |d¬«       |S )a  ``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.r   NTr7  r$   )ÚhttpxÚAsyncClientrY  ©rZ  r\  rQ  s      r    Úcreate_ssrf_safe_async_clientr_  *  s+   € ó ØˆU×ÑÑ( Ñ(€FÜ! &°4Õ8Ø€Mr%   c                  óH   — ddl } |j                  di | ¤Ž}t        |«       |S )z=Create an ``httpx.Client`` with connect-time SSRF validation.r   Nr$   )r\  ÚClientrY  r^  s      r    Úcreate_ssrf_safe_clientrb  4  s%   € ãØˆU�\‰\Ñ#˜FÑ#€FÜ! &Ô)Ø€Mr%   Úresponsec           	      ó   — t        | dd«      syt        | di «      xs i j                  d«      }|r)t        t        t        | dd«      «      t        |«      «      S t        | dd«      }|rt        |j                  «      S dS )	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'   rr   Únext_request)rH  r   r	   r/   r'   )rc  rg  rh  s      r    Úredirect_target_from_responseri  <  sy   € ô �8˜]¨EÔ2ØÜ˜ )¨RÓ0Ò6°B×;Ñ;¸JÓG€HÙÜ”sœ7 8¨U°BÓ7Ó8¼#¸h»-ÓHÐHÜ˜8 ^°TÓ:€LÙ$0Œ3ˆ|×ÑÓ Ð:°dÐ:r%   c                 ó   — t        | «      duS )zHReturn True when ``url`` carries likely credential-bearing query params.N)r_   ré   s    r    Úhas_sensitive_query_paramsrk  N  s   € ä% cÓ*°$Ð6Ð6r%   c                  ót   ‡— ddl }ddl}|j                  d«      Š G ˆfd„d|j                  «      } |di | ¤ŽS )zLReturn an httpx async transport that pins direct TCP connects to vetted IPs.r   NrS  c                   ó>   •‡ — e Zd Zdefˆ ˆfd„Zdedefˆ ˆfd„Zˆ xZS )ú2ssrf_safe_async_http_transport.<locals>._TransportÚtransport_kwargsc                 óX   •— t        ‰| �  di |¤Ž t        ‰«      | j                  _        y ©Nr$   )r  rþ   r  r=  r>  ©rý   ro  r  rù   s     €€r    rþ   z;ssrf_safe_async_http_transport.<locals>._Transport.__init__Z  s(   ø€ Ü‰GÑÑ0Ð/Ò0Ü*IØ%ó+ˆD�J‰JÕ'r%   r0  r   c              “   óÂ   •K  — ‰j                  t        |«      «      }	 t        ‰| �  |«      ƒ d {  –—† ‰j	                  |«       S 7 Œ# ‰j	                  |«       w xY w­wr   )r4  r2  r  r?  r5  ©rý   r0  rG   r  rù   s      €€r    r?  zGssrf_safe_async_http_transport.<locals>._Transport.handle_async_request`  sU   øè ø€ Ø)×-Ñ-Ô.DÀWÓ.MÓNˆEð3Ü"™WÑ9¸'ÓB×Bà%×+Ñ+¨EÕ2ð Cùà%×+Ñ+¨EÕ2üs+   ƒAŸA	 ±A²A	 µAÁA	 Á	AÁA)rí   rî   rï   r   rþ   r?  r'  ©r  rù   s   @€r    Ú
_Transportrn  Y  s'   ù„ ð	¨sö 	ð	3°cð 	3¸c÷ 	3ò 	3r%   rv  r$   )rV  r\  rW  ÚAsyncHTTPTransport©rZ  rV  r\  rv  rù   s       @r    Ússrf_safe_async_http_transportry  R  s=   ø€ ãÛà'×2Ñ2Ð3UÓVÐö3�U×-Ñ-ô 3ñ Ñ˜ÑÐr%   c                  ót   ‡— ddl }ddl}|j                  d«      Š G ˆfd„d|j                  «      } |di | ¤ŽS )zKReturn an httpx sync transport that pins direct TCP connects to vetted IPs.r   NrT  c                   ó>   •‡ — e Zd Zdefˆ ˆfd„Zdedefˆ ˆfd„Zˆ xZS )ú,ssrf_safe_http_transport.<locals>._Transportro  c                 óX   •— t        ‰| �  di |¤Ž t        ‰«      | j                  _        y rq  )r  rþ   r*  r=  r>  rr  s     €€r    rþ   z5ssrf_safe_http_transport.<locals>._Transport.__init__q  s(   ø€ Ü‰GÑÑ0Ð/Ò0Ü*DØ%ó+ˆD�J‰JÕ'r%   r0  r   c                 ó¦   •— ‰j                  t        |«      «      }	 t        ‰| �  |«      ‰j	                  |«       S # ‰j	                  |«       w xY wr   )r4  r2  r  r@  r5  rt  s      €€r    r@  z;ssrf_safe_http_transport.<locals>._Transport.handle_requestw  sI   ø€ Ø)×-Ñ-Ô.DÀWÓ.MÓNˆEð3Ü‘wÑ-¨gÓ6à%×+Ñ+¨EÕ2øÐ%×+Ñ+¨EÕ2ús	   �= ½A)rí   rî   rï   r   rþ   r@  r'  ru  s   @€r    rv  r|  p  s'   ù„ ð	¨sö 	ð	3¨#ð 	3°#÷ 	3ò 	3r%   rv  r$   )rV  r\  rW  ÚHTTPTransportrx  s       @r    Ússrf_safe_http_transportr€  i  s=   ø€ ãÛà'×2Ñ2Ð3OÓPÐö3�U×(Ñ(ô 3ñ Ñ˜ÑÐr%   )r   Nr   )\rð   rb   Úloggingr   r³   rç   r1   Ú
contextlibr   Útypingr   r   Úurllib.parser   r   r   r	   r
   r   r   Úhermes_constantsr   Úutilsr   Ú	getLoggerrí   r•   r#   Ú	frozensetr6   r½   rº   Ú
_IPAddressÚboolr&   r/   rC   rZ   r_   rÕ   Ú_METADATA_V4r¦   rÅ   r”   rÆ   rÜ   ró   rc   rÒ   r¼   r—   rm   rn   rˆ   r‰   ro   rl   rŠ   r�   rŸ   r¤   r§   r°   r¾   r·   rÀ   rÇ   rÊ   rÓ   rÚ   rÝ   rà   rå   rê   r3   rì   r“   rõ   r÷   r  r*  r�   r2  r6  rP  rY  r_  rb  ri  rk  ry  r€  r¿   s   0r    ú<module>rŒ     s’  ðñ
ó Û Û 	Û Û Û 	Ý %ß  ß [× [Ñ [å 5Ý !à	ˆ×	Ñ	˜8Ó	$€ð g€Ù˜6 7Ð+Ó,€Ø×"Ñ" Y×%:Ñ%:Ñ:€
ð;˜dó ;ðg 3ð g¨3ó gñF  )ò */ó  0Ð ð[ Cð [¨H°S©Mó [ñ" Ð :¸OÐLÓMÐ ð€ñ  Ø(4Ö5 "Ð€Y×Ñ˜"ÕÒ5Ø6BÖC°Ð€y×Ñ˜I¨™NÕ+ÒCñDà€y×Ñ˜OÓ,Ð-ñ.óÐ ñ !Ñ oÐBnÔ oÓoÐ ñ &Ð'@Ð&AÓBÐ ØÐ ð &�×%Ñ% oÓ6€ð
 0˜9×/Ñ/Ð0AÓBÐ ñ "'ñ 'ð Iô 'ó "Ð ð 2>Ñ .Ð Ð.Ø,5Ñ )Ð Ð)ð
! Dó 
!ð Tó ó& ð ó ð>" ó "ð4˜h s™mð 4°ó 4ð˜ð  ¨Ñ 4ó ð- #ó -ñT˜3ð T h¨s¡mó Tð
�zð 
 jó 
ð[˜jð [¨Tó [ð
>˜Zð >¨Dó >ðM�zð M dó Mð$˜sð $ tó $ðNG¨Cð G¸ð GÀó Gð
 *ð ¸Tð ÀhÈsÁmó ð3�Sð 3˜Tó 3ðl5 ð 5¨ó 5ô
R˜Jô Rð Sð °ð ¸Sð ÀTÈ#ÁYó ÷<]ñ ]ô8+Ð&=ô +ô.%Ð!8ô %ð(c Cð c¨D°°s¸C°x±À#Ð1EÑ,Fó cð
 ð+¨ð +°sò +ó ð+ð fkò *°ð *ÈCð *Ð^bð *Ðosó *ð8 DIò p¨#ð p¸Dð pÈTó pð¨Cð °Có ð cð ¨có ð
;¨Cð 
;°H¸S±Mó 
;ð$7 Cð 7¨Dó 7ð ¨Sð  °Só  ð.  sð  ¨sô  ùò{ 6ùÚCs   Â3JÃJ#
