§
    øžyjM†  ã                   óè  — U 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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j        e¦  «        Zd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 d
edefd„Z! eddh¦  «        Z" e ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «         ej#        d¦  «        h	¦  «        Z$ ej%        d¦  «         ej%        d¦  «        fZ& edh¦  «        Z'dZ( ej%        d¦  «        Z)da*da+ee,d <   defd!„Z-defd"„Z.dGd#„Z/d$ej0        ej1        z  defd%„Z2d
edefd&„Z3d'ed(edefd)„Z4d
edefd*„Z5d
edefd+„Z6 G d,„ d-e7¦  «        Z8d.ed/e9d0e:e;ee9f         ef         defd1„Z<d.ed/e9d(ede=e         fd2„Z> G d3„ d4¦  «        Z? G d5„ d6¦  «        Z@d7ede:e;ee9f         ef         fd8„ZAd9edefd:„ZBd9edefd;„ZCd<ed=eddfd>„ZDd<ed=eddfd?„ZEd@eddfdA„ZFd@eddfdB„ZGd9edefdC„ZHd9edefdD„ZIdEede	e         fdF„ZJdS )Hu«  URL safety checks â€” blocks requests to private/internal network addresses.

Prevents SSRF (Server-Side Request Forgery) where a malicious prompt or
skill could trick the agent into fetching internal resources like cloud
metadata endpoints (169.254.169.254), localhost services, or private
network hosts.

The check can be globally disabled via ``security.allow_private_urls: true``
in config.yaml for environments where DNS resolves external domains to
private/benchmark-range IPs (OpenWrt routers, corporate proxies, VPNs
that use 198.18.0.0/15 or 100.64.0.0/10).  Even when disabled, cloud
metadata hostnames (metadata.google.internal, 169.254.169.254) are
**always** blocked â€” those are never legitimate agent targets.

Limitations:
  - DNS rebinding (TOCTOU): an attacker-controlled DNS server with TTL=0
    can return a public IP for the check, then a private IP for the actual
    connection. Hermes-owned direct httpx request paths should use
    ``create_ssrf_safe_client()`` / ``create_ssrf_safe_async_client()`` so the
    same policy is applied immediately before TCP connect and the client
    connects to the validated IP while preserving Host/SNI semantics.
  - Redirect-based bypass is mitigated by httpx event hooks that re-validate
    each redirect target in vision_tools, gateway platform adapters, and
    media cache helpers. Web tools use third-party SDKs (Firecrawl/Tavily)
    where redirect handling is on their servers.
é    N)Ú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Úreturnc                  ó>   — t          d„ t          D ¦   «         ¦  «        S )z8Return True when at least one HTTP proxy env var is set.c              3   óT   K  — | ]#}t           j                             |¦  «        V — Œ$d S ©N)ÚosÚenvironÚget)Ú.0Úvs     ú6/home/ragecks/.hermes/hermes-agent/tools/url_safety.pyú	<genexpr>z'_proxy_is_configured.<locals>.<genexpr>7   s0   è è € Ð:Ð: Q�rŒz�~Š~˜aÑ Ô Ð:Ð:Ð:Ð:Ð:Ð:ó    )ÚanyÚ_PROXY_ENV_VARS© r   r   Ú_proxy_is_configuredr#   5   s   € åÐ:Ð:­/Ð:Ñ:Ô:Ñ:Ô:Ð:r   Úurlc                 ó”  — t          | t          ¦  «        s| S |                      ¦   «         }|s|S t          j        dd|¦  «        }	 t          |¦  «        }n# t          $ r |cY S w xY w|j                             ¦   «         dvr|S |j	        }|j
        }|rY	 |                     d¦  «                             d¦  «        }n# t          $ r |}Y nw xY w||k    r|                     ||d¦  «        }t          |j        d¬¦  «        }t          |j        d	¬¦  «        }t          |j        d	¬¦  «        }t'          |j        ||||f¦  «        S )
