o
    ç÷¡g‰M  ã                   @   s¬  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 d dlmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZmZmZmZmZmZ d dlmZm Z m!Z! zd dl"m#Z# W n e$ys   e%Z#Y nw zd d	l&m'Z' W n e$y‹   d d	l'm'Z' Y nw d
Z(dZ)dZ*G dd„ de+ƒZ,G dd„ dej-ƒZ-G dd„ de.ƒZ/G dd„ de.ƒZ0G dd„ de0e	j1j2ƒZ3G dd„ de0e	j1j4ƒZ5G dd„ de0e	j6j7ƒZ8dS )é    N)ÚThreadPoolExecutor)ÚIOLoop)Úoptions)Ú	cpu_count)Úis_valid_ip_addressÚis_valid_portÚis_valid_hostnameÚto_bytesÚto_strÚto_intÚto_ip_addressÚUnicodeTypeÚis_ip_hostnameÚis_same_primary_domainÚis_valid_encoding)ÚWorkerÚrecycle_workerÚclients)ÚJSONDecodeError)Úurlparseé   Tc                   @   s   e Zd ZdS )ÚInvalidValueErrorN)Ú__name__Ú
__module__Ú__qualname__© r   r   ú9/usr/local/lib/python3.10/dist-packages/webssh/handler.pyr   '   s    r   c                   @   s$   e Zd Zdd„ Zdd„ Zdd„ ZdS )Ú	SSHClientc                 C   s^   g }|D ](\}}|  ¡  ¡ }| d¡r| | j¡ q| d¡r&| | j¡ qtd |¡ƒ‚|S )NÚpasswordÚverificationzUnknown prompt: {})ÚstripÚlowerÚ
startswithÚappendr   ÚtotpÚ
ValueErrorÚformat)ÚselfÚtitleÚinstructionsÚprompt_listÚanswersÚprompt_Ú_Úpromptr   r   r   Úhandler-   s   

zSSHClient.handlerc                 C   s    | j stdƒ‚| j ||¡ d S )Nz!Need a verification code for 2fa.)r$   r%   Ú
_transportÚauth_interactive)r'   Úusernamer/   r   r   r   r1   9   s   zSSHClient.auth_interactivec           
   
   G   s4  || _ d }d}tƒ }ddh}|d urAt d¡ zt| j ||¡ƒ}||@ }|s*W d S W n tjy@ }	 z|	}W Y d }	~	nd }	~	ww |rOt d¡ |  || j	¡S |d ur„t d¡ z
| j 
||¡ W d S  tjyƒ }	 z|	}tt|	dg ƒƒ}||@ }W Y d }	~	nd }	~	ww |r’t d¡ |  || j	¡S |d us˜J ‚|‚)	NFzkeyboard-interactiver   zTrying publickey authenticationzTrying publickey 2fazTrying password authenticationÚallowed_typeszTrying password 2fa)r   ÚsetÚloggingÚinfor0   Úauth_publickeyÚparamikoÚSSHExceptionr1   r/   Úauth_passwordÚgetattr)
r'   r2   r   ÚpkeyÚargsÚsaved_exceptionÚ
two_factorr3   Útwo_factor_typesÚer   r   r   Ú_auth>   sL   
ÿÿ€ÿ

€ý
zSSHClient._authN)r   r   r   r/   r1   rB   r   r   r   r   r   +   s    r   c                   @   sH   e Zd ZdZdddddœZdd	d
„Zdd„ Zdd„ Zdd„ Zdd„ Z	dS )Ú
PrivateKeyi @  ÚRSAÚDSSÚECDSAÚEd25519)rD   ÚDSAÚECÚOPENSSHNÚ c                 C   s0   || _ || _|| _|  ¡  t |¡| _d | _d S ©N)Ú
privatekeyÚfilenamer   Úcheck_lengthÚioÚStringIOÚiostrÚlast_exception)r'   rM   r   rN   r   r   r   Ú__init__r   s   
zPrivateKey.__init__c                 C   s   t | jƒ| jkrtdƒ‚d S )NzInvalid key length.)ÚlenrM   Ú
max_lengthr   ©r'   r   r   r   rO   z   s   ÿzPrivateKey.check_lengthc                 C   sn   d }|D ],}|  ¡ }|r0| d¡r0| d¡r0| d¡}t|ƒdkr0|d }|r0| |¡}|r0 nq|t|ƒfS )Nz-----BEGIN z PRIVATE KEY-----ú é   é   )r    r"   ÚendswithÚsplitrU   Úget)r'   rR   Útag_to_nameÚnameÚline_ÚlineÚlstÚtagr   r   r   Ú
parse_name~   s   ÿ

