+
    „WÝjá  ã                  ó
  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIH	t	 ]P                  ! ]4      tRt]! R4      t]! 4       tR]R&   ]! 4       tR]R&   R R	 ltR
 R ltR R ltR R ltR R ltR R ltR R ltR R ltR# )a  X-Forwarded-Prefix and public-URL resolution for reverse-proxied deploys.

Proxies mounting the dashboard at a path inject ``X-Forwarded-Prefix: /hermes``
so the backend can build prefixed URLs (Location headers, OAuth redirect_uri,
cookie Path, SPA asset URLs). An operator-declared ``HERMES_DASHBOARD_PUBLIC_URL``
/ ``dashboard.public_url`` is used verbatim for the OAuth redirect_uri instead
(relief valve for unreliable proxy header chains). Single source of truth so
the gate, routes, cookies and SPA mount agree on validation.
)ÚannotationsN)ÚOptionalé   ÚsetÚ_warned_malformed_public_urlsÚ_warned_malformed_prefixesc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
é   Úseenr   ÚkeyÚtupleÚcleanedÚstrÚmsgÚreturnÚNone© )Úformats   "ÚTC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_cli\dashboard_auth\prefix.pyÚ__annotate__r      s/   € ÷ ñ �Sð ˜uð ¨sð ¸ð Èñ ó    c                óx   € V'       d   W9   d   R # V P                  V4       \        P                  ! V.VO5!   R # ©N)ÚaddÚ_logÚwarning)r
   r   r   r   Úargss   &&&&*r   Ú
_warn_oncer      s(   € ß�c”kÙØ‡H�HˆS„MÜ‡L‚L�Ð�tÖr   c               ó$   € V ^8„  d   QhRRRRRR/# )r	   Úsourcer   Úrawr   r   r   )r   s   "r   r   r   &   s&   € ÷ Kñ K˜sð K¨ð K°ñ Kr   c                ó¤   € V'       d   VP                  4       MRp\        \        W3TRYVP                  R4      R,          ;'       g    R4       R# )z´Warn once when a non-empty public-url value was rejected (almost always a missing scheme;
silently falling back to header reconstruction can yield the wrong scheme behind a proxy).Ú u  %s is set to %r but was ignored because it is not a valid absolute URL â€” it must include an http:// or https:// scheme (e.g. https://%s). Falling back to reconstructing the OAuth redirect URI from request headers, which may produce the wrong scheme behind a reverse proxy.z://zhermes.example.comNéÿÿÿÿ)Ústripr   r   Úsplit)r   r    r   s   && r   Ú_warn_if_malformedr&   &   sI   € ÷ !ˆc�i‰iŒk b€GÜÜ%¨Ð'8¸'ð	)ð
 	˜Ÿ™ uÓ-¨bÕ1×IÐIÐ5IöKr   c               ó$   € V ^8„  d   QhRRRRRR/# )r	   r    úOptional[str]Úreasonr   r   r   r   )r   s   "r   r   r   4   s&   € ÷ bñ b =ð b¸#ð bÀ$ñ br   c                ób   € V '       d   V P                  4       MRp\        \        W!3VRW!4       R# )z@Warn once when a non-empty X-Forwarded-Prefix value is rejected.r"   zzX-Forwarded-Prefix header %r was ignored because %s. Dashboard URLs will be generated without a reverse-proxy path prefix.N)r$   r   r   )r    r)   r   s   && r   Ú_warn_if_malformed_prefixr+   4   s-   € ç ˆc�i‰iŒk b€GÜÜ" WÐ$5°wð	PØQXöbr   c               ó    € V ^8„  d   QhRRRR/# ©r	   r    r(   r   r   r   )r   s   "r   r   r   =   s   € ÷ ñ ˜-ð ¨Cñ r   c                óÎ  a€ V '       d   V P                  4       MRoS'       g   R# SP                  R4      '       g
   RS,           oSP                  R4      oRS9   gP   RS9   gI   \        ;QJ d#    V3R l\         4       F  '       g   K   RM	  RM! V3R l\         4       4      '       d   \        V R4       R# \        S4      \        8”  d   \        V R	\         R