u�  Return an ASCII-safe HTTP URL for Hermes-owned URL tools.

    Browsers and HTTP clients expect URIs, but users and models often provide
    IRIs such as ``https://wttr.in/KÃ¶ln``.  Preserve URL syntax and existing
    percent escapes while encoding non-ASCII host/path/query/fragment text.
    This is intentionally for URL tool inputs only; arbitrary shell commands
    must not be rewritten.
    z ^([A-Za-z][A-Za-z0-9+.-]*://)\s+z\1>   ÚhttpÚhttpsÚidnaÚasciié   z/%:@!$&'()*+,;=)Úsafez/%:@!$&'()*+,;=?)Ú
isinstanceÚstrÚstripÚreÚsubr
   Ú
ValueErrorÚschemeÚlowerÚnetlocÚhostnameÚencodeÚdecodeÚUnicodeErrorÚreplacer   ÚpathÚqueryÚfragmentr   )	r$   ÚrawÚparsedr4   r5   Ú
ascii_hostr:   r;   r<   s	            r   Únormalize_url_for_requestr@   :   s|  € õ �c�3ÑÔð Øˆ
à
�)Š)‰+Œ+€CØð Øˆ
õ Œ&Ð4°e¸SÑ
AÔ
A€CðÝ˜#‘”ˆˆøÝð ð ð Øˆ
ˆ
ˆ
ðøøøð „}×ÒÑÔÐ$5Ð5Ð5Øˆ
àŒ]€FØŒ€HØð =ð	"Ø!Ÿš¨Ñ0Ô0×7Ò7¸Ñ@Ô@ˆJˆJøÝð 	"ð 	"ð 	"Ø!ˆJˆJˆJð	"øøøà˜Ò!Ð!Ø—^’^ H¨j¸!Ñ<Ô<ˆFå�”Ð#4Ð5Ñ5Ô5€DÝ�&”,Ð%7Ð8Ñ8Ô8€EÝ�V”_Ð+=Ð>Ñ>Ô>€Hå�v”} f¨d°E¸8ÐDÑEÔEÐEs$   ÁA ÁA&Á%A&Â(C  Ã CÃC>   ú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dS 	 t          |                      ¦   «         ¦  «        }n# t          $ r Y dS w xY w|j                             ¦   «         dvs|j        sdS t          |j        d¬¦  «        D ]3\  }}|r,t          |¦  «                             ¦   «         t          v r|c S Œ4dS )al  Return the first sensitive query parameter name in ``url``, if any.

    Used before handing URLs to third-party fetch/browser backends. Prefix-based
    token redaction catches known credential shapes; this catches opaque magic
    links, OAuth codes, signed URL signatures, and custom ``?token=...`` values
    that do not have a recognizable vendor prefix.
    ú?N>   r&   r'   T)Úkeep_blank_values)r,   r-   r
   r.   r1   r2   r3   r;   r   r   Ú_SENSITIVE_QUERY_PARAM_NAMES)r$   r>   ÚkeyÚvalues       r   Úsensitive_query_param_namer[   ‰   sÝ   € õ �c�3ÑÔð  3¨c > >ØˆtðÝ˜#Ÿ)š)™+œ+Ñ&Ô&ˆˆøÝð ð ð Øˆtˆtðøøøà„}×ÒÑÔÐ$5Ð5Ð5¸V¼\Ð5ØˆtÝ ¤ÀÐEÑEÔEð ð ‰
ˆˆUØð 	•W˜S‘\”\×'Ò'Ñ)Ô)Õ-IÐIÐIØˆJˆJˆJøØˆ4s   �!? ¿
AÁAc                 ó$   — t          | ¦  «        duS )zHReturn True when ``url`` carries likely credential-bearing query params.N)r[   ©r$   s    r   Úhas_sensitive_query_paramsr^   Ÿ   s   € å% cÑ*Ô*°$Ð6Ð6r   zmetadata.google.internalzmetadata.googz169.254.169.254z169.254.170.2z169.254.169.253zfd00:ec2::254z100.100.100.200z::ffff:169.254.169.254z::ffff:169.254.170.2z::ffff:169.254.169.253z::ffff:100.100.100.200z169.254.0.0/16z::ffff:169.254.0.0/112zmultimedia.nt.qq.com.cné   z100.64.0.0/10FÚ_cached_allow_privatec                  ó„   — t          ¦   «         �t          ¦   «         S t          rt          S dat          ¦   «         at          S )a   Return True when the user has opted out of private-IP blocking.

    Checks (in priority order):
    1. ``HERMES_ALLOW_PRIVATE_URLS`` env var  (``true``/``1``/``yes``)
    2. ``security.allow_private_urls`` in config.yaml
    3. ``browser.allow_private_urls`` in config.yaml  (legacy / backward compat)

    The single-profile result is cached for the process lifetime. Multiplexed
    profile turns bypass that process-global cache because their config root is
    context-local; ``read_raw_config()`` already provides path/mtime caching.
    NT)r   Ú_resolve_allow_private_urlsÚ_allow_private_resolvedr`   r"   r   r   Ú_global_allow_private_urlsrd   Ü   sB   € õ"  Ñ!Ô!Ð-Ý*Ñ,Ô,Ð,åð %Ý$Ð$à"ÐÝ7Ñ9Ô9ÐÝ Ð r   c                  ó  — t          j        dd¦  «                             ¦   «                              ¦   «         } | dv rdS | dv rdS 	 ddlm}  |¦   «         }|                     d	i ¦  «        }t          |t          ¦  «        r&t          |                     d
¦  «        d¬¦  «        rdS |                     di ¦  «        }t          |t          ¦  «        r&t          |                     d
¦  «        d¬¦  «        rdS n# t          $ r Y nw xY wdS )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Úallow_private_urls)ÚdefaultÚbrowser)r   Úgetenvr.   r3   Úhermes_cli.configrn   r   r,   Údictr   Ú	Exception)Úenv_valrn   ÚcfgÚsecrr   s        r   rb   rb   ø   sD  € õ ŒiÐ3°RÑ8Ô8×>Ò>Ñ@Ô@×FÒFÑHÔH€GØÐ&Ð&Ð&ØˆtØÐ&Ð&Ð&àˆuðØ5Ð5Ð5Ð5Ð5Ð5ØˆoÑÔˆà�gŠg�j "Ñ%Ô%ˆÝ�c�4Ñ Ô ð 	¥_Ø�GŠGÐ(Ñ)Ô)°5ð&
ñ &
ô &
ð 	ð �4à—'’'˜) RÑ(Ô(ˆÝ�g�tÑ$Ô$ð 	­Ø�KŠKÐ,Ñ-Ô-°uð*
ñ *
ô *
ð 	ð �4øøÝð ð ð àˆðøøøð ˆ5s   ÁAC: Â(AC: Ã:
DÄDc                  ó   — da dadS )u+   Reset the cached toggle â€” only for tests.FN)rc   r`   r"   r   r   Ú_reset_allow_private_cacher{     s   € ð $ÐØ!ÐÐÐr   Úipc                 ó.  — t          | t          j        ¦  «        rA| j        �:| j        }|j        p+|j        p$|j        p|j        p|j        p|j	        p|t          v S | j        s| j        s| j        s| j        rdS | j        s| j	        rdS | t          v rdS dS )z<Return True if the IP should be blocked for SSRF protection.NTF)r,   Ú	ipaddressÚIPv6AddressÚipv4_mappedÚ
is_privateÚis_loopbackÚis_link_localÚis_reservedÚis_multicastÚis_unspecifiedÚ_CGNAT_NETWORK)r|   Úembedded_ips     r   Ú_is_blocked_ipr‰   !  sÒ   € õ �"•iÔ+Ñ,Ô,ð /°´Ð1KØ”nˆØÔ&ð .¨+Ô*Að .ØÔ)ð.Ø-8Ô-Dð.àÔ(ð.à,7Ô,Fð.ð �~Ð-ð	/ð 
„}ð ˜œð ¨"Ô*:ð ¸b¼nð ØˆtØ	„ð ˜"Ô+ð Øˆtà	�^ÐÐØˆtØˆ5r   c                 óT  ‡	‡
— 	 t          | ¦  «        }|j        pd                     ¦   «                              ¦   «                              d¦  «        }|sdS |t
          v rt                               d|¦  «         dS 	 t          j	        |¦  «        Š	n# t          $ r dŠ	Y nw xY w‰	�H‰	t          v s t          ˆ	fd„t          D ¦   «         ¦  «        rt                               d|¦  «         dS dS 	 t          j        |dt          j        t          j        ¦  «        }n# t          j        $ r Y dS w xY w|D ]¿\  }}}}}|d	         }d