€zPrivateKey.parse_namec              
   C   s¬   | j  |¡ t d |¡¡ t d |¡¡ tt|d ƒ}d }z|j| j |d�}W |S  tjy6   t	dƒ‚ tj
tfyU } z|| _t t|ƒ¡ W Y d }~|S d }~ww )NzReset offset to {}.zTry parsing it as {} type keyÚKey)r   z%Need a passphrase to decrypt the key.)rR   Úseekr5   Údebugr&   r;   r8   Úfrom_private_keyÚPasswordRequiredExceptionr   r9   r%   rS   Ústr)r'   r_   Úoffsetr   Úpkeyclsr<   Úexcr   r   r   Úget_specific_pkey�   s    ú€üzPrivateKey.get_specific_pkeyc                 C   sÔ   t  d | j¡¡ |  | j| j¡\}}|std | j¡ƒ‚| j ¡ | }| j	r,t
| j	ƒnd }|  |||¡}|d u rM|dkrMdD ]}|  |||¡}|rL nq?|rQ|S t  t| jƒ¡ d}| j	rf|d | j	¡7 }t|ƒ‚)NzParsing private key {!r}zInvalid key {}.rG   )rD   rF   rE   zInvalid keyz, or wrong passphrase "{}" for decrypting it.)r5   r6   r&   rN   rd   rR   r^   r   Útellr   r	   rn   Úerrorrj   rS   )r'   r_   Úlengthrk   r   r<   Úmsgr   r   r   Úget_pkey_objŸ   s,   ÿÿzPrivateKey.get_pkey_obj)NrK   )
r   r   r   rV   r^   rT   rO   rd   rn   rs   r   r   r   r   rC   g   s    ü
rC   c                   @   sj   e Zd ZddiZdZddd„Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ ZdS )ÚMixinHandlerÚServerÚTornadoServerzT<html><head><title>{code} {reason}</title></head><body>{code} {reason}</body></html>Nc                 C   s    |   ¡  || _| j d¡| _d S )NÚorigin_policy)Úcheck_requestÚloopÚsettingsr]   rw   ©r'   ry   r   r   r   Ú
initializeÃ   s   zMixinHandler.initializec                 C   sˆ   | j jj}|  || j j¡}g | _|r&|  d¡ |  | jj	| j
| jd�¡ d S |du r?|  | j jtj| j j¡}| j|dd� d S || _d S )Né“  )ÚcodeÚreasonFT)Ú	permanent)ÚrequestÚ
connectionÚcontextÚis_forbiddenÚ	host_nameÚ_transformsÚ
set_statusÚfinishÚhtmlr&   Ú_status_codeÚ_reasonÚget_redirect_urlr   ÚsslportÚuriÚredirect)r'   rƒ   ÚresultÚto_urlr   r   r   rx   È   s   

ÿÿ
zMixinHandler.check_requestc                 C   sž   | j dkrdS t|ƒ}|j ¡ }t d |¡¡ | jj 	d¡}t d |¡¡ ||kr-dS | j dkr4dS | j dkrJt
| d	d
¡d | d	d
¡d ƒS || j v S )NÚ*Tz
netloc: {}ÚHostzhost: {}ÚsameFÚprimaryú:rZ   r   )rw   r   Únetlocr!   r5   rg   r&   r�   Úheadersr]   r   Úrsplit)r'   ÚoriginÚparsed_originr—   Úhostr   r   r   Úcheck_originÙ   s    



ÿ
zMixinHandler.check_originc                 C   s”   |j d }|j}d }|r||vrt d ||¡¡ dS |jdkrDtr/t|ƒs/t|ƒ}|j	s/dS t
jrF|d u r:t|ƒ}|j	sHt d¡ dS d S d S d S )Nr   z,IP {!r} not found in trusted downstream {!r}TÚhttpFz'Public plain http request is forbidden.)ÚaddressÚtrusted_downstreamr5   Úwarningr&   Ú_orig_protocolÚredirectingr   r   Ú
is_privater   Úfbidhttp)r'   rƒ   ÚhostnameÚiprb   Ú
ip_addressr   r   r   r„   ï   s,   

ÿ