24       R# S# )z°``"/hermes"`` form (no trailing slash) or ``""`` when unset/malformed. ``..``, ``//`` and
injection characters are rejected so a hostile proxy cannot smuggle HTML or traversal.r"   Ú/z//z..c              3  ó,   <"  € T F	  qS9   x € K  	  R # 5ir   r   )Ú.0ÚcÚps   & €r   Ú	<genexpr>Ú#normalise_prefix.<locals>.<genexpr>F   s   øé € Ð$C±]°¨!¦V³]ùó   ƒTFz3it contains a disallowed character or path sequencezit is longer than z characters)r$   Ú
startswithÚrstripÚanyÚ_REJECT_CHARSr+   ÚlenÚ_MAX_PREFIX_LENGTH)r    r3   s   &@r   Únormalise_prefixr=   =   s¥   ø€ ÷ ˆ�	‰	Œ €AßÙØ�<‰<˜×ÒØ�!�GˆØ	�‰�‹€AØˆq„y�D˜A”I§£Ô$Cµ]Ó$C§§¢Ô$Cµ]Ó$C×!CÒ!CÜ! #Ð'\Ô]ÙÜ
ˆ1ƒvÔ"Ô"Ü! #Ð);Ô<NÐ;OÈ{Ð'[Ô\ÙØ€Hr   c               ó   € V ^8„  d   QhRR/# ©r	   r   r   r   )r   s   "r   r   r   O   s   € ÷ Gñ G Cñ Gr   c                óJ   € \        V P                  P                  R4      4      # )zFNormalised ``X-Forwarded-Prefix`` from a Starlette request, or ``""``.zx-forwarded-prefix)r=   ÚheadersÚget)Úrequests   &r   Úprefix_from_requestrD   O   s   € ä˜GŸO™O×/Ñ/Ð0DÓEÓFÐFr   c               ó    € V ^8„  d   QhRRRR/# r-   r   )r   s   "r   r   r   V   s   € ÷ ñ ˜}ð °ñ r   c                ó¬  a€ V '       d   V P                  4       MRoS'       dI   \        ;QJ d#    V3R l\         4       F  '       g   K   RM	  RM! V3R l\         4       4      '       d   R#  \        P                  P                  S4      pTP                  R9  g   TP                  '       g   R# SP                  R4      #   \         d     R# i ; i)z–Cleaned ``scheme://netloc[/path]`` (trailing slash stripped) or ``""`` when
empty/malformed/injection-suspect (= fall back to request reconstruction).r"   c              3  ó,   <"  € T F	  qS9   x € K  	  R # 5ir   r   )r1   r2   Úurls   & €r   r4   Ú(_normalise_public_url.<locals>.<genexpr>Z   s   øé € Ð6© 1˜3–h«ùr6   TFr/   >   ÚhttpÚhttps)
r$   r9   r:   ÚurllibÚparseÚurlparseÚ
ValueErrorÚschemeÚnetlocr8   )r    ÚparsedrH   s   & @r   Ú_normalise_public_urlrS   V   s�   ø€ ÷ ˆ#�)‰)Œ+ "€Cß—#“#Ô6­Ó6—#—#’#Ô6­Ó6×6Ò6ÙðÜ—‘×&Ñ& sÓ+ˆð ‡}�}Ð-Ô-°V·]·]°]ÙØ�:‰:�c‹?Ðøô	 ô Úðús   Á/C ÃCÃCc               ó   € V ^8„  d   QhRR/# )r	   r   Údictr   )r   s   "r   r   r   e   s   € ÷ 8ñ 8 ñ 8r   c                 ó,  €  ^ RI Hp   T ! 4       p\        T\        4      '       d   TP                  R4      MRp\        T\        4      '       d   T# / #   \         d    / u # i ; i  \         d#   p\        P	                  RT4       / u Rp?# Rp?ii ; i)zX``dashboard`` block of config.yaml as a dict, or ``{}`` when unloadable/absent/non-dict.)Úload_configzVdashboard-auth.prefix: load_config() raised %s; falling back to env-only configurationNÚ	dashboard)Úhermes_cli.configrW   Ú	Exceptionr   ÚdebugÚ
isinstancerU   rB   )rW   ÚcfgÚexcÚsections       r   Ú_load_dashboard_sectionr`   e   sŒ   € ðÝ1ðÙ‹mˆô
 '1°´d×&;Ò&;ˆc�g‰g�kÔ"À€GÜ  ¬$×/Ò/ˆ7Ð7°RÐ7øô ô ØŠ	ðûô ô Ü�
‰
ð <Ø=@ô	Bà�	ûðús.   ‚A ‰A& ÁA#Á"A#Á&BÁ1BÂBÂBc               ó   € V ^8„  d   QhRR/# r?   r   )r   s   "r   r   r   u   s   € ÷ ñ ˜Cñ r   c                 ó  € \         P                  P                  RR4      p \        V 4      pV'       d   V# \	        RV 4       \        \        4       P                  RR4      4      p\        V4      pV'       g   \	        RV4       V# )a  Operator-declared dashboard public URL, or ``""`` (reconstruct from request). Precedence:
``HERMES_DASHBOARD_PUBLIC_URL`` env (blank counts as unset so a provisioned-but-blank secret
cannot shadow config.yaml), then ``dashboard.public_url``; malformed warns and falls through.ÚHERMES_DASHBOARD_PUBLIC_URLr"   z#HERMES_DASHBOARD_PUBLIC_URL env varÚ
public_urlz#dashboard.public_url in config.yaml)ÚosÚenvironrB   rS   r&   r   r`   )Úenv_rawÚ	env_cleanÚcfg_rawÚ	cfg_cleans       r   Úresolve_public_urlrk   u   sp   € ô �j‰j�n‰nÐ:¸BÓ?€GÜ% gÓ.€IßØÐÜÐ<¸gÔFÜÔ)Ó+×/Ñ/°¸bÓAÓB€GÜ% gÓ.€IßÜÐ@À'ÔJØÐr   )Ú"Ú'Ú<Ú>Ú Ú
ÚÚ	)Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úloggingre   Úurllib.parserL   Útypingr   Ú	getLoggerÚ__name__r   r<   Ú	frozensetr:   r   r   Ú__annotations__r   r   r&   r+   r=   rD   rS   r`   rk   )rt   s   @r   Ú<module>r~      sˆ   øðôõ #ã Û 	Û Ý à×Ò˜Ó"€ð Ð ñ ÐEÓF€ñ &)£UÐ ˜sÓ *Ù"%£%Ð ˜CÓ 'õõKõbõõ$Gõõ8÷ r   