|v r|                     d
¦  «        d	         }	 t          j	        |¦  «        Š
n2# t          $ r% t                               d|d	         |¦  «         Y Œsw xY w‰
t          v s t          ˆ
fd„t          D ¦   «         ¦  «        rt                               d||¦  «          dS ŒÀdS # t(          $ r'}t                               d| |¦  «         Y d}~dS d}~ww xY w)u‡  Return True when the URL targets an always-blocked endpoint.

    This is the security floor â€” cloud metadata IPs / hostnames
    (169.254.169.254, metadata.google.internal, ECS task metadata, etc.)
    that have no legitimate agent use regardless of backend, routing, or
    the ``allow_private_urls`` toggle.  Used by callers that bypass the
    full ``is_safe_url`` check for their own reasons (e.g. hybrid cloud
    browser routing to a local Chromium sidecar for private URLs) and
    still need to enforce the non-negotiable floor before letting the
    request proceed.

    Returns True (= blocked) on:
      - Hostnames in ``_BLOCKED_HOSTNAMES``
      - IPs / networks in ``_ALWAYS_BLOCKED_IPS`` / ``_ALWAYS_BLOCKED_NETWORKS``
      - URLs whose hostname resolves to any of the above

    Returns False (= not in the always-blocked floor) on:
      - Benign public / private / loopback URLs (whether or not they'd
        be blocked by the ordinary SSRF check)
      - DNS-resolution failures for non-sentinel hostnames (these are
        someone else's problem â€” the caller's ordinary fail-closed path
        will catch them if applicable)
      - Parse errors (caller decides fail-open vs fail-closed)

    Intentionally narrower than ``is_safe_url``: only blocks the sentinel
    set, not ordinary private addresses.  Callers that want the full
    SSRF check should still use ``is_safe_url``.
    rg   ú.Fz?Blocked request to internal hostname (always-blocked floor): %sTNc              3   ó    •K  — | ]}‰|v V — Œ	d S r   r"   ©r   Únetr|   s     €r   r   z(is_always_blocked_url.<locals>.<genexpr>i  s8   øè è € ð 0ð 0Ø!��c�	ð0ð 0ð 0ð 0ð 0ð 0r   zDBlocked request to cloud metadata address (always-blocked floor): %sr   ú%u>   Unparseable IP address %r for hostname %s â€” skipping addressc              3   ó    •K  — | ]}‰|v V — Œ	d S r   r"   )r   rŽ   Úresolveds     €r   r   z(is_always_blocked_url.<locals>.<genexpr>†  s8   øè è € ð 6ð 6Ø$'�˜C�ð6ð 6ð 6ð 6ð 6ð 6r   zJBlocked request to cloud metadata address (always-blocked floor): %s -> %sz&is_always_blocked_url error for %s: %s)r	   r5   r.   r3   ÚrstripÚ_BLOCKED_HOSTNAMESÚloggerÚwarningr~   Ú
ip_addressr1   Ú_ALWAYS_BLOCKED_IPSr    Ú_ALWAYS_BLOCKED_NETWORKSÚsocketÚgetaddrinfoÚ	AF_UNSPECÚSOCK_STREAMÚgaierrorÚsplitrv   Údebug)r$   r>   r5   Ú	addr_infoÚ_familyÚ_ÚsockaddrÚip_strÚexcr|   r‘   s            @@r   Úis_always_blocked_urlr¦   7  sÜ  øø€ ð:CÝ˜#‘”ˆØ”OÐ) r×0Ò0Ñ2Ô2×8Ò8Ñ:Ô:×AÒAÀ#ÑFÔFˆØð 	Ø�5ð Õ)Ð)Ð)Ý�NŠNØQØñô ð ð �4ð	ÝÔ% hÑ/Ô/ˆBˆBøÝð 	ð 	ð 	ØˆBˆBˆBð	øøøð ˆ>ØÕ(Ð(Ð(­Cð 0ð 0ð 0ð 0Ý%=ð0ñ 0ô 0ñ -ô -Ð(õ —’ð1àñô ð ð
 �tØ�5ð	ÝÔ*Ø˜$¥Ô 0µ&Ô2Dñô ˆIˆIøõ Œð 	ð 	ð 	Ø�5�5ð	øøøð +4ð 	ð 	Ñ&ˆG�Q˜˜1˜hØ˜a”[ˆFØ�fˆ}ˆ}ØŸš cÑ*Ô*¨1Ô-�ðÝ$Ô/°Ñ7Ô7��øÝð ð ð Ý—’Ð_ÐaiÐjkÔalÐnvÑwÔwÐwØ�ðøøøð Õ.Ð.Ð.µ#ð 6ð 6ð 6ð 6Ý+Cð6ñ 6ô 6ñ 3ô 3Ð.õ —’ð7àØñ	ô ð ð �t�tð /ð ˆuøåð ð ð õ 	�ŠÐ=¸sÀCÑHÔHÐHØˆuˆuˆuˆuˆuøøøøð	øøøs’   „AG6 Á$G6 Á>B ÂG6 ÂB"ÂG6 Â!B"Â"A	G6 Ã0+D ÄG6 ÄD/Ä+G6 Ä.D/Ä/4G6 Å$E9Å8G6 Å9,F(Æ%G6 Æ'F(Æ(A	G6 Ç3G6 Ç6