ôzMixinHandler.is_forbiddenc                 C   s"   |dkrdnd| }d  |||¡S )Ni»  rK   z:%szhttps://{}{}{})r&   )r'   r¦   ÚportrŽ   r   r   r   rŒ     s   zMixinHandler.get_redirect_urlc                 C   s   | j  ¡ D ]}| j|Ž  qd S rL   )Úcustom_headersÚitemsÚ
set_header)r'   Úheaderr   r   r   Úset_default_headers  s   ÿz MixinHandler.set_default_headersc                 C   s    |   |¡}|std |¡ƒ‚|S )NzMissing value {})Úget_argumentr   r&   )r'   r_   Úvaluer   r   r   Ú	get_value  s   
zMixinHandler.get_valuec                 C   s   | j jd d… S )Né   )rƒ   rŸ   rW   r   r   r   Úget_context_addr  s   zMixinHandler.get_context_addrc                 C   s   t jr|  ¡ p
|  ¡ S |  ¡ S rL   )r   ÚxheadersÚget_real_client_addrr³   rW   r   r   r   Úget_client_addr  s   zMixinHandler.get_client_addrc                 C   sv   | j j}|| j j d¡kr| j j d¡}n|| j j dd¡v r'| j j d¡}nd S t|ƒ}|d u s5t|ƒs7d}||fS )Nz	X-Real-IpzX-Real-PortzX-Forwarded-ForrK   zX-Forwarded-Portiÿÿ  )r�   Ú	remote_ipr˜   r]   r   r   )r'   r§   r©   r   r   r   rµ     s   z!MixinHandler.get_real_client_addrrL   )r   r   r   rª   r‰   r|   rx   r�   r„   rŒ   r®   r±   r³   r¶   rµ   r   r   r   r   rt   º   s    ÿ
rt   c                       s$   e Zd Z‡ fdd„Zdd„ Z‡  ZS )ÚNotFoundHandlerc                    s   t t| ƒ ¡  d S rL   )Úsuperr¸   r|   rW   ©Ú	__class__r   r   r|   4  s   zNotFoundHandler.initializec                 C   s   t j d¡‚)Ni”  )ÚtornadoÚwebÚ	HTTPErrorrW   r   r   r   Úprepare7  s   zNotFoundHandler.prepare)r   r   r   r|   r¿   Ú__classcell__r   r   rº   r   r¸   2  s    r¸   c                       s¬   e Zd Zeeƒ d d�Z‡ fdd„Z‡ fdd„Zdd„ Zd	d
„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z‡ fdd„Zdd„ Zdd„ Zejjdd „ ƒZ‡  ZS )!ÚIndexHandleré   )Úmax_workersc                    sZ   t t| ƒ |¡ || _|| _|  ¡ | _| j dd¡| _	| j dd¡| _
td d d d�| _d S )Nrg   FÚfontrK   )ÚidÚstatusÚencoding)r¹   rÁ   r|   ÚpolicyÚhost_keys_settingsÚget_ssh_clientÚ
ssh_clientrz   r]   rg   rÄ   Údictr�   )r'   ry   rÈ   rÉ   rº   r   r   r|   ?  s   
zIndexHandler.initializec                    s~   t r1| jjdkr1| d¡}|rt|d dd ƒ}|r|| _| jj| jd� |  d¡ |  	| j¡ d S t
t| ƒj|fi |¤Ž d S )NÚPOSTÚexc_inforZ   Úlog_message©rÆ   éÈ   )Úswallow_http_errorsr�   Úmethodr]   r;   r‹   r�   Úupdater‡   rˆ   r¹   rÁ   Úwrite_error)r'   Ústatus_codeÚkwargsrÎ   r   rº   r   r   rÕ   H  s   

