Ë
    âß²j+H  ã                  ó¶  — U d Z ddlm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	Z	ddl
Z
ddlZddlmZmZ ddlmZ ddlmZmZmZmZmZ ddlmZmZ ddlmZmZmZmZmZm Z  dd	l!m"Z"  ejF                  d
«      Z$ e%h d£«      Z&de'd<   dZ(d*d„Z)d+d„Z*d*d„Z+d,d„Z,d-d.d„Z-d/d„Z.	 	 	 	 	 	 d0d„Z/	 	 	 	 	 	 	 	 	 	 	 	 d1d„Z0	 	 	 	 	 	 	 	 	 	 	 	 d2d„Z1ddœd3d„Z2d4d„Z3ddddœ	 	 	 	 	 	 	 d5d„Z4	 	 	 	 	 	 	 	 	 	 d6d„Z5d7d„Z6dd d!œ	 	 	 	 	 	 	 	 	 	 	 d8d"„Z7	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d9d#„Z8	 	 	 	 	 	 	 	 	 	 	 	 	 	 d:d$„Z9d;d%„Z:d d&œ	 	 	 	 	 	 	 d<d'„Z;dd(œ	 	 	 	 	 	 	 	 	 	 	 	 	 d=d)„Z<y)>a  Shared device-code / loopback-PKCE / browser / TLS helpers for interactive OAuth logins.

Split out of ``hermes_cli/auth.py`` and re-exported there; origin helpers are imported lazily
inside each function so ``hermes_cli.auth.<name>`` patches still intercept (and no import cycle).
é    )ÚannotationsN)ÚBaseHTTPRequestHandlerÚ
HTTPServer)ÚPath)ÚAnyÚCallableÚDictÚ	FrozenSetÚOptional)Úparse_qsÚurlparse)Ú	AuthErrorÚDEFAULT_NOUS_PORTAL_URLÚ%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDSÚDEVICE_CODE_GRANT_TYPEÚOAUTH_OVER_SSH_DOCS_URLÚhttpx)Úis_truthy_valuezhermes_cli.auth>   úwww-browserÚw3mÚlynxÚlinksÚbrowshÚelinksÚlinks2zFrozenSet[str]Ú_CONSOLE_BROWSER_NAMES)ÚCLOUD_SHELLÚ
CODESPACESÚCODESPACE_NAMEÚGITPOD_WORKSPACE_IDÚREPL_IDÚ
STACKBLITZc                 óœ   — t        t        j                  d«      xs- t        j                  d«      xs t        d„ t        D «       «      «      S )u;  Detect environments where loopback OAuth can't reach the local browser.

    Historically only SSH was checked, but #26923 surfaced that **browser-only remote consoles** (GCP Cloud
    Shell, GitHub Codespaces, AWS EC2 Instance Connect, Gitpod, Replit, etc.) hit the exact same problem â€”
    the user has a browser on their laptop but the loopback listener is bound on the remote VM that the
    laptop's browser can't reach. These environments typically don't set ``SSH_CLIENT`` / ``SSH_TTY``, so
    the SSH-only check left them with no guidance and no fallback.
    Ú