H'È H"È"H'r5   r2   c                 ó    — |dk    o| t           v S )zGReturn True when a trusted HTTPS hostname may bypass IP-class blocking.r'   )Ú_TRUSTED_PRIVATE_IP_HOSTS)r5   r2   s     r   Ú_allows_private_ip_resolutionr©   š  s   € à�WÒÐF Õ-FÐ!FÐFr   c                 ó  ‡— 	 t          | ¦  «        }|j        pd                     ¦   «                              ¦   «                              d¦  «        }|j        pd                     ¦   «                              ¦   «         }|dvrt                               d|pd¦  «         dS |sdS |t          v rt                               d|¦  «         dS t          ¦   «         }t          ||¦  «        }	 t          j        |dt          j        t          j        ¦  «        }n‰# t          j        $ rw d	}	 t!          j        |¦  «         n# t$          $ r d}Y nw xY w|s,t'          ¦   «         rt                               d
|¦  «         Y d	S t                               d|¦  «         Y dS w xY w|D ]ó\  }}	}	}	}
|
d         }d|v r|                     d¦  «        d         }	 t!          j        |¦  «        Šn4# t$          $ r' t                               d|
d         |¦  «         Y  dS w xY w‰t,          v s t/          ˆfd„t0          D ¦   «         ¦  «        rt                               d||¦  «          dS |s0|s.t3          ‰¦  «        rt                               d||¦  «          dS Œô|rt                               d|¦  «         n|rt                               d|¦  «         d	S # t4          $ r'}t                               d| |¦  «         Y d}~dS d}~ww xY w)uø  Return True if the URL target is not a private/internal address.

    Resolves the hostname to an IP and checks against private ranges.
    Fails closed: DNS errors and unexpected exceptions block the request.

    When ``security.allow_private_urls`` is enabled (or the env var
    ``HERMES_ALLOW_PRIVATE_URLS=true``), private-IP blocking is skipped.
    Cloud metadata endpoints (169.254.169.254, metadata.google.internal)
    remain blocked regardless â€” they are never legitimate agent targets.
    rg   r‹   >   r&   r'   u.   Blocked request â€” unsupported URL scheme: %sz<empty>Fz(Blocked request to internal hostname: %sNTu]   DNS resolution failed for %s â€” proxy configured, allowing through for proxy-side resolutionu1   Blocked request â€” DNS resolution failed for: %sr   r�   u=   Blocked request â€” unparseable IP address %r for hostname %sc              3   ó    •K  — | ]}‰|v V — Œ	d S r   r"   r�   s     €r   r   zis_safe_url.<locals>.<genexpr>è  s'   øè è € Ð/^Ð/^¸c°°c°	Ð/^Ð/^Ð/^Ð/^Ð/^Ð/^r   z3Blocked request to cloud metadata address: %s -> %sz5Blocked request to private/internal address: %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	   r5   r.   r3   r’   r2   r”   r•   r“   rd   r©   r™   rš   r›   rœ   r�   r~   r–   r1   r#   rŸ   rž   r—   r    r˜   r‰   rv   )r$   r>   r5   r2   Úallow_all_privateÚallow_private_ipr    Ú_is_literal_ipÚfamilyr¢   r£   r¤   r¥   r|   s                @r   Úis_safe_urlr°   Ÿ  s£  ø€ ð]Ý˜#‘”ˆØ”OÐ) r×0Ò0Ñ2Ô2×8Ò8Ñ:Ô:×AÒAÀ#ÑFÔFˆØ”-Ð% 2×,Ò,Ñ.Ô.×4Ò4Ñ6Ô6ˆØÐ*Ð*Ð*Ý�NŠNÐKÈVÐM`ÐW`ÑaÔaÐaØ�5Øð 	Ø�5ð Õ)Ð)Ð)Ý�NŠNÐEÀxÑPÔPÐPØ�5õ 7Ñ8Ô8Ðå8¸À6ÑJÔJÐð	ÝÔ*¨8°T½6Ô;KÍVÔM_Ñ`Ô`ˆIˆIøÝŒð 	ð 	ð 	ð "ˆNð'ÝÔ$ XÑ.Ô.Ð.Ð.øÝð 'ð 'ð 'Ø!&���ð'øøøà!ð Õ&:Ñ&<Ô&<ð Ý—’ðAàñô ð ð
 �t�tÝ�NŠNÐNÐPXÑYÔYÐYØ�5�5ð3	øøøð6 *3ð 	ð 	Ñ%ˆF�A�q˜!˜XØ˜a”[ˆFØ�fˆ}ˆ}ØŸš cÑ*Ô*¨1Ô-�ðÝÔ)¨&Ñ1Ô1��øÝð ð ð å—’Ð^Ð`hÐijÔ`kÐmuÑvÔvÐvØ�u�u�uðøøøð Õ(Ð(Ð(­CÐ/^Ð/^Ð/^Ð/^ÕE]Ð/^Ñ/^Ô/^Ñ,^Ô,^Ð(Ý—’ØIØ˜fñô ð ð �u�uà$ð Ð-=ð Å.ÐQSÑBTÔBTð Ý—’ØKØ˜fñô ð ð �u�uøàð 		Ý�LŠLØ]Øñô ð ð ð ð 	Ý�LŠLØSØñô ð ð
 ˆtøåð ð ð õ 	�ŠÐNÐPSÐUXÑYÔYÐYØˆuˆuˆuˆuˆuøøøøð	øøøs¯   ƒBK Â"K Â&$K ÃK Ã++D ÄK ÄFÄ)D>Ä=FÄ>EÅ
FÅEÅ.FÅ;K Å>FÆK ÆFÆ4K ÇG'Ç&K Ç',HÈK ÈHÈA	K É#0K Ê<K Ë
LËK?Ë?Lc              ƒ   óF   K  — t          j        t          | ¦  «        ƒ d{V —†S )zîSame rules as :func:`is_safe_url`, but run the DNS work off the event loop.

    ``socket.getaddrinfo`` can block; call this from async code paths (gateway,
    ``web_extract_tool``, vision download hooks) instead of ``is_safe_url``.
    N)ÚasyncioÚ	to_threadr°   r]   s    r   Úasync_is_safe_urlr´   
  s-   è è € õ Ô"¥;°Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4r   c                   ó   — e Zd ZdZdS )ÚSSRFConnectionBlockedzGRaised when connect-time DNS resolution violates the URL safety policy.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r"   r   r   r¶   r¶     s   € € € € € ØQÐQÐQÐQr   r¶   ÚhostÚportÚschemes_by_originc                 óD   — |                      | |f¦  «        p	|dk    rdndS )Ni»  r'   r&   )r   )r»   r¼   r½   s      r   Ú_safe_connect_schemer¿     s+   € Ø× Ò  $¨ Ñ.Ô.ÐV¸dÀcºk¸k°7°7ÈvÐVr   c                 óP  ‡— | pd                      ¦   «                              ¦   «                              d¦  «        }|st          d¦  «        ‚|t          v rt          d|› �¦  «        ‚t          ¦   «         }t          ||¦  «        }	 t          j        ||t          j	        t          j
        ¦  «        }n*# t          j        $ r}t          d|› �¦  «        |‚d}~ww xY wg }t          ¦   «         }	|D �] \  }
}}}}|d         }d|v r|                     d¦  «        d         }	 t          j        |¦  «        Šn.# t           $ r!}t          d	|d         ›d
|› �¦  «        |‚d}~ww xY w‰t"          v s t%          ˆfd„t&          D ¦   «         ¦  «        rt          d|› d|› �¦  «        ‚|s&|s$t)          ‰¦  «        rt          d|› d|› �¦  «        ‚||	vrBt+          |¦  «        t,          k     r*|                     |¦  «         |	                     |¦  «         �Œ"|st          d|› �¦  «        ‚|S )au  Resolve and validate *host* for one HTTP connect attempt.

    Unlike :func:`is_safe_url`, this is called from the HTTP transport at the
    time the TCP socket is about to be opened.  It returns concrete IP strings
    that the transport can dial directly, closing the DNS-rebinding gap between
    pre-flight validation and connection setup for direct httpx clients.
    rg   r‹   z#Blocked request with empty hostnamez&Blocked request to internal hostname: z-Blocked request - DNS resolution failed for: Nr   r�   z)Blocked request - unparseable IP address z for hostname c              3   ó    •K  — | ]}‰|v V — Œ	d S r   r"   r�   s     €r   r   z-_resolved_http_connect_ips.<locals>.<genexpr>C  s'   øè è € Ð+ZÐ+Z¸#¨B°#¨IÐ+ZÐ+ZÐ+ZÐ+ZÐ+ZÐ+Zr   z:Blocked request to cloud metadata address during connect: z -> z<Blocked request to private/internal address during connect: z/Blocked request - DNS returned no results for: )r.   r3   r’   r¶   r“   rd   r©   r™   rš   r›   rœ   r�   Úsetrž   r~   r–   r1   r—   r    r˜   r‰   ÚlenÚ_MAX_SSRF_CONNECT_IPSÚappendÚadd)r»   r¼   r2   r5   r¬   r­   r    r¥   Úsafe_ipsÚseenr¡   r¢   r£   r¤   r|   s                 @r   Ú_resolved_http_connect_ipsrÉ     s²  ø€ ð �
