+
    „WÝj  ã                  ó  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIHtH	t	H
t
Ht ^t]P                  ! 4       t/ tR]R&   RsR]R&   RtRt ! R	 R
]4      tRRRR/R R lltR R ltR R ltR R ltR R ltR R ltR# )u�  WS-upgrade auth credentials for gated mode.

Browsers cannot set ``Authorization`` on a WebSocket upgrade, and gated mode has no token
injected into the SPA, so two credential shapes exist: (1) single-use browser tickets
(``mint_ticket`` / ``consume_ticket``) fetched via authenticated ``POST /api/auth/ws-ticket`` and
passed as ``?ticket=`` on the upgrade â€” 30 s TTL, a leak is uninteresting; (2) a process-lifetime
internal credential (``internal_ws_credential`` / ``consume_internal_credential``) for
*server-spawned* WS clients (the embedded-TUI PTY child on ``/api/ws`` + ``/api/pub``), which
reuse their attach URL on every reconnect, possibly >30 s after boot â€” minted once, never expires,
multi-use, never injected into any HTML/SPA (leaves the process only via the child's environment,
so browser XSS cannot read it; grants no more than a ticket). In-memory; ``time.time`` patchable.
)ÚannotationsN)ÚAnyÚDictÚOptionalÚTuplez%dict[str, tuple[int, dict[str, Any]]]Ú_ticketszOptional[str]Ú_internal_credentialzserver-internalc                  ó   € ] tR t^ tRtRtR# )ÚTicketInvalidz-Ticket missing, expired, or already consumed.© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r   ó    ÚXC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_cli\dashboard_auth\ws_tickets.pyr
   r
       s   † Ý7r   r
   ÚissuerÚ Úextrac          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )é   Úuser_idÚstrÚproviderr   r   zOptional[dict[str, Any]]Úreturnr   )Úformats   "r   Ú__annotate__r   $   s1   € ÷ ñ ˜Cð ¨3ð ¸ð Ø/ðØ;>ñr   c           	     óx  € \         P                  ! ^ 4      pRV RVR\        \        P                  ! 4       4      /T;'       g    / CpV'       d   W%R&   \        ;_uu_ 4        \        \        P                  ! 4       4      \
        ,           V3\        V&   \        4        RRR4       V#   + '       g   i     T# ; i)a=  One-shot base64url ticket (32 random bytes) bound to this identity; ``consume_ticket``