SSH_CLIENTÚSSH_TTYc              3  óF   K  — | ]  }t        j                  |«      –— Œ y ­w©N)ÚosÚgetenv)Ú.0Úvars     ú@/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth_device_flow.pyú	<genexpr>z%_is_remote_session.<locals>.<genexpr><   s   è ø€ Ò> #Œr�y‰y˜�~Ñ>ùs   ‚!)Úboolr(   r)   ÚanyÚ_REMOTE_IDE_ENV_VARS© ó    r,   Ú_is_remote_sessionr3   1   sC   € ô Ü
�	‰	�,Óò 	?¤2§9¡9¨YÓ#7ò 	?ÜÑ>Ô)=Ô>Ó>ó@ð @r2   c                óÎ   — | j                  «       r!| j                  «       j                  «       d   nd}t        j                  j	                  |«      j                  «       t        v S )Nr   Ú )ÚstripÚsplitr(   ÚpathÚbasenameÚlowerr   )ÚvalueÚtokens     r,   Ú_names_console_browserr=   ?   sI   € Ø(-¯©¬ˆE�K‰K‹M×ÑÓ! !Ò$¸2€EÜ�7‰7×Ñ˜EÓ"×(Ñ(Ó*Ô.DÐDÐDr2   c                 óà  — t         j                  j                  dd«      } | rt        | «      ryt        j
                  j                  d«      rNt        t         j                  j                  d«      xs t         j                  j                  d«      «      }|s| sy	 t        j                  «       }t        |dd«      xs t        |dd«      xs d}|xr t        |«       S # t        $ r Y yw xY w)	a»  Return True only when a *graphical* browser is likely to open.

    On a headless Linux box ``webbrowser.open()`` often resolves to a text-mode browser that takes
    over the terminal. Heuristics: a ``$BROWSER`` naming a console browser refuses; on Linux a
    display server (``$DISPLAY`` / ``$WAYLAND_DISPLAY``) is required unless ``$BROWSER`` is set
    (a console one already returned False, so a set ``$BROWSER`` here is graphical).
    ÚBROWSERr5   FÚlinuxÚDISPLAYÚWAYLAND_DISPLAYÚnamer9   )r(   ÚenvironÚgetr=   ÚsysÚplatformÚ
startswithr.   Ú
webbrowserÚ	ExceptionÚgetattr)Úbrowser_envÚhas_displayÚ
controllerÚ	candidates       r,   Ú_can_open_graphical_browserrP   D   sÈ   € ô —*‘*—.‘. ¨BÓ/€KÙÔ-¨kÔ:ØÜ
‡|�|×Ñ˜wÔ'Üœ2Ÿ:™:Ÿ>™>¨)Ó4ÒY¼¿
¹
¿¹ÐGXÓ8YÓZˆÙ¡;ØðÜ—^‘^Ó%ˆ
ô ˜
 F¨BÓ/Ò\´7¸:ÀzÐSUÓ3VÒ\ÐZ\€IØÒ?Ô4°YÓ?Ð@Ð@øô ò Ùðús   ÂC! Ã!	C-Ã,C-c                 óÄ   — 	 ddl } | j                  «       xs d}t        j                  d«      xs t        j                  d«      xs d}|› d|› �S # t        $ r d}Y ŒDw xY w)zWBest-effort 'user@hostname' for the SSH tunnel hint; placeholders keep it valid syntax.r   Nz<this-host>ÚUSERÚLOGNAMEz<user>ú@)ÚsocketÚgethostnameÚOSErrorr(   r)   )Ú_socketÚhostnameÚusers      r,   Ú_ssh_user_at_hostr[   [   sg   € ð!Û Ø×&Ñ&Ó(Ò9¨Mˆô �9‰9�VÓÒ@¤§	¡	¨)Ó 4Ò@¸€DØˆV�1�X�JÐÐøô ò !Ø Šð!ús   ‚A ÁAÁAc                ó”   — t        j                  t        j                  | «      «      j	                  d«      j                  d«      d d S )NÚasciiú=é€   )Úbase64Úurlsafe_b64encoder(   ÚurandomÚdecodeÚrstrip)Úlengths    r,   Ú_pkce_code_verifierrf   f   s;   € Ü×#Ñ#¤B§J¡J¨vÓ$6Ó7×>Ñ>¸wÓG×NÑNÈsÓSÐTXÐUXÐYÐYr2   c                óÌ   — t        j                  | j                  d«      «      j                  «       }t	        j
                  |«      j                  d«      j                  d«      S )Núutf-8r]   r^   )ÚhashlibÚsha256ÚencodeÚdigestr`   ra   rc   rd   )Úcode_verifierrl   s     r,   Ú_pkce_code_challengern   j   sK   € Ü�^‰^˜M×0Ñ0°Ó9Ó:×AÑAÓC€FÜ×#Ñ# FÓ+×2Ñ2°7Ó;×BÑBÀ3ÓGÐGr2   c               óD   ‡ ‡‡— dddddœŠ G ˆˆ ˆfd„dt         «      }|‰fS )aG  Handler class for an RFC 8252 loopback redirect plus the dict it fills in.

    Only a GET on *expected_path* is accepted (anything else is a 404 and leaves the result
    untouched), so a nonce embedded in the path acts as the CSRF ``state`` for authorization
    servers that do not echo an explicit ``state`` parameter.
    N)ÚcodeÚstateÚerrorÚerror_descriptionc                  ó&   •— e Zd Zdˆ ˆˆfd„Zdd„Zy)úA_make_loopback_callback_handler.<locals>._LoopbackCallbackHandlerc                ó  •— t        | j                  «      }|j                  ‰k7  r=| j                  d«       | j                  «        | j                  j                  d«       y t        |j                  «      }‰D ]  }|j                  |d g«      d   ‰|<   Œ | j                  d«       | j                  dd«       | j                  «        ‰d   rdnd	}| j                  j                  d
‰› d|› d�j                  d«      «       y )Ni”  s
   Not found.r   éÈ   zContent-Typeztext/html; charset=utf-8rr   ÚfailedÚreceivedz<html><body><h1>z authorization z+.</h1>You can close this tab.</body></html>rh   )r   r8   Úsend_responseÚend_headersÚwfileÚwriter   ÚqueryrE   Úsend_headerrk   )ÚselfÚparsedÚparamsÚkeyÚoutcomeÚdisplay_nameÚexpected_pathÚresults        €€€r,   Údo_GETzH_make_loopback_callback_handler.<locals>._LoopbackCallbackHandler.do_GET{   sò   ø€ Ü˜dŸi™iÓ(ˆFØ�{‰{˜mÒ+Ø×"Ñ" 3Ô'Ø× Ñ Ô"Ø—
‘
× Ñ  Ô/Øä˜fŸl™lÓ+ˆFØò 9�Ø$Ÿj™j¨¨t¨fÓ5°aÑ8��s’ð9ð ×Ñ˜sÔ#Ø×Ñ˜^Ð-GÔHØ×ÑÔØ"(¨¢/‘h°zˆGØ�J‰J×ÑØ" < .°À¸yð I8ð 8ß8>¹¸w»õIr2   c                 ó   — y r'   r1   )r€   ÚformatÚargss      r,   Úlog_messagezM_make_loopback_callback_handler.<locals>._LoopbackCallbackHandler.log_message�   s   € Ør2   N)ÚreturnÚNone)rŠ   Ústrr‹   r   r�   rŽ   )Ú__name__Ú
__module__Ú__qualname__rˆ   rŒ   )r…   r†   r‡   s   €€€r,   Ú_LoopbackCallbackHandlerru   z   s   ø„ ÷	Iô(	r2   r“   )r   )r†   r…   r“   r‡   s   `` @r,   Ú_make_loopback_callback_handlerr”   o   s3   ú€ ð '+°TÀDÐ_cÑd€F÷ð Ô#9ô ð0 $ VÐ+Ð+r2   c          	     ó€   —  G d„ dt         «      }	  || |f|«      S # t        $ r} |d| › d|› d|› �|«      |‚d}~ww xY w)u³   Bind the loopback listener up front (``port=0`` = OS-assigned) so the redirect URI sent to
    the authorization server names a port we already own â€” no probe-close-rebind race.c                  ó   — e Zd ZdZy)ú8_bind_loopback_callback_server.<locals>._ReuseHTTPServerTN)r�   r‘   r’   Úallow_reuse_addressr1   r2   r,   Ú_ReuseHTTPServerr—   œ   s   „ Ø"Ñr2   r™   z"Could not bind callback server on ú:z: N)r   rW   )ÚhostÚportÚhandler_clsÚerrÚbind_failed_coder™   Úexcs          r,   Ú_bind_loopback_callback_serverr¡   •   s\   € ô#œ:ô #ðhÙ  t ¨kÓ:Ð:øÜò hÙÐ6°t°f¸A¸d¸VÀ2ÀcÀUÐKÐM]Ó^ÐdgÐgûðhús   ‘
 œ	=¥8¸=c               ó–  — t        j                  | j                  ddid¬«      }|j                  «        t	        j
                  «       t        d|«      z   }	 t	        j
                  «       |k  rk|d   s|d   r4|| j                  «        | j                  «        |j                  d¬	«       S t	        j                  d«       t	        j
                  «       |k  rŒk| j                  «        | j                  «        |j                  d¬	«        |d
|«      ‚# | j                  «        | j                  «        |j                  d¬	«       w xY w)zZServe *server* until the redirect lands in *result* or the deadline passes; always closes.Úpoll_intervalgš™™™™™¹?T)ÚtargetÚkwargsÚdaemong      @rp   rr   g      ð?)Útimeoutz7Authorization timed out waiting for the local callback.)Ú	threadingÚThreadÚserve_foreverÚstartÚtimeÚ	monotonicÚmaxÚshutdownÚserver_closeÚjoinÚsleep)Úserverr‡   Útimeout_secondsrž   Útimeout_codeÚthreadÚdeadlines          r,   Ú_serve_loopback_callbackr¸   ¥   s
  € ô
 ×Ñ V×%9Ñ%9À?ÐTWÐBXÐaeÔf€FØ
‡L�L„NÜ�~‰~Ó¤# c¨?Ó";Ñ;€Hð!Ü�n‰nÓ Ò)Ø�fŠ~ ¨¢Øð 	�‰ÔØ×ÑÔØ�‰˜CˆÕ ô	 �J‰J�sŒOô �n‰nÓ Ó)ð
 	�‰ÔØ×ÑÔØ�‰˜CˆÔ Ù
ÐGÈÓ
VÐVøð 	�‰ÔØ×ÑÔØ�‰˜CˆÕ ús   Á"D Â,,D Ä4E)Údocs_urlc               ó8  — ddl m}  |«       sy	 t        | «      }|j                  xs d|j
                  }}|dvs|syd}t        d|› d|› d	| › d
|› d|› dt        «       › d�«       |rt        d|› �«       t        dt        › d|› d�«       y# t        $ r Y yw xY w)a  Print an SSH tunnel hint when a loopback-redirect OAuth flow runs on a remote host.

    The auth server redirects the browser to ``127.0.0.1:<port>/callback``; when the browser is
    on another machine (the SSH case) the redirect needs a local port forward to reach us.
    r   )r3   Nr5   >   ú::1ú	127.0.0.1Ú	localhostz<------------------------------------------------------------ú
u1   
Remote session detected â€” SSH tunnel required
z-
Hermes is waiting for the OAuth callback on z‹
but your browser is on a different machine. Run this command
in a NEW terminal on your local machine BEFORE opening the URL:

  ssh -N -L z:127.0.0.1:ú z:

Then open the authorize URL above in your local browser.zProvider docs:      zSSH/jump-box guide: )	Úhermes_cli.authr3   r   rJ   rY   rœ   Úprintr[   r   )Úredirect_urir¹   r3   r�   r›   rœ   Údividers          r,   Ú_print_loopback_ssh_hintrÄ   ¹   sÚ   € õ 3ÙÔØðÜ˜,Ó'ˆð —‘Ò& B¨¯©ˆ$€DØÐ4Ñ4¹DØØ€GÜ	Ø
ˆWˆIÐHÈÈ	ð R7Ø7C°nð Eð �f˜K¨ v¨QÔ/@Ó/BÐ.Cð DCð		CôDñ ÜÐ$ X JÐ/Ô0Ü	Ð Ô!8Ð 9¸¸G¸9ÀBÐ
GÕHøô ò Ùðús   �B Â	BÂBc                 óš   — t         j                  dk(  r)	 ddl} t        j                  | j                  «       ¬«      S y# t        $ r Y yw xY w)zíPlatform-aware default SSL verify for httpx clients.

    On macOS with Homebrew Python the system OpenSSL cannot find the system trust store, so pin
    certifi's bundle when importable; elsewhere defer to httpx's built-in default.
    Údarwinr   N©ÚcafileT)rF   rG   ÚcertifiÚsslÚcreate_default_contextÚwhereÚImportError)rÉ   s    r,   Ú_default_verifyrÎ   Ö   sK   € ô ‡|�|�xÒð	ÛÜ×-Ñ-°W·]±]³_ÔEÐEð øô ò 	ØØð	ús   •'> ¾	A
Á	A
)ÚinsecureÚ	ca_bundleÚ
auth_statec                óZ  — ddl m} t        |t        «      r|j	                  d«      ni }t        |t        «      r|ni }| �t        | d¬«      nt        |j	                  dd«      d¬«      }|xsV |j	                  d«      xsC t        j                  d«      xs, t        j                  d	«      xs t        j                  d
«      }|ry|r]t        |«      }t        j                  j                  |«      st        j                  d|«        |«       S t        j                  |¬«      S  |«       S )Nr   )rÎ   ÚtlsF©ÚdefaultrÏ   rÐ   ÚHERMES_CA_BUNDLEÚSSL_CERT_FILEÚREQUESTS_CA_BUNDLEuJ   CA bundle path does not exist: %s â€” falling back to default certificatesrÇ   )rÀ   rÎ   Ú
isinstanceÚdictrE   r   r(   r)   r�   r8   ÚisfileÚloggerÚwarningrÊ   rË   )rÏ   rÐ   rÑ   rÎ   Ú	tls_stateÚeffective_insecureÚeffective_caÚca_paths           r,   Ú_resolve_verifyrâ   å   s  € õ 0Ü)3°JÄÔ)E�
—‘˜uÔ%È2€IÜ'¨	´4Ô8‘	¸b€Ià4<Ð4HŒ˜¨%Õ0Ü˜YŸ]™]¨:°uÓ=ÀuÔMð ð 	ò 	I�Y—]‘] ;Ó/ò 	I´2·9±9Ð=OÓ3Pò 	IÜ�9‰9�_Ó%ò	IÜ)+¯©Ð3GÓ)Hð ñ ØÙÜ�lÓ#ˆÜ�w‰w�~‰~˜gÔ&Ü�N‰NØ\Øôñ #Ó$Ð$Ü×)Ñ)°Ô9Ð9ÙÓÐr2   c                óþ   — | j                  |› d�d|i|rd|ini ¥¬«      }|j                  «        |j                  «       }g d¢}|D �cg c]	  }||vsŒ|‘Œ }}|rt        ddj	                  |«      › �«      ‚|S c c}w )zFPOST to the device code endpoint. Returns device_code, user_code, etc.z/api/oauth/device/codeÚ	client_idÚscope©Údata)Údevice_codeÚ	user_codeÚverification_uriÚverification_uri_completeÚ
expires_inÚintervalz%Device code response missing fields: z, )ÚpostÚraise_for_statusÚjsonÚ
ValueErrorr±   )	ÚclientÚportal_base_urlrä   rå   Úresponserç   Úrequired_fieldsÚfÚmissings	            r,   Ú_request_device_coderø   þ   sŸ   € ð �{‰{ØÐ
Ð1Ð2Ø˜9ÐL¹U¨'°5Ñ)9ÈÐLð ó N€Hð ×ÑÔØ�=‰=‹?€Dò€Oð *Ö;�Q¨Q°dª]ŠqÐ;€GÐ;ÙÜÐ@ÀÇÁÈ7ÓASÐ@TÐUÓVÐVØ€Kùò <s   Á		A:ÁA:c                ó@   — | xs t         j                  d«      }d|› d�S )a‚  Actionable timeout text: the usual cause is Portal sign-in failing in the browser tab.

    A bare "Timed out waiting for device authorization" gives the user nothing to act on. The most common
    cause is Portal sign-in failing in the opened browser tab (including the server-side CAPTCHA loop from
    20605), so point at the Portal login page and the retry command. See #20605.
    ú/a   Timed out waiting for device authorization.
  Portal sign-in is required before the device code can be approved.
  If the browser showed a CAPTCHA / 'You did not pass CAPTCHA' error,
  finish signing in at the Portal in a normal browser tab, then retry:
    hermes portal
  Portal login: z/login)r   rd   )ró   Úportals     r,   Ú!_nous_device_auth_timeout_messagerü     s2   € ð Ò8Ô!8×@Ñ@ÀÓE€Fð	ð
 "˜( &ð	*ð+r2   z--F)Úfailure_dashÚswallow_open_errorsc               óú   — t        «        t        d«       t        d| › �«       t        d|› �«       |sy	 t        j                  | «      }|rt        d«       yt        d|› d�«       y# t        $ r |s‚ d}Y Œ.w xY w)	a   Print the shared "To continue" device-code block and optionally open the browser.

    Callers decide *whether* to open (remote-session / graphical-browser gating differs per
    provider); *failure_dash* keeps each provider's historical hint wording.
    zTo continue:z  1. Open: z  2. If prompted, enter code: NFz#  (Opened browser for verification)z'  Could not open browser automatically z use the URL above.)rÁ   rI   ÚopenrJ   )Úverification_urlré   Úopen_browserrý   rþ   Úopeneds         r,   Ú_print_device_code_instructionsr  !  s‰   € ô 
„GÜ	ˆ.ÔÜ	ˆKÐ(Ð)Ð
*Ô+Ü	Ð*¨9¨+Ð
6Ô7ÙØðÜ—‘Ð!1Ó2ˆñ
 ÜÐ3Õ4äÐ7¸°~ÐEXÐYÕZøô ò Ù"ØØŠðús   ¶A) Á)A:Á9A:c               ó(  — t        j                  «       t        d|«      z   }|}t        j                  «       |k  r­ | «       }	|	j                  dk(  r|	j	                  «       }
 ||
«       |
S 	 |	j	                  «       }t        |j                  d«      xs d«      }|dk(  rt        j                  |«       Œ‘|dk(  r%t        |dz   d«      }t        j                  |«       Œ» ||	|«      ‚ |«       ‚# t
        $ r |	j                  «         ||	«      ‚w xY w)a^  RFC 8628 device-code polling loop shared by the Nous and xAI flows.

    ``authorization_pending`` sleeps and retries; ``slow_down`` grows the interval by 1s (cap 30s).
    Every other error, a non-JSON error body, and the deadline become provider-specific exceptions
    via the supplied factories so each caller keeps its exact error contract.
    é   rw   rr   r5   Úauthorization_pendingÚ	slow_downé   )r¬   r­   r®   Ústatus_coderð   rJ   rï   r�   rE   r²   Úmin)rî   rì   r£   Úvalidate_successÚon_non_json_errorÚon_errorÚ
on_timeoutr·   Úcurrent_intervalrô   ÚpayloadÚerror_payloadÚ
error_codes                r,   Ú_poll_device_token_genericr  ;  s  € ô �~‰~Ó¤# a¨Ó"4Ñ4€HØ$ÐÜ
�.‰.Ó
˜XÒ
%Ù“6ˆØ×Ñ 3Ò&Ø—m‘m“oˆGÙ˜WÔ%ØˆNð	.Ø$ŸM™M›OˆMô ˜×*Ñ*¨7Ó3Ò9°rÓ:ˆ
ØÐ0Ò0Ü�J‰JÐ'Ô(ØØ˜Ò$Ü"Ð#3°aÑ#7¸Ó<ÐÜ�J‰JÐ'Ô(ØÙ�x Ó/Ð/Ù
‹,Ðøô ò 	.Ø×%Ñ%Ô'Ù# HÓ-Ð-ð	.ús   Á,C/ Ã/"Dc                ó‚   ‡ ‡‡‡— dd„}d	d„}t        ˆ ˆˆˆfd„|t        dt        |t        «      «      ||d„ ˆfd„¬«      S )
zIPoll the Nous token endpoint until the user approves or the code expires.c                ó"   — d| vrt        d«      ‚y )NÚaccess_tokenz+Token response did not include access_token)rñ   )r  s    r,   Ú	_validatez"_poll_for_token.<locals>._validated  s   € Ø Ñ(ÜÐJÓKÐKð )r2   c                ó’   — ddl m}  |t        |j                  dd«      xs d«      t        |j                  d«      xs d«      «      S )Nr   )Údevice_flow_errorrr   r5   rs   zUnknown authentication error)Úhermes_cli.auth_error_copyr  r�   rE   )Ú	_responser  r  s      r,   Ú_errorz_poll_for_token.<locals>._errorh  sH   € å@Ù Ü�×!Ñ! '¨2Ó.Ò4°"Ó5Ü�×!Ñ!Ð"5Ó6ÒXÐ:XÓYó[ð 	[r2   c                 ó@   •— ‰ j                  ‰› d�t        ‰‰dœ¬«      S )Nz/api/oauth/token)Ú
grant_typerä   rè   ræ   )rî   r   )rò   rä   rè   ró   s   €€€€r,   ú<lambda>z!_poll_for_token.<locals>.<lambda>p  s.   ø€ �—‘ØÐÐ/Ð0ä4À9Ø*ñ,ð ó -€ r2   r  c                ó   — t        d«      S )Nz1Token endpoint returned a non-JSON error response)ÚRuntimeError)Ú_rs    r,   r   z!_poll_for_token.<locals>.<lambda>x  s   € ¤\Ø?ó&A€ r2   c                 ó,   •— t        t        ‰ «      «      S r'   )ÚTimeoutErrorrü   )ró   s   €r,   r   z!_poll_for_token.<locals>.<lambda>|  s   ø€ œ<Ô(IÈ/Ó(ZÓ[€ r2   )rì   r£   r  r  r  r  )r  úDict[str, Any]r�   rŽ   )r�   rJ   )r  r®   r  r   )rò   ró   rä   rè   rì   r£   r  r  s   ````    r,   Ú_poll_for_tokenr'  `  sM   û€ óLó[ô &ö	-ð
 Ü˜!œS Ô0UÓVÓWØ"¨VñAó \ô]ð ]r2   c               óš   — 	 t        | «      j                  «       j                  «       }|dk(  r|dv S |dv S # t        t        f$ r |}Y Œ w xY w)zB``input()`` a [Y/n]-style question; EOF/Ctrl-C count as *default*.Úy>   r5   r)  Úyes>   r)  r*  )Úinputr6   r:   ÚEOFErrorÚKeyboardInterrupt)ÚpromptrÕ   Úanswers      r,   Ú_prompt_yes_nor0    s\   € ðÜ�v“×$Ñ$Ó&×,Ñ,Ó.ˆð *1°Cªˆ6Ð%Ð%ÐS¸VÀ|Ð=SÐSøô Ô'Ð(ò ØŠðús   ‚'6 ¶A
Á	A
)Úshow_auth_statec               óŠ   — t        «        t        d«       |rddlm} t        d |«       › d�«       t        d|› d| › d�«       y )	NzLogin successful!r   )Údisplay_hermes_homez  Auth state: z
/auth.jsonz  Config updated: z (model.provider=ú))rÁ   Úhermes_constantsr3  )Úprovider_idÚconfig_pathr1  Ú_dhhs       r,   Ú_print_login_successr9  ˆ  sB   € ä	„GÜ	Ð
ÔÙÝ@Ü�™t›v˜h jÐ1Ô2Ü	Ð˜{˜mÐ+<¸[¸MÈÐ
KÕLr2   )Úexpired_noticec               ó6  — ddl m} 	  |«       }|j                  dd«      }t        |t        «      rM|rK ||d«      sBt        d|› d�«       t        dd	¬
«      r3 || |j                  d|«      «      }	t        | |	«       y|rt        |«       y# t        $ r Y yw xY w)uö   Offer to reuse still-valid stored OAuth credentials. Returns True when the user accepted.

    *resolve* attempts a refresh, so a resolved token should be valid â€” but double-check the
    expiry before telling the user "Login successful!".
    r   )Ú_update_config_for_providerÚapi_keyr5   é<   z	Existing z( credentials found in Hermes auth store.z!Use existing credentials? [Y/n]: r)  rÔ   Úbase_urlTF)	rÀ   r<  rE   rÙ   r�   rÁ   r0  r9  r   )