˜×!Ò!Ñ#Ô#×)Ò)Ñ+Ô+×2Ò2°3Ñ7Ô7€HØð KÝ#Ð$IÑJÔJÐJàÕ%Ð%Ð%Ý#Ð$WÈXÐ$WÐ$WÑXÔXÐXå2Ñ4Ô4ÐÝ4°X¸vÑFÔFÐðÝÔ&Ø�d�FÔ,­fÔ.@ñ
ô 
ˆ	ˆ	øõ Œ?ð ð ð Ý#ØF¸HÐFÐFñ
ô 
àð	øøøøðøøøð
 €HÝ‘U”U€DØ&/ð ñ Ñ"ˆ��A�q˜(Ø˜!”ˆØ�&ˆ=ˆ=Ø—\’\ #Ñ&Ô& qÔ)ˆFð	ÝÔ% fÑ-Ô-ˆBˆBøÝð 	ð 	ð 	Ý'Øc¸HÀQ¼KÐcÐcÐYaÐcÐcñô àðøøøøð	øøøð
 Õ$Ð$Ð$­Ð+ZÐ+ZÐ+ZÐ+ZÕAYÐ+ZÑ+ZÔ+ZÑ(ZÔ(ZÐ$Ý'ØcÈXÐcÐcÐ[aÐcÐcñô ð ð !ð 	Ð)9ð 	½nÈRÑ>PÔ>Pð 	Ý'ØeÈxÐeÐeÐ]cÐeÐeñô ð ð ˜ÐÐ¥# h¡-¤-Õ2GÒ"GÐ"GØ�OŠO˜FÑ#Ô#Ð#Ø�HŠH�VÑÔÐùàð bÝ#Ð$`ÐV^Ð$`Ð$`ÑaÔaÐaØ€Os0   Â+B4 Â4CÃCÃCÄ!D6Ä6
E!Å EÅE!c                   ó‚   — e Zd Zde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
dS )Ú_SSRFGuardedAsyncNetworkBackendÚschemes_by_origin_varc                 ó>   — ddl m}  |¦   «         | _        || _        d S )Nr   )ÚAutoBackend)Úhttpcore._backends.autorÎ   Ú_backendÚ_schemes_by_origin_var)ÚselfrÌ   rÎ   s      r   Ú__init__z(_SSRFGuardedAsyncNetworkBackend.__init__W  ó/   € Ø7Ð7Ð7Ð7Ð7Ð7à#˜™œˆŒØ&;ˆÔ#Ð#Ð#r   Nr»   r¼   ÚtimeoutÚlocal_addressÚsocket_optionsr   c              ƒ   óp  K  — dd l }| j                             i ¦  «        }t          |||¦  «        }t	          j        t          |||¦  «        ƒ d {V —†}	d }
|	D ]I}	 | j                             |||||¬¦  «        ƒ d {V —†c S # |j	        |j
        f$ r}|}
Y d }~ŒBd }~ww xY w|
�|
‚t          d|› �¦  «        ‚©Nr   )rÕ   rÖ   r×   z2Blocked request - DNS returned no usable IPs for: )ÚhttpcorerÑ   r   r¿   r²   r³   rÉ   rÐ   Úconnect_tcpÚConnectErrorÚConnectTimeoutr¶   ©rÒ   r»   r¼   rÕ   rÖ   r×   rÚ   r½   r2   ÚipsÚlast_excr|   r¥   s                r   rÛ   z+_SSRFGuardedAsyncNetworkBackend.connect_tcp]  s3  è è € ð 	ˆˆˆà Ô7×;Ò;¸BÑ?Ô?ÐÝ% d¨DÐ2CÑDÔDˆÝÔ%Õ&@À$ÈÈfÑUÔUÐUÐUÐUÐUÐUÐUˆà%)ˆØð 	ð 	ˆBð
Ø!œ]×6Ò6ØØØ#Ø"/Ø#1ð 7ñ ô ð ð ð ð ð ð ð ð ð øð Ô)¨8Ô+BÐCð ð ð Ø�Ø����øøøøðøøøð ÐØˆNÝ#Ð$_ÐY]Ð$_Ð$_Ñ`Ô`Ð`s   Á$BÂBÂBÂBr:   c              ƒ   ó$   K  — t          d¦  «        ‚©Nz5Blocked Unix socket connection in SSRF-safe transport©r¶   ©rÒ   r:   rÕ   r×   s       r   Úconnect_unix_socketz3_SSRFGuardedAsyncNetworkBackend.connect_unix_socket|  s   è è € õ $Ð$[Ñ\Ô\Ð\r   Úsecondsc              ƒ   óJ   K  — | j                              |¦  «        ƒ d {V —† d S r   ©rÐ   Úsleep©rÒ   ræ   s     r   ré   z%_SSRFGuardedAsyncNetworkBackend.sleep„  s4   è è € ØŒm×!Ò! 'Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*r   ©NNN©NN©r·   r¸   r¹   r   rÓ   r-   ÚintÚfloatrÛ   rå   ré   r"   r   r   rË   rË   V  s  € € € € € ð<¨cð <ð <ð <ð <ð !%Ø$(Ø"ðað aàðað ðað ˜‘ð	að
 ˜T‘zðað ðað 
ðað að að aðD !%Ø"ð	]ð ]àð]ð ˜‘ð]ð ð	]ð
 