hands the ``info`` dict back to the WS handler. ``extra`` rides along for routes that need
server-chosen context (the Bot Desktop bridge pins the RFB socket's profile home here so a
client can never pick another profile's screen).r   r   Ú	minted_atr   N)ÚsecretsÚtoken_urlsafeÚintÚtimeÚ_lockÚTTL_SECONDSr   Ú_gc_expired_locked)r   r   r   r   ÚticketÚinfos   $$$$  r   Úmint_ticketr*   $   s�   € ô ×"Ò" 2Ó&€FØ�w 
¨H°kÄ3ÄtÇyÂyÃ{ÓCSÐeÐX]×XcÐXcÐacÐe€DßØˆX‰ß	ŽÜ¤§	¢	£Ó,¬{Õ:¸DÐAŒ�ÑÜÔ÷ 
ð €M÷ 
Žð €Mús   Á!=B(Â(B9	c               ó    € V ^8„  d   QhRRRR/# )r   r(   r   r   údict[str, Any]r   )r   s   "r   r   r   4   s   € ÷ ñ ˜3ð  >ñ r   c                óJ  € \        \        P                  ! 4       4      p\        ;_uu_ 4        \        P	                  V R4      pVf)   V '       d   V R,          R,           MRp\        RV 24      hVw  rEWA8  d   \        R4      hVuuRRR4       #   + '       g   i     R# ; i)zYValidate and consume (single-use). Raises :class:`TicketInvalid` on missing/expired/used.N:Né   Nu   â€¦z<empty>zunknown ticket: Úexpired)r#   r$   r%   r   Úpopr
   )r(   ÚnowÚentryÚ	truncatedÚ
expires_atr)   s   &     r   Úconsume_ticketr5   4   sy   € ä
Œd�iŠi‹kÓ
€Cß	ŽÜ—‘˜V TÓ*ˆØŠ=ç06˜ � eÖ+¸IˆIÜÐ"2°9°+Ð >Ó?Ð?Ø Ñˆ
ØÔÜ 	Ó*Ð*Ø÷ 
��‹ús   ­"BÁ6BÂB"	c               ó   € V ^8„  d   QhRR/# ©r   r   ÚNoner   )r   s   "r   r   r   C   s   € ÷ ñ ˜Dñ r   c                 óô   € \        \        P                  ! 4       4      p \        P                  4        UUUu. uF  w  pw  r#W 8  g   K  VNK  	  uppp F  p\        P	                  VR4       K  	  R# u upppi )z1Drop expired tickets. Caller must hold ``_lock``.N)r#   r$   r   Úitemsr0   )r1   ÚtÚexpÚ_s       r   r'   r'   C   sR   € ä
Œd�iŠi‹kÓ
€CÜ#+§>¡>Ô#3ÕAÑ#3‘K�A‘x˜°s±y�aˆaÑ#3ÖAˆÜ�‰�Q˜Öó BùÔAs   ·A3Á	A3c               ó   € V ^8„  d   QhRR/# )r   r   r   r   )r   s   "r   r   r   J   s   € ÷ $ñ $ ñ $r   c                 ó¤   € \         ;_uu_ 4        \        f   \        P                  ! ^ 4      s\        uuRRR4       #   + '       g   i     R# ; i)uŸ   Process-lifetime internal WS credential, minted once. Never injected into the SPA or
returned over REST â€” only passed to a spawned child via its environment.N)r%   r   r!   r"   r   r   r   Úinternal_ws_credentialr@   J   s/   € ÷ 
ŽÜÒ'Ü#*×#8Ò#8¸Ó#<Ð Ü#÷ 
��‹ús	   �$>¾A	c               ó    € V ^8„  d   QhRRRR/# )r   Úvaluer   r   r,   r   )r   s   "r   r   r   T   s   € ÷ 
Hñ 
H sð 
H¨~ñ 
Hr   c                ó4  € \         ;_uu_ 4        \        pRRR4       V '       d   Xf   \        R4      h\        P                  ! V P                  4       VP                  4       4      '       g   \        R4      hR\        R\        /#   + '       g   i     Ly; i)zåValidate an internal credential (NOT single-use); returns the fixed server-internal
``{user_id, provider}`` info dict, mirroring ``consume_ticket``. Constant-time compare; any
value is rejected until a credential has been minted.Nzno internal credentialzinternal credential mismatchr   r   )r%   r   r
   r!   Úcompare_digestÚencodeÚINTERNAL_USER_IDÚINTERNAL_PROVIDER)rB   Úexpecteds   & r   Úconsume_internal_credentialrI   T   sl   € ÷ 
ŽÜ'ˆ÷ 
ç�HÒ$ÜÐ4Ó5Ð5Ü×!Ò! %§,¡,£.°(·/±/Ó2C×DÒDÜÐ:Ó;Ð;ØÔ'¨Ô5FÐGÐG÷ 
�ús   �BÂB	c               ó   € V ^8„  d   QhRR/# r7   r   )r   s   "r   r   r   a   s   € ÷ $ñ $˜$ñ $r   c                 óˆ   € \         ;_uu_ 4        \        P                  4        RsRRR4       R#   + '       g   i     R# ; i)z8Test-only: drop all tickets and the internal credential.N)r%   r   Úclearr   r   r   r   Ú_reset_for_testsrM   a   s%   € ÷ 
ŽÜ�‰ÔØ#Ð÷ 
��Šús	   �0°A	)Ú__conditional_annotations__r   Ú
__future__r   r!   Ú	threadingr$   Útypingr   r   r   r   r&   ÚLockr%   r   Ú__annotations__r   rF   rG   Ú	Exceptionr
   r*   r5   r'   r@   rI   rM   )rN   s   @r   Ú<module>rU      s�   øðôõ #ã Û Û ß -Ó -ð €à�ŠÓ€Ø24€Ð
/Ó 4Ø&*Ð �mÓ *ð %Ð Ø%Ð ô8�Iô 8ð¸bð Ø26÷õ õõ$õ
H÷$r   