zIndexHandler.write_errorc                 C   s:   t ƒ }| jd |_| jd |_| jd |_| | j¡ |S )NÚsystem_host_keysÚ	host_keysÚhost_keys_filename)r   rÉ   Ú_system_host_keysÚ
_host_keysÚ_host_keys_filenameÚset_missing_host_key_policyrÈ   )r'   Ússhr   r   r   rÊ   U  s   zIndexHandler.get_ssh_clientc                 C   s`   d}| j j |¡}|r$|d d }|d d }| j||d� ¡ }||fS |  |d¡}d}||fS )NrM   r   rN   Úbody)r_   rK   )r�   Úfilesr]   Údecode_argumentr    r¯   )r'   r_   rb   rN   Údatar°   r   r   r   Úget_privatekey]  s   ýzIndexHandler.get_privatekeyc                 C   s,   |   d¡}t|ƒst|ƒstd |¡ƒ‚|S )Nr¦   zInvalid hostname: {})r±   r   r   r   r&   )r'   r°   r   r   r   Úget_hostnamel  s   
zIndexHandler.get_hostnamec                 C   s>   |   dd¡}|s
tS t|ƒ}|d u st|ƒstd |¡ƒ‚|S )Nr©   rK   zInvalid port: {})r¯   ÚDEFAULT_PORTr   r   r   r&   )r'   r°   r©   r   r   r   Úget_portr  s   zIndexHandler.get_portc                 C   sZ   |dkr|nd  ||¡}| jj |¡d u r)| jj |¡d u r+tj dd  ||¡¡‚d S d S )Nr   z[{}]:{}r}   z#Connection to {}:{} is not allowed.)r&   rË   rÛ   ÚlookuprÜ   r¼   r½   r¾   )r'   r¦   r©   Úkeyr   r   r   Úlookup_hostname|  s   ÿÿþzIndexHandler.lookup_hostnamec                 C   s¢   |   ¡ }|  ¡ }|  d¡}|  dd¡}|  ¡ \}}|  dd¡}|  dd¡}t| jtjƒr2|  	||¡ |r=t
|||ƒ ¡ }	nd }	|| j_|||||	f}
t |
¡ |
S )Nr2   r   rK   Ú
passphraser$   )rå   rç   r±   r¯   rä   Ú
isinstancerÈ   r8   ÚRejectPolicyrê   rC   rs   rË   r$   r5   rg   )r'   r¦   r©   r2   r   rM   rN   rë   r$   r<   r=   r   r   r   Úget_args†  s    

zIndexHandler.get_argsc                 C   s8   z	t | ¡ dƒ}W n
 ty   Y d S w t|ƒr|S d S )NÚascii)r
   r    ÚUnicodeDecodeErrorr   )r'   rã   rÇ   r   r   r   Úparse_encoding�  s   ÿÿzIndexHandler.parse_encodingc           	      C   sº   ddg}|D ]O}z|j |ddd�\}}}W n tjy/ } zt t|ƒ¡ W Y d }~qd }~ww z| ¡ }W n
 tjy@   Y qw t 	d 
||¡¡ |  |¡}|rU|  S qt d¡ dS )	Nz$SHELL -ilc "locale charmap"z$SHELL -ic "locale charmap"TrZ   )Úget_ptyÚtimeoutz{!r} => {!r}z&Could not detect the default encoding.zutf-8)Úexec_commandr8   r9   r5   r6   rj   ÚreadÚsocketró   rg   r&   rñ   r¡   )	r'   rß   ÚcommandsÚcommandr-   Ústdoutrm   rã   r�   r   r   r   Úget_default_encoding¦  s2   þþ€ÿÿ
ÿ
z!IndexHandler.get_default_encodingc                 C   sò   | j }|d d… }t dj|Ž ¡ z|j|dtjiŽ W n0 tjy+   t	dj|Ž ƒ‚ t
jy6   t	dƒ‚ t
jyA   t	dƒ‚ t
jyL   t	dƒ‚w |  dd	¡pTd
}|j|d�}| d¡ t| j|||ƒ}tjrqtj|_|S |  |¡|_|S )Nr²   zConnecting to {}:{}ró   zUnable to connect to {}:{}zBad authentication type.zAuthentication failed.zBad host key.ÚtermrK   Úxterm)rû   r   )rË   r5   r6   r&   Úconnectr   ró   rö   rp   r%   r8   ÚBadAuthenticationTypeÚAuthenticationExceptionÚBadHostKeyExceptionr¯   Úinvoke_shellÚsetblockingr   ry   rÇ   rú   )r'   r=   rß   Údst_addrrû   ÚchanÚworkerr   r   r   Ússh_connectÁ  s.   ÿ
ÿÿzIndexHandler.ssh_connectc                    sn   |   dd¡}| jj d¡}|p|}|r1tt| ƒ |¡s"tj 	dd¡‚|s3| j
dkr5|  d|¡ d S d S d S d S )NÚ_originrK   ÚOriginr}   z&Cross origin operation is not allowed.r”   zAccess-Control-Allow-Origin)r¯   r�   r˜   r]   r¹   rÁ   r�   r¼   r½   r¾   rw   r¬   )r'   Úevent_originÚheader_originrš   rº   r   r   r�   Ù  s   ÿùzIndexHandler.check_originc                 C   s   d S rL   r   rW   r   r   r   Úheadç  s   zIndexHandler.headc                 C   s   | j d| j| jd� d S )Nz
index.html)rg   rÄ   )Úrenderrg   rÄ   rW   r   r   r   r]   ê  s   zIndexHandler.getc              
   c   sP  � | j r|  dd¡rtdƒ‚|  ¡ \}}t |i ¡}|r*t|ƒtjkr*t	j
 dd¡‚|  ¡  z|  ¡ }W n tyI } z	t	j
 dt|ƒ¡‚d }~ww | j | j|¡}z|V }W n% ttjfy| } zt t ¡ ¡ | jjt|ƒd� W Y d }~n(d }~ww |sƒ|t|< ||f|_|||j< | j tjt |¡ | jj|j|j!d� |  "| j¡ d S )	Nrp   rK   zUncaught exceptionr}   zToo many live connections.i�  rÐ   )rÅ   rÇ   )#rg   r¯   r%   r¶   r   r]   rU   r   Úmaxconnr¼   r½   r¾   r�   rî   r   rj   ÚexecutorÚsubmitr  r8   r9   r5   rp   Ú	tracebackÚ