ð]ð ]ð ]ð ]ð+ 5ð +¨Tð +ð +ð +ð +ð +ð +r   rË   c                   ó‚   — e Zd Zde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
dS )Ú_SSRFGuardedNetworkBackendrÌ   c                 ó>   — ddl m}  |¦   «         | _        || _        d S )Nr   )ÚSyncBackend)Úhttpcore._backends.syncró   rÐ   rÑ   )rÒ   rÌ   ró   s      r   rÓ   z#_SSRFGuardedNetworkBackend.__init__‰  rÔ   r   Nr»   r¼   rÕ   rÖ   r×   r   c                 ó>  — dd l }| j                             i ¦  «        }t          |||¦  «        }t	          |||¦  «        }	d }
|	D ]C}	 | j                             |||||¬¦  «        c S # |j        |j        f$ r}|}
Y d }~Œ<d }~ww xY w|
�|
‚t          d|› �¦  «        ‚rÙ   )
rÚ   rÑ   r   r¿   rÉ   rÐ   rÛ   rÜ   rÝ   r¶   rÞ   s                r   rÛ   z&_SSRFGuardedNetworkBackend.connect_tcp�  sù   € ð 	ˆˆˆà Ô7×;Ò;¸BÑ?Ô?ÐÝ% d¨DÐ2CÑDÔDˆÝ(¨¨t°VÑ<Ô<ˆà%)ˆØð 	ð 	ˆBð
Ø”}×0Ò0ØØØ#Ø"/Ø#1ð 1ñ ô ð ð ð øð Ô)¨8Ô+BÐCð ð ð Ø�Ø����øøøøðøøøð ÐØˆNÝ#Ð$_ÐY]Ð$_Ð$_Ñ`Ô`Ð`s   ÁA)Á)BÁ:BÂBr:   c                 ó    — t          d¦  «        ‚râ   rã   rä   s       r   rå   z._SSRFGuardedNetworkBackend.connect_unix_socket®  s   € õ $Ð$[Ñ\Ô\Ð\r   ræ   c                 ó:   — | j                              |¦  «         d S r   rè   rê   s     r   ré   z _SSRFGuardedNetworkBackend.sleep¶  s   € ØŒ×Ò˜GÑ$Ô$Ð$Ð$Ð$r   rë   rì   rí   r"   r   r   rñ   rñ   ˆ  s  € € € € € ð<¨cð <ð <ð <ð <ð !%Ø$(Ø"ðað aàðað ðað ˜‘ð	að
 ˜T‘zðað ðað 
ðað að að aðD !%Ø"ð	]ð ]àð]ð ˜‘ð]ð ð	]ð
 
ð]ð ]ð ]ð ]ð%˜Uð % tð %ð %ð %ð %ð %ð %r   rñ   Úrequestc                 ój   — | j         j        }| j         j        }| j         j        }|r|�|dvri S ||f|iS )N>   r&   r'   )r$   r»   r¼   r2   )rø   r»   r¼   r2   s       r   Ú_origin_scheme_contextrú   º  sK   € ØŒ;Ô€DØŒ;Ô€DØŒ[Ô€FØð �4�< 6Ð1BÐ#BÐ#BØˆ	Ø�4ˆL˜&Ð!Ð!r   Úkwargsc                  óx   ‡— ddl }ddl}|                     d¦  «        Š G ˆfd„d|j        ¦  «        } |di | ¤ŽS )zLReturn an httpx async transport that pins direct TCP connects to vetted IPs.r   NÚ hermes_ssrf_async_origin_schemesc                   ó>   •‡ — 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                 ól   •—  t          ¦   «         j        di |¤Ž t          ‰¦  «        | j        _        d S ©Nr"   )ÚsuperrÓ   rË   Ú_poolÚ_network_backend©rÒ   r   Ú	__class__rÌ   s     €€r   rÓ   z;ssrf_safe_async_http_transport.<locals>._Transport.__init__Ë  s>   ø€ Ø�E‰GŒGÔÐ0Ð0Ð/Ð0Ð0Ð0Ý*IØ%ñ+ô +ˆDŒJÔ'Ð'Ð'r   rø   r   c              “   óü   •K  — ‰                      t          |¦  «        ¦  «        }	 t          ¦   «                              |¦  «        ƒ d {V —†	 ‰                     |¦  «         S # ‰                     |¦  «         w xY wr   )rÂ   rú   r  Úhandle_async_requestÚreset©rÒ   rø   rD   r  rÌ   s      €€r   r	  zGssrf_safe_async_http_transport.<locals>._Transport.handle_async_requestÑ  s„   øè è € Ø)×-Ò-Õ.DÀWÑ.MÔ.MÑNÔNˆEð3Ý"™WœW×9Ò9¸'ÑBÔBÐBÐBÐBÐBÐBÐBÐBà%×+Ò+¨EÑ2Ô2Ð2Ð2øÐ%×+Ò+¨EÑ2Ô2Ð2Ð2øøøs   §&A$ Á$A;)r·   r¸   r¹   r   rÓ   r	  Ú__classcell__©r  rÌ   s   @€r   Ú
_Transportrÿ   Ê  s{   øø€ € € € € ð	¨sð 	ð 	ð 	ð 	ð 	ð 	ð 	ð	3°cð 	3¸cð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3r   r  r"   )ÚcontextvarsÚhttpxÚ
ContextVarÚAsyncHTTPTransport©rû   r  r  r  rÌ   s       @r   Ússrf_safe_async_http_transportr  Ã  s|   ø€ àÐÐÐØ€L€L€Là'×2Ò2Ð3UÑVÔVÐð3ð 3ð 3ð 3ð 3ð 3ð 3�UÔ-ñ 3ô 3ð 3ð ˆ:ÐÐ˜ÐÐÐr   c                  óx   ‡— ddl }ddl}|                     d¦  «        Š G ˆfd„d|j        ¦  «        } |di | ¤ŽS )zKReturn an httpx sync transport that pins direct TCP connects to vetted IPs.r   NÚhermes_ssrf_origin_schemesc                   ó>   •‡ — 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>._Transportr   c                 ól   •—  t          ¦   «         j        di |¤Ž t          ‰¦  «        | j        _        d S r  )r  rÓ   rñ   r  r  r  s     €€r   rÓ   z5ssrf_safe_http_transport.<locals>._Transport.__init__ã  s>   ø€ Ø�E‰GŒGÔÐ0Ð0Ð/Ð0Ð0Ð0Ý*DØ%ñ+ô +ˆDŒJÔ'Ð'Ð'r   rø   r   c                 óê   •— ‰                      t          |¦  «        ¦  «        }	 t          ¦   «                              |¦  «        ‰                     |¦  «         S # ‰                     |¦  «         w xY wr   )rÂ   rú   r  Úhandle_requestr
  r  s      €€r   r  z;ssrf_safe_http_transport.<locals>._Transport.handle_requesté  sk   ø€ Ø)×-Ò-Õ.DÀWÑ.MÔ.MÑNÔNˆEð3Ý‘w”w×-Ò-¨gÑ6Ô6à%×+Ò+¨EÑ2Ô2Ð2Ð2øÐ%×+Ò+¨EÑ2Ô2Ð2Ð2øøøs   ¥ A ÁA2)r·   r¸   r¹   r   rÓ   r  r  r  s   @€r   r  r  â  s{   øø€ € € € € ð	¨sð 	ð 	ð 	ð 	ð 	ð 	ð 	ð	3¨#ð 	3°#ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3r   r  r"   )r  r  r  ÚHTTPTransportr  s       @r   Ússrf_safe_http_transportr  Û  s|   ø€ àÐÐÐØ€L€L€Là'×2Ò2Ð3OÑPÔPÐð3ð 3ð 3ð 3ð 3ð 3ð 3�UÔ(ñ 3ô 3ð 3ð ˆ:ÐÐ˜ÐÐÐr   Ú	transportrÌ   c                 ó†  ‡‡— | �t          | di ¦  «        ni }| �|                     dd¦  «        rd S |                     d¦  «        }|�t          |d¦  «        st          d¦  «        ‚t	          ‰¦  «        |_        t          | dd ¦  «        Š‰€t          d¦  «        ‚dt          d	t          fˆˆfd
„}|| _        d| _        d S )NÚ__dict__Ú_hermes_ssrf_guardedFr  r  z:Unsupported async httpx transport cannot be made SSRF-safer	  rø   r   c              “   óÐ   •K  — ‰                      t          | ¦  «        ¦  «        }	  ‰| ¦  «        ƒ d {V —†	 ‰                     |¦  «         S # ‰                     |¦  «         w xY wr   ©rÂ   rú   r
  )rø   rD   r	  rÌ   s     €€r   Úguarded_handle_async_requestzL_install_ssrf_guard_on_async_transport.<locals>.guarded_handle_async_request  s}   øè è € Ø%×)Ò)Õ*@ÀÑ*IÔ*IÑJÔJˆð	/Ø-Ð-¨gÑ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6à!×'Ò'¨Ñ.Ô.Ð.Ð.øÐ!×'Ò'¨Ñ.Ô.Ð.Ð.øøøs   §A ÁA%T)	Úgetattrr   Úhasattrr¶   rË   r  r   r	  r!  )r  rÌ   ÚstateÚpoolr$  r	  s    `   @r   Ú&_install_ssrf_guard_on_async_transportr)  ó  sõ   øø€ Ø2;Ð2G�G�I˜z¨2Ñ.Ô.Ð.ÈR€EØÐ˜EŸIšIÐ&<¸eÑDÔDÐØˆà�9Š9�WÑÔ€DØ€|�7 4Ð);Ñ<Ô<€|Ý#Ð$`ÑaÔaÐaÝ;Ð<QÑRÔR€DÔå" 9Ð.DÀdÑKÔKÐØÐ#Ý#Ð$`ÑaÔaÐað/µCð /½Cð /ð /ð /ð /ð /ð /ð /ð &B€IÔ"Ø%)€IÔ"Ð"Ð"r   c                 ó†  ‡‡— | �t          | di ¦  «        ni }| �|                     dd¦  «        rd S |                     d¦  «        }|�t          |d¦  «        st          d¦  «        ‚t	          ‰¦  «        |_        t          | dd ¦  «        Š‰€t          d¦  «        ‚dt          d	t          fˆˆfd
