+
    0å·j=  ã                   óT  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt]P                  ! ]
4      P                  4       P                  t]P                  P                  ^ ]! ]4      4       ^ RIt^ RIt^ RIt]P(                  tRtRt ! R R4      tR]R3R lt ! R R]P4                  4      t ! R	 R
]P4                  4      t ! R R4      t ! R R]]P4                  4      t ! R R]]P4                  4      t ! R R]P4                  4      t ]!R8X  d   ]PD                  ! 4        R# R# )z�Tests for remote access to the MCP bridge (a domain name, e.g. through frp, with a password):
python3 -m unittest scripts/test_mcp_remote.py
Nzcorrect horse battery staplezmcp.example.comc                   ó,   a € ] tR t^t o R tR tRtV tR# )ÚClockc                ó   € R V n         R# )g     @�@N©Út©Úselfs   &Ú//work/data/stt/webtt/scripts/test_mcp_remote.pyÚ__init__ÚClock.__init__   s	   € ØˆŽó    c                ó   € V P                   # ©Nr   r   s   &r	   Ú__call__ÚClock.__call__   s   € Ø�v‰vˆr   r   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__r
   r   Ú__static_attributes__Ú__classdictcell__©Ú__classdict__s   @r	   r   r      s   ø‡ € ò÷ð r   r   c                 ó¨   € \         P                  P                  R \        ./T ;'       g    / CV'       d   RV/M/ T;'       g    \	        4       R7      # )ÚhostsÚWEBTT_MCP_PASSWORD©Úclock)Ú
mcp_remoteÚRemoteAccessÚfrom_configÚHOSTr   )ÚcfgÚpasswordr   s   &&&r	   Úremoter$      sV   € Ü×"Ñ"×.Ñ.°¼$¸Ð/OÀCÇIÀIÈ2Ð/O×u}ÐRfÐhpÑQqð  DFØ5:×5EÐ5E¼e»gð /ó Gð Gr   c                   ó8   a € ] tR t^$t o R tR tR tR tRtV t	R# )Ú
ConfigTestc                ód   € V P                  \        P                  P                  R / 4      4       R # r   )ÚassertIsNoner   r   r    r   s   &r	   Ú-test_no_remote_section_means_no_remote_accessÚ8ConfigTest.test_no_remote_section_means_no_remote_access%   s#   € Ø×Ñœ*×1Ñ1×=Ñ=¸dÀBÓGÖHr   c                ó   € V P                  \        R 4      ;_uu_ 4        \        RR7       RRR4       V P                  \        R4      ;_uu_ 4        \        RR7       RRR4       R#   + '       g   i     LE; i  + '       g   i     R# ; i)r   N)r#   Ú16Úshort)ÚassertRaisesRegexÚ
ValueErrorr$   r   s   &r	   Ú'test_a_long_enough_password_is_requiredÚ2ConfigTest.test_a_long_enough_password_is_required(   s[   € Ø×#Ñ#¤JÐ0D×EÕEÜ˜DÕ!÷ Fà×#Ñ#¤J°×5Õ5Ü˜GÕ$÷ 6Ñ5÷ F×Eúç5×5Ð5ús   ŸA)ÁA<Á)A9	Á<B	c                óX  € R . /R R/R R./R \         .R^/R \         .R^ /R \         .RR/R \         .R^/R R./R R	./R R
./3
 FQ  pV P                  \        VR7      ;_uu_ 4        \        P                  P                  VR\        /4       RRR4       KS  	  R#   + '       g   i     Kh  ; i)r   zx.comzbad hostÚextraÚsession_hoursÚinsecure_httpÚyesÚtrust_localhostúlocalhost:8289ú	127.0.0.1Ú	LOCALHOST)Úmsgr   N)r!   ÚassertRaisesr/   r   r   r    ÚPASSWORD)r   Úbads   & r	   Útest_bad_sections_are_rejectedÚ)ConfigTest.test_bad_sections_are_rejected.   sÌ   € Ø˜b�M G¨WÐ#5¸À*ÀÐ7NÐQXÔ[_ÐZ`ÐbiÐklÐPmØœt˜f o°qÐ9¸GÄdÀVÈ_Ð^cÐ;dØœt˜fÐ&7¸Ð;¸gÐHXÐGYÐ=ZÐ]dÐgrÐfsÐ\tØ˜{˜mÐ,ó.ˆCð ×"Ñ"¤:°3Ð"×7Õ7Ü×'Ñ'×3Ñ3°CÐ:NÔPXÐ9YÔZ÷ 8Ñ7ó	.÷ 8×7Ð7ús   Á#'BÂB)c                ó$  € \        R RR./4      pV P                  VP                  R4      4       V P                  VP                  R4      4       V P                  VP                  R4      4       V P                  VP                  R4      4       R# )r   zMCP.example.comzb.example.com:8443zmcp.EXAMPLE.comzb.example.comzevil.comN)r$   Ú