r6  ÚresolveÚis_expiringr…   Údefault_base_urlr:  r<  Úexistingr=  r7  s
             r,   Ú!_offer_existing_oauth_credentialsrD  ’  s¥   € õ <ðÙ“9ˆØ—,‘,˜y¨"Ó-ˆÜ�gœsÔ#©¹ÀGÈRÔ8PÜ�I˜l˜^Ð+SÐTÔUÜÐAÈ3ÕOÙ9Ø §¡¨jÐ:JÓ!KóM�ä$ [°+Ô>ØÙÜ�.Ô!ð øô ò ØØðús   ˆA5B Á>B Â	BÂB)r�   r.   )r;   r�   r�   r.   )r�   r�   )é@   )re   Úintr�   r�   )rm   r�   r�   r�   )r†   r�   r…   r�   r�   z3tuple[type[BaseHTTPRequestHandler], dict[str, Any]])r›   r�   rœ   rF  r�   ztype[BaseHTTPRequestHandler]rž   úCallable[..., AuthError]rŸ   r�   r�   r   )r³   r   r‡   údict[str, Any]r´   Úfloatrž   rG  rµ   r�   r�   rH  )rÂ   r�   r¹   z
str | Noner�   rŽ   )r�   úbool | ssl.SSLContext)rÏ   zOptional[bool]rÐ   úOptional[str]rÑ   zOptional[Dict[str, Any]]r�   rJ  )
rò   úhttpx.Clientró   r�   rä   r�   rå   rK  r�   r&  )ró   r�   r�   r�   )r  r�   ré   r�   r  r.   rý   r�   rþ   r.   r�   rŽ   )rî   zCallable[[], 'httpx.Response']rì   rF  r£   rF  r  z Callable[[Dict[str, Any]], None]r  z'Callable[['httpx.Response'], Exception]r  z7Callable[['httpx.Response', Dict[str, Any]], Exception]r  zCallable[[], Exception]r�   r&  )rò   rL  ró   r�   rä   r�   rè   r�   rì   rF  r£   rF  r�   r&  )r.  r�   rÕ   r�   r�   r.   )r6  r�   r7  r   r1  r.   r�   rŽ   )r6  r�   r@  zCallable[[], Dict[str, Any]]rA  zCallable[[str, int], bool]r…   r�   rB  r�   r:  rK  r�   r.   )=Ú__doc__Ú
__future__r   r`   ri   Úloggingr(   rÊ   rF   r¨   r¬   rI   Úhttp.serverr   r   Úpathlibr   Útypingr   r   r	   r
   r   Úurllib.parser   r   Úhermes_cli.auth_constantsr   r   r   r   r   r   Úutilsr   Ú	getLoggerrÜ   Ú	frozensetr   Ú__annotations__r0   r3   r=   rP   r[   rf   rn   r”   r¡   r¸   rÄ   rÎ   râ   rø   rü   r  r  r'  r0  r9  rD  r1   r2   r,   ú<module>rY     s  ðòõ #ã Û Û Û 	Û 
Û 
Û Û Û ß :Ý ß ;Õ ;ß +÷<÷ <õ "ð 
ˆ×	Ñ	Ð,Ó	-€ñ
 *3ò 4ó *Ð ˜ó ðÐ ó@óEó
Aó. ôZóHð
#,Øð#,Ø),ð#,à8ó#,ðLhØ
ðhØðhØ'CðhØMeðhàðhð óhð WØðWØ .ðWØDIðWØPhðWàðWð óWð( KOõ Ió:ð  #'À4Ø+/ñØðØ3@ðà(ðà4Ióð2ØðØ+.ðØ;>ðØGTðàóó$+ð$ W[Ø %ñ[Øð[Ø&)ð[Ø<@ð[ØPSð[àð[à*.ó[ð4"Ø
(ð"Ø9<ð"ØMPð"à6ð"ð ?ð"ð Fð	"ð
 (ð"ð
 -;ó"ðJ]Øð]Ø+.ð]Ø;>ð]ØMPð]àð]à$'ð]à,:ó]ó>Tð EJñMØðMØ#'ðMØ=AðMØNRóMð %)ñØðØ">ðà+ðà;>ðàRUðð "ðð .2ôr2   