„}|| _        d| _        d S )Nr   r!  Fr  r  z4Unsupported httpx transport cannot be made SSRF-safer  rø   r   c                 ó¾   •— ‰                      t          | ¦  «        ¦  «        }	  ‰| ¦  «        ‰                     |¦  «         S # ‰                     |¦  «         w xY wr   r#  )rø   rD   r  rÌ   s     €€r   Úguarded_handle_requestz@_install_ssrf_guard_on_transport.<locals>.guarded_handle_request  sc   ø€ Ø%×)Ò)Õ*@ÀÑ*IÔ*IÑJÔJˆð	/Ø!�> 'Ñ*Ô*à!×'Ò'¨Ñ.Ô.Ð.Ð.øÐ!×'Ò'¨Ñ.Ô.Ð.Ð.øøøs   ¥
A ÁAT)	r%  r   r&  r¶   rñ   r  r   r  r!  )r  rÌ   r'  r(  r,  r  s    `   @r   Ú _install_ssrf_guard_on_transportr-    só   øø€ Ø2;Ð2G�G�I˜z¨2Ñ.Ô.Ð.ÈR€EØÐ˜EŸIšIÐ&<¸eÑDÔDÐØˆà�9Š9�WÑÔ€DØ€|�7 4Ð);Ñ<Ô<€|Ý#Ð$ZÑ[Ô[Ð[Ý6Ð7LÑMÔM€DÔå˜YÐ(8¸$Ñ?Ô?€NØÐÝ#Ð$ZÑ[Ô[Ð[ð/­ð /µð /ð /ð /ð /ð /ð /ð /ð  6€IÔØ%)€IÔ"Ð"Ð"r   Úclientc                 ó    — dd l }|                     d¦  «        }t          | di ¦  «        }t          |                     d¦  «        |¦  «         d S )Nr   rý   r   Ú
_transport)r  r  r%  r)  r   ©r.  r  rÌ   r'  s       r   Ú#_install_ssrf_guard_on_async_clientr2  %  sb   € ØÐÐÐà'×2Ò2Ð3UÑVÔVÐÝ�F˜J¨Ñ+Ô+€EÝ*Ø�	Š	�,ÑÔÐ!6ñô ð ð ð r   c                 ó    — dd l }|                     d¦  «        }t          | di ¦  «        }t          |                     d¦  «        |¦  «         d S )Nr   r  r   r0  )r  r  r%  r-  r   r1  s       r   Ú_install_ssrf_guard_on_clientr4  /  sb   € ØÐÐÐà'×2Ò2Ð3OÑPÔPÐÝ�F˜J¨Ñ+Ô+€EÝ$Ø�	Š	�,ÑÔÐ!6ñô ð ð ð r   c                  óF   — ddl } |j        di | ¤Ž}t          |¦  «         |S )a¢  Create an ``httpx.AsyncClient`` with connect-time SSRF validation.

    Direct HTTP(S) connections are resolved, validated, and dialed by IP at
    TCP-connect time while the original request hostname is preserved for Host,
    SNI, and certificate verification.  If httpx routes through a proxy, final
    target resolution is delegated to that configured proxy; treat the proxy as
    a trusted egress boundary.
    r   Nr"   )r  ÚAsyncClientr2  ©rû   r  r.  s      r   Úcreate_ssrf_safe_async_clientr8  9  s8   € ð €L€L€LàˆUÔÐ(Ð( Ð(Ð(€FÝ'¨Ñ/Ô/Ð/Ø€Mr   c                  óF   — ddl } |j        di | ¤Ž}t          |¦  «         |S )z=Create an ``httpx.Client`` with connect-time SSRF validation.r   Nr"   )r  ÚClientr4  r7  s      r   Úcreate_ssrf_safe_clientr;  I  s5   € à€L€L€LàˆUŒ\Ð#Ð#˜FÐ#Ð#€FÝ! &Ñ)Ô)Ð)Ø€Mr   Úresponsec           	      ó@  — t          | dd¦  «        sdS t          | di ¦  «        pi }|                     d¦  «        }|r9t          t          t          | dd¦  «        ¦  «        t          |¦  «        ¦  «        S t          | dd¦  «        }|rt          |j        ¦  «        S dS )	a©  Return the redirect target visible from inside an httpx response hook.

    In ``httpx.AsyncClient`` response event hooks, ``response.next_request`` is
    frequently ``None`` even for a genuine redirect (it is populated later by
    the redirect-following machinery). Relying on ``next_request`` alone means
    an SSRF redirect guard silently never fires: a public URL that 302s to
    ``http://169.254.169.254/`` gets followed anyway. The ``Location`` header,
    however, is already present on the response, so resolve the target from it
    first (handling relative Locations via ``urljoin``) and only fall back to
    ``next_request`` when no ``Location`` header is set.
    Úis_redirectFNÚheadersÚlocationr$   rg   Únext_request)r%  r   r   r-   r$   )r<  r?  r@  rA  s       r   Úredirect_target_from_responserB  R  s¦   € õ �8˜]¨EÑ2Ô2ð Øˆtå�h 	¨2Ñ.Ô.Ð4°"€GØ�{Š{˜:Ñ&Ô&€HØð IÝ•s�7 8¨U°BÑ7Ô7Ñ8Ô8½#¸h¹-¼-ÑHÔHÐHå˜8 ^°TÑ:Ô:€LØð %Ý�<Ô#Ñ$Ô$Ð$àˆ4r   )r   N)Krº   r~   Úloggingr   r™   r²   r/   Útypingr   r   Úurllib.parser   r   r   r   r	   r
   r   Úhermes_constantsr   Úutilsr   Ú	getLoggerr·   r”   r!   Úboolr#   r-   r@   Ú	frozensetrX   r[   r^   r“   r–   r—   Ú