assertTrueÚis_remote_hostÚassertFalse)r   Úrs   & r	   Ú7test_hosts_match_case_insensitively_and_with_their_portÚBConfigTest.test_hosts_match_case_insensitively_and_with_their_port6   sz   € Ü�GÐ/Ð1EÐFÐGÓHˆØ�‰˜×(Ñ(Ð):Ó;Ô<Ø�‰˜×(Ñ(Ð)=Ó>Ô?Ø×Ñ˜×)Ñ)¨/Ó:Ô;Ø×Ñ˜×)Ñ)¨*Ó5Ö6r   © N)
r   r   r   r   r)   r0   r?   rF   r   r   r   s   @r	   r&   r&   $   s    ø‡ € òIò%ò[÷7ð 7r   r&   c                   óJ   a € ] tR t^>t o R tR tR tR tR tR t	R t
RtV tR	# )
ÚSessionTestc                ó`   € \        4       V n        \        R ^/V P                  R7      V n        R# )r4   r   N)r   r   r$   rE   r   s   &r	   ÚsetUpÚSessionTest.setUp?   s"   € Ü“WˆŒ
Ü˜¨!Ð,°D·J±JÔ?ˆŽr   c                ó¼  € V P                  V P                  P                  R 4      P                  4       V P                  P                  \        4      P                  pV P                  V P                  P                  V4      4       V P                  V P                  P                  R4      4       V P                  V P                  P                  R4      4       R# )úwrong password hereÚforgedÚ N)r(   rE   ÚloginÚtokenr=   rB   ÚvalidrD   )r   rS   s   & r	   Útest_login_and_sessionÚ"SessionTest.test_login_and_sessionC   s‹   € Ø×Ñ˜$Ÿ&™&Ÿ,™,Ð'<Ó=×CÑCÔDØ—‘—‘œXÓ&×,Ñ,ˆØ�‰˜Ÿ™Ÿ™ UÓ+Ô,Ø×Ñ˜Ÿ™Ÿ™ hÓ/Ô0Ø×Ñ˜Ÿ™Ÿ™ bÓ)Ö*r   c                óh  € V P                   P                  \        4      P                  pV P                  ;P
                  R,          un        V P                  V P                   P                  V4      4       V P                  ;P
                  ^,          un        V P                  V P                   P                  V4      4       V P                   P                  \        4      P                  pV P                   P                  V4       V P                  V P                   P                  V4      4       R# )é   Ni  )
rE   rR   r=   rS   r   r   rB   rT   rD   Úlogout)r   rS   Úothers   &  r	   Ú)test_sessions_expire_and_logout_ends_themÚ5SessionTest.test_sessions_expire_and_logout_ends_themJ   sµ   € Ø—‘—‘œXÓ&×,Ñ,ˆØ�
‰
�Š˜Õ$�Ø�‰˜Ÿ™Ÿ™ UÓ+Ô,Ø�
‰
�Š˜Õ�Ø×Ñ˜Ÿ™Ÿ™ eÓ,Ô-Ø—‘—‘œXÓ&×,Ñ,ˆØ�‰�‰�eÔØ×Ñ˜Ÿ™Ÿ™ eÓ,Ö-r   c                óš  € \        \        P                  4       F7  pV P                  V P                  P                  R 4      P                  4       K9  	  V P                  P                  \        4      pV P                  VP                  R4       V P                  VP                  ^<4       V P                  ;P                  ^=,          un        V P                  V P                  P                  R 4      P                  4       V P                  V P                  P                  \        4      P                  ^x4       V P                  ;P                  ^y,          un        V P                  V P                  P                  \        4      P                  4       V P                  V P                  P                  R 4      P                  4       R# )Únopez*even the right password waits out the lockN)Úranger   ÚFREE_ATTEMPTSr(   rE   rR   rS   r=   ÚassertEqualÚretry_afterr   r   ÚassertIsNotNone)r   Ú_Úlockeds   &  r	   Ú,test_failures_lock_login_with_growing_delaysÚ8SessionTest.test_failures_lock_login_with_growing_delaysT   s  € Ü”z×/Ñ/Ö0ˆAØ×Ñ˜dŸf™fŸl™l¨6Ó2×8Ñ8Ö9ñ 1à—‘—‘œhÓ'ˆØ×Ñ˜&Ÿ,™,Ð(TÔUØ×Ñ˜×+Ñ+¨RÔ0Ø�
‰
�Š˜Õ�Ø×Ñ˜$Ÿ&™&Ÿ,™, vÓ.×4Ñ4Ô5Ø×Ñ˜Ÿ™Ÿ™¤hÓ/×;Ñ;¸SÔAØ�
‰
�Š˜Õ�Ø×Ñ˜TŸV™VŸ\™\¬(Ó3×9Ñ9Ô:Ø×Ñ˜$Ÿ&™&Ÿ,™, vÓ.×:Ñ:Ö;r   c                ój  € \        ^(4       FA  pV P                  P                  R4       V P                  ;P                  R,          un        KC  	  V P                  P                  R4       V P                  V P                  P                  \        4      P                  \        P                  4       R# )é(   r^   i'  N)
r_   rE   rR   r   r   ÚassertLessEqualr=   rb   r   ÚMAX_LOCK)r   rd   s   & r	   Útest_lock_is_cappedÚSessionTest.test_lock_is_cappeda   sm   € Ü�r–ˆAØ�F‰F�L‰L˜Ô Ø�J‰J�LŠL˜FÕ"�Lñ ð 	�‰�‰�VÔØ×Ñ˜TŸV™VŸ\™\¬(Ó3×?Ñ?Ä×ATÑATÖUr   c                ó  € V P                   P                  R 4      pR F  pV P                  W!4       K  	  V P                  R\	        RR/4      P                  R 4      4       V P                  RV P                   P                  4       4       R# )ÚtokÚSecurer5   Tú	Max-Age=0N)zmcp_session=tokÚHttpOnlyrp   zSameSite=Strictz
Path=/api;zMax-Age=7200)rE   Úcookie_headerÚassertInÚassertNotInr$   Úclear_cookie_header)r   ÚcookieÚparts   &  r	   Útest_cookie_attributesÚ"SessionTest.test_cookie_attributesh   sn   € Ø—‘×%Ñ% eÓ,ˆÛnˆDØ�M‰M˜$Ö'ñ oà×Ñ˜¤6¨?¸DÐ*AÓ#B×#PÑ#PÐQVÓ#WÔXØ�‰�k 4§6¡6×#=Ñ#=Ó#?Ö@r   c                óŠ  € V P                  V P                  P                  \        R \         24      4       V P	                  V P                  P                  \        R\         24      4       V P	                  V P                  P                  \        R4      4       V P                  V P                  P                  \        P                  4       R \         24      4       V P                  V P                  P                  RR4      R4       V P                  \        RR/4      P                  \        R\         24      4       R# )	úhttps://úhttp://zhttps://evil.comr8   zhttp://localhost:8289z'localhost is a secure context over httpr5   TN)rB   rE   Ú	origin_okr!   rD   Úupperr$   r   s   &r	   Útest_originsÚSessionTest.test_originso   sä   € Ø�‰˜Ÿ™×(Ñ(¬°¼$¸Ð/@ÓAÔBØ×Ñ˜Ÿ™×)Ñ)¬$°'¼$¸Ð0@ÓAÔBØ×Ñ˜Ÿ™×)Ñ)¬$Ð0BÓCÔDØ�‰˜Ÿ™×(Ñ(¬¯©«¸Ä$ÀÐ7HÓIÔJØ�‰˜Ÿ™×(Ñ(Ð)9Ð;RÓSÐU~ÔØ�‰œ °Ð6Ó7×AÑAÄ$È'ÔRVÐQWÐHXÓYÖZr   )r   rE   N)r   r   r   r   rL   rU   r[   rf   rl   ry   r€   r   r   r   s   @r	   rJ   rJ   >   s2   ø‡ € ò@ò+ò.ò<òVòA÷[ð [r   rJ   c                   óˆ   a € ] tR t^xt o RtRt]R 4       t]R 4       tR t	R]
RRR3R lt]]
R3R ltRR lt]
3R	 ltR
tV tR# )ÚBridgeHarnesszˆA real bridge; requests arrive from 127.0.0.1 like frp's, with the domain as Host.
Subclasses set REMOTE, the config's "remote" section.Nc                ó*  € \         P                  ! 4       V n        R V P                  RRRR\        \        \        R,          4      ./RRRRR	.R
R//RRR RRRR	.R
R//RRR RRRRRR./././p\        P                  ! V P                  P                  4      R,          pVP                  \        P                  ! V4      RR7       \        P                  ! V^ R\        /R7      V n        \"        P$                  ! ^ V P                   RRR7      V n        V P&                  P(                  ^,          ;V n        V P                   n        RV P*                   2V n        \.        P0                  ! V P&                  P2                  RR7      P5                  4        R# )r$   ÚserversÚidÚdemoÚcommandzmcp_demo_server.pyÚshÚshellÚallowÚechoÚconfirmFú	sh-remoteTÚhiddenÚcliÚnameÚwczmcp.config.jsonzutf-8)Úencodingr   ©Úenvr9   )ÚhostÚquietz
localhost:)ÚtargetÚdaemonN)ÚtempfileÚTemporaryDirectoryÚtmpÚREMOTEÚPYÚstrÚHEREÚpathlibÚPathr‘   Ú
write_textÚjsonÚdumpsÚ
mcp_bridgeÚBridger=   ÚbridgeÚserveÚmake_serverÚhttpdÚserver_addressÚportÚlocalÚ	threadingÚThreadÚserve_foreverÚstart)ÚclsÚconfigÚpaths   &  r	   Ú
setUpClassÚBridgeHarness.setUpClass}   s_  € ä×-Ò-Ó/ˆŒà�c—j‘jØØ�v˜y¬2¬s´4Ð:NÕ3NÓ/OÐ*PÐQØ�t˜W w°°¸)ÀUÐ&KÐLØ�{ H¨d°G¸gÈÀxÐQZÐ\aÐ=bÐcØ�x ¨5°%¸6À4ÈÐUYÐTZÐ:[Ð9\Ð]ð	ðˆô �|Š|˜CŸG™GŸL™LÓ)Ð,=Õ=ˆØ�‰œŸ
š
 6Ó*°WˆÔ=Ü×&Ò& t¨QÐ5IÌ8Ð4TÔUˆŒ
Ü×%Ò% a¨¯©¸+ÈTÔRˆŒ	Ø%(§Y¡Y×%=Ñ%=¸aÕ%@Ð@ˆŒ�3—:‘:”?Ø  §¡ 
Ð+ˆŒ	Ü×Ò §	¡	× 7Ñ 7ÀÔE×KÑKÖMr   c                ó¢   € V P                   P                  4        V P                  P                  4        V P                  P	                  4        R # r   )r«   Úshutdownr¨   rœ   Úcleanup)r³   s   &r	   ÚtearDownClassÚBridgeHarness.tearDownClass�   s0   € à�	‰	×ÑÔØ�
‰
×ÑÔØ�‰�‰Ör   c                óN   € V P                   P                  P                  4        R # r   )r¨   r$   Úreset_limitsr   s   &r	   rL   ÚBridgeHarness.setUp–   s   € Ø�‰×Ñ×'Ñ'Ö)r   c                óR  € \         P                  P                  R V P                  ^
R7      pRV/T;'       g    / Cp	V'       d   WYR&   V'       d   WiR&   Rp
Ve*   \        P
                  ! V4      P                  4       p
RV	R&   VP                  WW©R7       VP                  4       pVP                  4       P                  4       pVP                  4        VP                  \        VP                  4       4      VP                  R	4      '       d   \        P                   ! V4      3# T3# )
r9   )ÚtimeoutÚHostÚOriginÚCookieNzapplication/jsonzContent-Type)ÚbodyÚheaders)Ú{Ú[)ÚhttpÚclientÚHTTPConnectionr­   r¤   r¥   ÚencodeÚrequestÚgetresponseÚreadÚdecodeÚcloseÚstatusÚdictÚ
getheadersÚ
startswithÚloads)r   Úmethodrµ   rÅ   r–   Úoriginrw   rÆ   ÚconnÚhÚdataÚrespÚtexts   &&&&&&&&     r	   rÍ   ÚBridgeHarness.request™   sï   € Ü�{‰{×)Ñ)¨+°t·y±yÈ"Ð)ÓMˆØ�TÐ-˜gŸm˜m¨Ð-ˆßØ ˆh‰KßØ ˆh‰KØˆØÒÜ—:’:˜dÓ#×*Ñ*Ó,ˆDØ 2ˆAˆnÑØ�‰�V¨ˆÔ8Ø×ÑÓ!ˆØ�y‰y‹{×!Ñ!Ó#ˆØ�
‰
ŒØ�{‰{œD §¡Ó!2Ó3È$Ï/É/ÐZd×JeÒJe´d·j²jÀÓ6FÐpÐpÐkoÐpÐpr   c                óª   € T P                  R RRV/TT;'       g    RV 2R7      w  rEpVP                  RR4      P                  R4      ^ ,          pWGV3# )ÚPOSTú/api/mcp/loginr#   r|   ©r–   rØ   ú
Set-CookierQ   Ú;©rÍ   ÚgetÚsplit)r   r#   r–   rØ   rÒ   rÆ   rÅ   rw   s   &&&&    r	   rR   ÚBridgeHarness.loginª   sh   € Ø $§¡¨VÐ5EÈ
ÐT\ÐG]ÐdhØ4:×4OÐ4OÀÈÈÐ>Oð !-ó !QÑˆ˜à—‘˜\¨2Ó.×4Ñ4°SÓ9¸!Õ<ˆØ˜tÐ#Ð#r   c                ó€   € V P                  RRWR7      w  r4pVP                  RR4      P                  R4      ^ ,          # )z$The cookie a page load sets, if any.ÚGETú	/www/mcp/)r–   rÆ   rã   rQ   rä   rå   )r   r–   rÆ   rd   rÚ   s   &&&  r	   Úpage_cookieÚBridgeHarness.page_cookie°   s;   € à—,‘,˜u k¸�,ÓN‰ˆˆaØ�u‰u�\ 2Ó&×,Ñ,¨SÓ1°!Õ4Ð4r   c                ó€   € V P                  R RW!R7      w  r4pY3^È8X  d   V Uu. uF  qfR,          NK  	  up3# T3# u upi )rê   ú/api/mcp/servers©r–   rw   r†   )rÍ   )r   rw   r–   rÒ   rd   r…   Úss   &&&    r	   ÚidsÚBridgeHarness.idsµ   sI   € Ø!Ÿ\™\¨%Ð1CÈ$˜\Ó^Ñˆ�7Ø¸s´]©Ó1© A˜$Ÿ˜©Ñ1ÐOÐOÈÐOÐOùÒ1s   £;rH   r   )r   r   r   r   Ú__doc__r�   Úclassmethodr¶   r»   rL   r!   rÍ   r=   rR   rì   rò   r   r   r   s   @r	   rƒ   rƒ   x   st   ø‡ € ñ=à€FàñNó ðNð$ ñó ðò
*ð *.°DÀÈdÐ\`ô qð" &¨D¸ô $ô5ð
  $÷ Pò Pr   rƒ   c                   óf   a € ] tR t^ºt o R]./tR tR tR tR t	R t
R tR tR	 tR
 tR tRtV tR# )ÚRemoteBridgeTestr   c           	     ó:  € V P                  V P                  V P                  4      R 4       V P                  R V P                  R7      w  rV P                  WP	                  R4      3R4       V P                  V P                  RV P                   2R7      w  rpV P                  V^ÈR4       V P                  V P                  W0P                  R7      ^ÈRR.3R4       V P                  V P                  R	R
V P                  VR7      ^,          R,          R4       R# )rQ   ©r–   rR   r}   râ   z!localhost logs in over plain httpr‡   rŽ   zsame reach as remoterê   ú/api/mcp/whoamirð   Úmoder$   N©é‘  T)ra   rì   r®   rò   ræ   rR   rÍ   )r   rÒ   rÅ   rw   rd   s   &    r	   Ú1test_localhost_page_gets_no_token_and_must_log_inÚBRemoteBridgeTest.test_localhost_page_gets_no_token_and_must_log_in¿   sî   € à×Ñ˜×)Ñ)¨$¯*©*Ó5°rÔ:Ø—x‘x ¨¯©�xÓ4‰ˆØ×Ñ˜&§(¡(¨7Ó"3Ð4°kÔBØ ŸJ™J¨D¯J©JÀÈÏÉÈÐ?U˜JÓVÑˆ˜Ø×Ñ˜ Ð&IÔJØ×Ñ˜Ÿ™ &¯z©z˜Ó:¸SÀ6È;ÐBWÐ<XÐZpÔqØ×Ñ˜Ÿ™ eÐ->ÀTÇZÁZÐX^˜Ó_Ð`aÕbÐciÕjÐltÖur   c                ó  € V P                  V P                  \        4      R R4       V P                  R 4      w  rV P                  WP	                  R4      3R	4       V P                  V P                  RRRR7      ^ ,          R4       R# )
rQ   zno token for remote page loadsrR   rê   rï   zevil.examplerù   é“  Nrü   )ra   rì   r!   rò   ræ   rÍ   )r   rÒ   rÅ   s   &  r	   Ú#test_remote_requests_need_a_sessionÚ4RemoteBridgeTest.test_remote_requests_need_a_sessionË   sr   € Ø×Ñ˜×)Ñ)¬$Ó/°Ð5UÔVØ—x‘x “|‰ˆØ×Ñ˜&§(¡(¨7Ó"3Ð4°kÔBØ×Ñ˜Ÿ™ eÐ-?Àn˜ÓUÐVWÕXÐZ]Ö^r   c                ó*  € V P                  V P                  R 4      ^ ,          R4       V P                  4       w  rpV P                  V^È4       V P                  VP                  R4      4       V P                  V P	                  V4      ^ÈRR.3R4       RRR^R	R
RRRR/ //pV P                  RRWBR\         2R7      w  rpV P                  WR,          R,          R,          3R$4       R% Fd  pV P                  V P                  RRV R2WBR7      ^ ,          RV4       V P                  V P                  RRV R2/ VR7      ^ ,          RV4       Kf  	  V P                  RRVR7      ^,          pV P                  VR,          R4       V P                  VR,          ^ 4       V P                  RR / VR\         2R7      w  rpV P                  V^È4       V P                  R!VR",          4       V P                  V P	                  V4      ^ ,          R4       R## )&rO   rý   zmcp_session=r‡   rŽ   zshells need "remote": trueÚjsonrpcz2.0r†   r×   Ú
initializeÚparamsÚprotocolVersionz
2025-06-18Úcapabilitiesrà   z/api/mcp/demo/rpcr|   ©rw   rØ   ÚresultÚ
serverInfor‘   z	/api/mcp/z/rpc)rw   i”  z/restartrê   rú   rû   r$   Ú
expires_inz/api/mcp/logoutrq   rã   N)éÈ   z
webtt-demo)r‰   r�   )	ra   rR   rB   rÕ   rò   rÍ   r!   ÚassertGreaterrt   )	r   rÒ   rw   rd   ÚinitÚreplyr�   ÚwhoamirÆ   s	   &        r	   Ú.test_login_logout_and_what_a_session_can_reachÚ?RemoteBridgeTest.test_login_logout_and_what_a_session_can_reachÑ   s  € Ø×Ñ˜Ÿ™Ð$9Ó:¸1Õ=¸sÔCØ ŸJ™J›LÑˆ˜Ø×Ñ˜ Ô%Ø�‰˜×)Ñ)¨.Ó9Ô:Ø×Ñ˜Ÿ™ &Ó)¨C°&¸+Ð1FÐ+GÐIeÔfØ˜5 $¨¨8°\À8ÐN_ÐamÐo}ð  @Bð  NCð  DˆØŸ<™<¨Ð0CÀTÐckÔlpÐkqÐar˜<ÓsÑˆ�5Ø×Ñ˜&¨¥/°,Õ"?ÀÕ"GÐHÐJ]Ô^Û&ˆFØ×Ñ˜TŸ\™\¨&°I¸f¸XÀTÐ2JÈD˜\Ó`ÐabÕcÐehÐjpÔqØ×Ñ˜TŸ\™\¨&°I¸f¸XÀXÐ2NÐPRÐ[a˜\ÓbÐcdÕeÐgjÐlrÖsñ 'ð —‘˜eÐ%6¸v�ÓFÀqÕIˆØ×Ñ˜ �¨Ô2Ø×Ñ˜6 ,Õ/°Ô3Ø!Ÿ\™\¨&Ð2CÀRÐPVÐaiÔjnÐioÐ_p˜\ÓqÑˆ˜Ø×Ñ˜ Ô%Ø�‰�k 7¨<Õ#8Ô9Ø×Ñ˜Ÿ™ &Ó)¨!Õ,¨cÖ2r   c                óˆ   € V P                  \        P                  4       R \         2R7      w  rpV P                  V^È4       R# )r|   râ   N)rR   r!   r   ra   )r   rÒ   rw   rd   s   &   r	   Útest_host_case_does_not_matterÚ/RemoteBridgeTest.test_host_case_does_not_matterå   s6   € Ø ŸJ™J¬D¯J©J«LÀ8ÌDÈ6ÐAR˜JÓSÑˆ˜Ø×Ñ˜ Ö%r   c           	     ó>  € V P                  V P                  R RR\        /4      ^ ,          R4       V P                  V P                  R RR\        /RR7      ^ ,          R4       V P                  V P                  R RR\        /R\         2R7      ^ ,          RR4       R# )	rà   rá   r#   r  úhttps://evil.example©rØ   r}   zhttps only unless insecure_httpN)ra   rÍ   r=   r!   r   s   &r	   Ú"test_login_needs_this_sites_originÚ3RemoteBridgeTest.test_login_needs_this_sites_originé   s˜   € Ø×Ñ˜Ÿ™ fÐ.>ÀÌXÐ@VÓWÐXYÕZÐ\_Ô`Ø×Ñ˜Ÿ™ fÐ.>ÀÌXÐ@VÐ_u˜ÓvÐwxÕyÐ{~ÔØ×Ñ˜Ÿ™ fÐ.>ÀÌXÐ@VÐahÔimÐhnÐ_o˜ÓpÐqrÕsÐuxØ:ö	<r   c           	     óà   € V P                  4       w  rpV P                  V P                  R RVRR7      ^ ,          R4       V P                  V P                  R RVRR/R7      ^ ,          R4       R# )	rê   rï   r  r
  r  zSec-Fetch-Sitez
cross-site)rw   rÆ   N)rR   ra   rÍ   )r   rd   rw   s   &  r	   ÚKtest_cross_site_and_foreign_origin_requests_are_refused_even_with_a_sessionÚ\RemoteBridgeTest.test_cross_site_and_foreign_origin_requests_are_refused_even_with_a_sessionï   sr   € Ø—z‘z“|‰ˆ�1Ø×Ñ˜Ÿ™ eÐ-?ÈÐWm˜ÓnÐopÕqÐsvÔwØ×Ñ˜Ÿ™ eÐ-?ÈÐYiÐkwÐXx˜ÓyÐz{Õ|ð  Bö  	Cr   c                ó  € \        \        P                  4       F  pV P                  R 4       K  	  V P	                  RRR\
        /R\         2R7      w  r!pV P                  VR4       V P                  VR,          ^ 4       R# )	rO   rà   rá   r#   r|   r  i­  rb   N)	r_   r   r`   rR   rÍ   r=   r!   ra   r  )r   rd   rÒ   rÅ   s   &   r	   Ú2test_repeated_failures_answer_429_with_retry_afterÚCRemoteBridgeTest.test_repeated_failures_answer_429_with_retry_afterô   ss   € Ü”z×/Ñ/Ö0ˆAØ�J‰JÐ,Ö-ñ 1àŸ,™, vÐ/?À*ÌhÐAWÐbjÔkoÐjpÐ`q˜,Ór‰ˆ�4Ø×Ñ˜ Ô%Ø×Ñ˜4 Õ.°Ö2r   c           
     óŠ   € / R ^{/. 3 F7  pV P                  V P                  RRVR\         2R7      ^ ,          RV4       K9  	  R# )r#   rà   rá   r|   r  N)i�  rý   )rt   rÍ   r!   )r   rÅ   s   & r	   Útest_bad_login_bodiesÚ&RemoteBridgeTest.test_bad_login_bodiesû   sL   € Ø˜* cÐ*¨BÓ/ˆDØ�M‰M˜$Ÿ,™, vÐ/?ÀÐPXÔY]ÐX^ÐN_˜,Ó`ÐabÕcÐeoÐquÖvó 0r   c                óÌ   € R F]  pV P                  RV4      w  r#pV P                  VP                  R4      RV4       V P                  RVP                  RR4      V4       K_  	  R# )	rë   rê   zX-Frame-OptionsÚDENYzframe-ancestors 'none'zContent-Security-PolicyrQ   N)rë   z/www/rú   )rÍ   ra   ræ   rt   )r   rµ   rd   rÆ   s   &   r	   Ú#test_pages_and_api_cannot_be_framedÚ4RemoteBridgeTest.test_pages_and_api_cannot_be_framedÿ   s[   € ã=ˆDØ ŸL™L¨°Ó5‰MˆA˜Ø×Ñ˜WŸ[™[Ð):Ó;¸VÀTÔJØ�M‰MÐ2°G·K±KÐ@YÐ[]Ó4^Ð`dÖeó >r   c                ó’   € V P                   P                  P                  pT P                  VP                  ;'       g    ^ ^ 4       R# )é    N)r«   ÚRequestHandlerClassÚfuncr  rÁ   )r   Úhandlers   & r	   Útest_idle_connections_time_outÚ/RemoteBridgeTest.test_idle_connections_time_out  s3   € Ø—*‘*×0Ñ0×5Ñ5ˆØ×Ñ˜7Ÿ?™?×/Ð/¨a°Ö3r   rH   N)r   r   r   r   r!   r�   rþ   r  r  r  r  r  r!  r$  r(  r/  r   r   r   s   @r	   r÷   r÷   º   sM   ø‡ € Ø˜�vÐ€Fòvò_ò3ò(&ò<òCò
3òwòf÷4ð 4r   r÷   c                   óD   a € ] tR tRt o RtR].RR/tR tR tR t	R	t
V tR
# )ÚTrustLocalhostTesti  zw"trust_localhost": true keeps the no-login local flow (only safe when no proxy in front
can rewrite Host to localhost).r   r7   Tc           	     óL  € V P                  V P                  4      pV P                  VP                  R 4      4       V P	                  V P                  WP                  R7      ^È. RO34       V P	                  V P                  RRV P                  VR7      ^,          RR/4       R# )	z
mcp_token=rù   rê   rú   rð   rû   r®   N)r‡   r‰   rŽ   r�   )rì   r®   rB   rÕ   ra   rò   rÍ   )r   rw   s   & r	   Ú4test_local_page_gets_the_token_and_sees_every_serverÚGTrustLocalhostTest.test_local_page_gets_the_token_and_sees_every_server  s†   € Ø×!Ñ! $§*¡*Ó-ˆØ�‰˜×)Ñ)¨,Ó7Ô8Ø×Ñ˜Ÿ™ &¯z©z˜Ó:¸SÒBgÐ<hÔiØ×Ñ˜Ÿ™ eÐ->ÀTÇZÁZÐX^˜Ó_Ð`aÕbÐekÐmtÐduÖvr   c           	     ó  € R	 F…  pV P                  V P                  V P                  VR/R7      RV4       V P                  RRV P                  V P                  V P                  4      VR/R7      w  p pV P                  VRV4       K‡  	  R# )
úX-Forwarded-Forz203.0.113.9)rÆ   rQ   rê   rï   )r–   rw   rÆ   r  N)r7  z	X-Real-IPÚ	ForwardedzX-Forwarded-Host)ra   rì   r®   rÍ   )r   ÚheaderrÒ   rd   s   &   r	   Ú3test_localhost_with_forwarding_headers_is_not_localÚFTrustLocalhostTest.test_localhost_with_forwarding_headers_is_not_local  sŽ   € ÛWˆFØ×Ñ˜T×-Ñ-¨d¯j©jÀ6È=ÐBYÐ-ÓZÐ\^Ð`fÔgØŸ<™<¨Ð/AÈÏ
É
Ð[_×[kÑ[kÐlp×lvÑlvÓ[wØ17¸Ð0Gð (ó I‰LˆF�A�qà×Ñ˜V S¨&Ö1ó	 Xr   c                óˆ   € V P                  V P                  V P                  V P                  4      4      ^ ,          R4       R# )r+  rý   N)ra   rò   rì   r®   r   s   &r	   Ú,test_the_local_token_is_no_good_from_outsideÚ?TrustLocalhostTest.test_the_local_token_is_no_good_from_outside  s/   € Ø×Ñ˜Ÿ™ $×"2Ñ"2°4·:±:Ó">Ó?ÀÕBÀCÖHr   rH   N)r   r   r   r   rô   r!   r�   r4  r:  r=  r   r   r   s   @r	   r2  r2    s2   ø‡ € ñ'à˜�vÐ0°$Ð7€Fòwò2÷Ið Ir   r2  c                   ó2   a € ] tR tRt o R tR tR tRtV tR# )ÚBridgeConfigTesti!  c                óò  € \         P                  ! R RRR7      ;_uu_ 4       p\        P                  ! RR\        ./R. /V4       RRR4       V P                  \        P                  ! XP                  4      P                  4       V P                  \        R4      ;_uu_ 4        \        P                  ! VP                  ^ / R	7       RRR4       R#   + '       g   i     L•; i  + '       g   i     R# ; i)
Úwú.jsonF©ÚsuffixÚdeleter$   r   r…   Nr   r”   )rš   ÚNamedTemporaryFiler¤   Údumpr!   Ú
addCleanupr¡   r¢   r‘   Úunlinkr.   r/   r¦   r§   ©r   Úfs   & r	   Ú4test_remote_hosts_without_a_password_refuse_to_startÚEBridgeConfigTest.test_remote_hosts_without_a_password_refuse_to_start"  s¦   € Ü×(Ò(¨°WÀU×KÕKÈqÜ�IŠI�x '¬D¨6Ð!2°I¸rÐBÀAÔF÷ Là�‰œŸš Q§V¡VÓ,×3Ñ3Ô4Ø×#Ñ#¤JÐ0D×EÕEÜ×Ò˜aŸf™f a¨RÕ0÷ FÑE÷ L×Kú÷ F×EÐEús   ¢#CÂ$$C%ÃC"	Ã%C6	c                óè  € \         P                  ! R RRR7      ;_uu_ 4       p\        P                  ! RRRRRR	R
././V4       RRR4       V P	                  \
        P                  ! XP                  4      P                  4       V P                  \        4      ;_uu_ 4        \        P                  ! VP                  4       RRR4       R#   + '       g   i     L‘; i  + '       g   i     R# ; i)rB  rC  FrD  r…   r†   Úar$   r6   rˆ   ÚxN)rš   rG  r¤   rH  rI  r¡   r¢   r‘   rJ  r<   r/   r¦   Úload_configrK  s   & r	   Ú'test_server_remote_flag_must_be_booleanÚ8BridgeConfigTest.test_server_remote_flag_must_be_boolean)  s¥   € Ü×(Ò(¨°WÀU×KÕKÈqÜ�IŠI�y D¨#¨x¸À	ÈCÈ5Ð#QÐ"RÐSÐUVÔW÷ Là�‰œŸš Q§V¡VÓ,×3Ñ3Ô4Ø×Ñœz×*Õ*Ü×"Ò" 1§6¡6Ô*÷ +Ñ*÷ L×Kú÷ +×*Ð*ús   ¢"CÂ"!C ÃC	Ã C1	c                ó\  € \         P                  ! R RRR7      ;_uu_ 4       p\        P                  ! RR\        .RR/RR	R
RR./R	RRRR.RR//./V4       RRR4       V P                  \        P                  ! XP                  4      P                  4       RP                  \        P                  ! VP                  ^ R\        /R7      P                  4       4      pV P                  \        V4       V P                  R
V4       V P                  RVR4       R#   + '       g   i     LÌ; i)rB  rC  FrD  r$   r   r5   Tr…   r†   rP  rˆ   rQ  rñ   rŠ   r‹   Úlsr�   NÚ
r   r”   u   æ˜Žæ–‡zinsecure_http is called out)rš   rG  r¤   rH  r!   rI  r¡   r¢   r‘   rJ  Újoinr¦   r§   r=   Ústartup_linesrt   )r   rL  rÝ   s   &  r	   Ú1test_startup_lines_say_what_is_reachable_remotelyÚBBridgeConfigTest.test_startup_lines_say_what_is_reachable_remotely0  sÿ   € Ü×(Ò(¨°WÀU×KÕKÈqÜ�IŠI�x '¬D¨6°?ÀDÐ!IØ  D¨#¨y¸3¸%Ð#@À4ÈÈgÐX_ÐbfÐagÐirÐtyÐWzÐB{Ð"|ð~ð @AôB÷ Lð 	�‰œŸš Q§V¡VÓ,×3Ñ3Ô4Ø�y‰yœ×*Ò*¨1¯6©6°1Ð;OÔQYÐ:ZÔ[×iÑiÓkÓlˆØ�‰”d˜DÔ!Ø�‰�c˜4Ô Ø�‰�h Ð&CÖD÷ L×Kús   ¢5DÄD+	rH   N)	r   r   r   r   rM  rS  rZ  r   r   r   s   @r	   r@  r@  !  s   ø‡ € ò1ò+÷Eð Er   r@  Ú__main__)#rô   Úhttp.clientrÉ   r¤   r¡   Úsysrš   r¯   Úunittestr¢   Ú__file__ÚresolveÚparentr    rµ   ÚinsertrŸ   r¦   r   r©   Ú
executablerž   r=   r!   r   r$   ÚTestCaser&   rJ   rƒ   r÷   r2  r@  r   ÚmainrH   r   r	   Ú<module>rg     s  ðñó Û Û Û 
Û Û Û à‡|‚|�HÓ×%Ñ%Ó'×.Ñ.€Ø ‡�‡��‘3�t“9Ô Û Û Û à‡^�^€Ø)€Ø€÷ñ ð ˜h¨dô Gô
7�×"Ñ"ô 7ô47[�(×#Ñ#ô 7[÷t?Pñ ?PôDN4�} h×&7Ñ&7ô N4ôbI˜¨×(9Ñ(9ô Iô,E�x×(Ñ(ô Eð4 ˆzÔØ‡M‚M†Oñ r   