format_excr�   rÔ   Úsrc_addrrÅ   ry   Ú
call_laterÚdelayr   rÇ   Úwrite)r'   r§   r©   Úworkersr=   rm   Úfuturer  r   r   r   Úpostí  s:   €€ÿ
€þ

zIndexHandler.post)r   r   r   r   r   r  r|   rÕ   rÊ   rä   rå   rç   rê   rî   rñ   rú   r  r�   r  r]   r¼   ÚgenÚ	coroutiner  rÀ   r   r   rº   r   rÁ   ;  s$    	

	rÁ   c                       s4   e Zd Z‡ fdd„Zdd„ Zdd„ Zdd„ Z‡  ZS )	ÚWsockHandlerc                    s   t t| ƒ |¡ d | _d S rL   )r¹   r  r|   Ú
worker_refr{   rº   r   r   r|     s   
zWsockHandler.initializec              
   C   sì   |   ¡ | _t dj| jŽ ¡ t | jd ¡}|s | jdd� d S z|  d¡}W n t	j
jtfyF } z| jt|ƒd� W Y d }~d S d }~ww | |¡}|rnd ||< |  d¡ | | ¡ t |¡| _| j |j|tj¡ d S | jdd� d S )NzConnected from {}:{}r   z Websocket authentication failed.©r   rÅ   T)r¶   r  r5   r6   r&   r   r]   Úcloser±   r¼   r½   ÚMissingArgumentErrorr   rj   Úset_nodelayÚset_handlerÚweakrefÚrefr  ry   Úadd_handlerÚfdr   ÚREAD)r'   r  Ú	worker_idrm   r  r   r   r   Úopen  s(   
€ÿ


zWsockHandler.openc              
   C   s  t  dj|g| j¢R Ž ¡ |  ¡ }|s$t  dj| jŽ ¡ | jdd� d S |jr/| jdd� d S zt |¡}W n
 t	y@   Y d S w t
|tƒsHd S | d¡}|rlt|ƒdkrlz|jj|Ž  W n ttjtjfyk   Y nw | d¡}|r„t
|tƒr†|j |¡ | ¡  d S d S d S )	Nz{!r} from {}:{}z,received message to closed worker from {}:{}zNo worker foundr  zWorker closedÚresizer²   rã   )r5   rg   r&   r  r  r  ÚclosedÚjsonÚloadsr   rì   rÌ   r]   rU   r  Ú
resize_ptyÚ	TypeErrorÚstructrp   r8   r9   r   Údata_to_dstr#   Úon_write)r'   Úmessager  rr   r)  rã   r   r   r   Ú
on_message/  s@   ÿÿÿ

ÿ
þzWsockHandler.on_messagec                 C   sJ   t  dj| jŽ ¡ | jsd| _| jr|  ¡ nd }|r#|j| jd� d S d S )NzDisconnected from {}:{}zclient disconnectedr  )r5   r6   r&   r  Úclose_reasonr  r  )r'   r  r   r   r   Úon_closeT  s   ÿzWsockHandler.on_close)r   r   r   r|   r(  r3  r5  rÀ   r   r   rº   r   r    s
    %r  )9rP   r+  r5   rö   r/  r  r"  r8   Útornado.webr¼   Úconcurrent.futuresr   Útornado.ioloopr   Útornado.optionsr   Útornado.processr   Úwebssh.utilsr   r   r   r	   r
   r   r   r   r   r   r   Úwebssh.workerr   r   r   Újson.decoderr   ÚImportErrorr%   Úurllib.parser   ræ   rÒ   r£   Ú	Exceptionr   r   ÚobjectrC   rt   r½   ÚErrorHandlerr¸   ÚRequestHandlerrÁ   Ú	websocketÚWebSocketHandlerr  r   r   r   r   Ú<module>   sH    4ÿÿ<Sx	 W