ip_networkr˜   r¨   rÄ   r‡   rc   r`   Ú__annotations__rd   rb   r{   ÚIPv4Addressr   r‰   r¦   r©   r°   r´   r1   r¶   rî   ru   Útupler¿   ÚlistrÉ   rË   rñ   rú   r  r  r)  r-  r2  r4  r8  r;  rB  r"   r   r   ú<module>rP     s|  ððð ð ð6 Ð Ð Ð Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø 	€	€	€	Ø  Ð  Ð  Ð  Ð  Ð  Ð  Ð  Ø [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [Ð [à 5Ð 5Ð 5Ð 5Ð 5Ð 5Ø !Ð !Ð !Ð !Ð !Ð !à	ˆÔ	˜8Ñ	$Ô	$€ð€ð;˜dð ;ð ;ð ;ð ;ð
-F 3ð -F¨3ð -Fð -Fð -Fð -Fðn  )˜yð *ð *ð *ñ  ô  Ð ð0 Cð ¨H°S¬Mð ð ð ð ð,7 Cð 7¨Dð 7ð 7ð 7ð 7ð �YØØð ñ ô Ð ð  �iØ€IÔÐ*Ñ+Ô+Ø€IÔ˜Ñ)Ô)Ø€IÔÐ*Ñ+Ô+Ø€IÔ˜Ñ)Ô)Ø€IÔÐ*Ñ+Ô+à€IÔÐ1Ñ2Ô2Ø€IÔÐ/Ñ0Ô0Ø€IÔÐ1Ñ2Ô2Ø€IÔÐ1Ñ2Ô2ð!ñ ô Ð ð €IÔÐ)Ñ*Ô*Ø€IÔÐ1Ñ2Ô2ðÐ ð &˜IØð'ñ ô Ð ð Ð ð &�Ô% oÑ6Ô6€ð  Ð Ø#Ð �tÐ #Ð #Ñ #ð! Dð !ð !ð !ð !ð8 Tð ð ð ð ðD"ð "ð "ð "ð�yÔ,¨yÔ/DÑDð Èð ð ð ð ð,`˜sð ` tð `ð `ð `ð `ðFG¨Cð G¸ð GÀð Gð Gð Gð Gð
h�Sð h˜Tð hð hð hð hðV5 ð 5¨ð 5ð 5ð 5ð 5ðRð Rð Rð Rð R˜Jñ Rô Rð RðW˜sð W¨#ð WÀ$ÀuÈSÐRUÈXÄÐX[ÐG[ÔB\ð WÐadð Wð Wð Wð Wð8 Sð 8°ð 8¸Sð 8ÀTÈ#ÄYð 8ð 8ð 8ð 8ðv/+ð /+ð /+ð /+ð /+ñ /+ô /+ð /+ðd/%ð /%ð /%ð /%ð /%ñ /%ô /%ð /%ðd" Cð "¨D°°s¸C°x´À#Ð1EÔ,Fð "ð "ð "ð "ð ¨Sð  °Sð  ð  ð  ð  ð0  sð  ¨sð  ð  ð  ð  ð0*°cð *ÐRUð *ÐZ^ð *ð *ð *ð *ð2*°ð *ÈCð *ÐTXð *ð *ð *ð *ð2°ð ¸ð ð ð ð ð¨#ð °$ð ð ð ð ð¨Cð °Cð ð ð ð ð  cð ¨cð ð ð ð ð¨Cð °H¸S´Mð ð ð ð ð ð r   