a
    mzf3                     @   s  d Z ddlZddlZddlZddlZzHddlZddlmZ ddlmZ z
ej	Z
W n eyh   ejZ
Y n0 W n ey   dZY n0 ddlmZ ddlmZmZ dd	lmZmZ G d
d dZG dd deeZG dd deeZG dd dZG dd dedZG dd deZdS )a  
A library for integrating :doc:`pyOpenSSL <pyopenssl:index>` with Cheroot.

The :py:mod:`OpenSSL <pyopenssl:OpenSSL>` module must be importable
for SSL/TLS/HTTPS functionality.
You can obtain it from `here <https://github.com/pyca/pyopenssl>`_.

To use this module, set :py:attr:`HTTPServer.ssl_adapter
<cheroot.server.HTTPServer.ssl_adapter>` to an instance of
:py:class:`ssl.Adapter <cheroot.ssl.Adapter>`.
There are two ways to use :abbr:`TLS (Transport-Level Security)`:

Method One
----------

 * :py:attr:`ssl_adapter.context
   <cheroot.ssl.pyopenssl.pyOpenSSLAdapter.context>`: an instance of
   :py:class:`SSL.Context <pyopenssl:OpenSSL.SSL.Context>`.

If this is not None, it is assumed to be an :py:class:`SSL.Context
<pyopenssl:OpenSSL.SSL.Context>` instance, and will be passed to
:py:class:`SSL.Connection <pyopenssl:OpenSSL.SSL.Connection>` on bind().
The developer is responsible for forming a valid :py:class:`Context
<pyopenssl:OpenSSL.SSL.Context>` object. This
approach is to be preferred for more flexibility, e.g. if the cert and
key are streams instead of files, or need decryption, or
:py:data:`SSL.SSLv3_METHOD <pyopenssl:OpenSSL.SSL.SSLv3_METHOD>`
is desired instead of the default :py:data:`SSL.SSLv23_METHOD
<pyopenssl:OpenSSL.SSL.SSLv3_METHOD>`, etc. Consult
the :doc:`pyOpenSSL <pyopenssl:api/ssl>` documentation for
complete options.

Method Two (shortcut)
---------------------

 * :py:attr:`ssl_adapter.certificate
   <cheroot.ssl.pyopenssl.pyOpenSSLAdapter.certificate>`: the file name
   of the server's TLS certificate.
 * :py:attr:`ssl_adapter.private_key
   <cheroot.ssl.pyopenssl.pyOpenSSLAdapter.private_key>`: the file name
   of the server's private key file.

Both are :py:data:`None` by default. If :py:attr:`ssl_adapter.context
<cheroot.ssl.pyopenssl.pyOpenSSLAdapter.context>` is :py:data:`None`,
but ``.private_key`` and ``.certificate`` are both given and valid, they
will be read, and the context will be automatically created from them.

.. spelling::

   pyopenssl
    N)SSL)crypto   )Adapter   )errorsserver)StreamReaderStreamWriterc                       sV   e Zd ZdZdZdZdd Z fddZd fd	d
	Z fddZ	 fddZ
  ZS )SSLFileobjectMixinz#Base mixin for a TLS socket stream.   g{Gz?c           	      O   s~  t   }z||i |W S  tjy:   t | j Y n" tjyZ   t | j Y n tjy } zX|r|jdkrW Y d}~dS |jd }|r|tj	v rW Y d}~dS t
|W Y d}~nd}~0  tjyZ } zv|r|jdkrW Y d}~dS d}z|jd d d }W n ty&   Y n0 |dkr:t tj|j W Y d}~n
d}~0 0 t   | | jkrt
dqdS )zWrap the given call with TLS error-trapping.

        is_reader: if False EOF errors will be raised. If True, EOF errors
        will return "" (to emulate normal sockets).
        )zUnexpected EOFN    r   r   zhttp requestz	timed out)timer   ZWantReadErrorsleep	ssl_retryZWantWriteErrorZSysCallErrorargsr   Zsocket_errors_to_ignoresocketerrorError
IndexErrorZ
NoSSLErrorZFatalSSLAlertssl_timeouttimeout)	selfZ	is_readercallr   kwargsstarteZerrnumZthirdarg r   C/var/www/media/lib/python3.9/site-packages/cheroot/ssl/pyopenssl.py
_safe_callR   s6    

"zSSLFileobjectMixin._safe_callc                    s   |  dtt| j|S )z*Receive message of a size from the socket.T)r    superr   recvr   size	__class__r   r   r"      s
    
zSSLFileobjectMixin.recvr   c                    s   |  dtt| j|S )zReceive message of a size from the socket.

        Matches the following interface:
        https://docs.python.org/3/library/io.html#io.IOBase.readline
        T)r    r!   r   readliner#   r%   r   r   r'      s
    
zSSLFileobjectMixin.readlinec                    s"   | j dtt| jg|R i |S )z!Send whole message to the socket.F)r    r!   r   sendallr   r   r   r%   r   r   r(      s    
zSSLFileobjectMixin.sendallc                    s"   | j dtt| jg|R i |S )z(Send some part of message to the socket.F)r    r!   r   sendr)   r%   r   r   r*      s    
zSSLFileobjectMixin.send)r   )__name__
__module____qualname____doc__r   r   r    r"   r'   r(   r*   __classcell__r   r   r%   r   r   K   s   .r   c                   @   s   e Zd ZdZdS )SSLFileobjectStreamReader,SSL file object attached to a socket object.Nr+   r,   r-   r.   r   r   r   r   r0      s   r0   c                   @   s   e Zd ZdZdS )SSLFileobjectStreamWriterr1   Nr2   r   r   r   r   r3      s   r3   c                   @   s   e Zd ZdZdd ZdS )SSLConnectionProxyMetaz2Metaclass for generating a bunch of proxy methods.c           
         sb   d}d d} fdd}|D ]}||||< ||| _ qdd }|D ]}	||	||	< qDt|||S )z.Attach a list of proxy methods to a new class.)"get_contextpendingr*   writer"   readZrenegotiatebindlistenconnectacceptsetblockingfilenocloseZget_cipher_listgetpeernamegetsockname
getsockopt
setsockoptmakefileZget_app_dataZset_app_dataZstate_stringZsock_shutdownZget_peer_certificateZ	want_readZ
want_writeZset_connect_stateZset_accept_state
connect_exr(   
settimeout
gettimeoutshutdown)rH   )familyc                    s    fdd}|S )&Create a proxy method for a new class.c                    sP   | j   z4 vr |d d  ng }t| j | W | j   S | j   0 d S N)_lockacquiregetattr	_ssl_connrelease)r   r   new_args)methodproxy_methods_no_argsr   r   proxy_wrapper   s    

zMSSLConnectionProxyMeta.__new__.<locals>.lock_decorator.<locals>.proxy_wrapperr   )rR   rT   rS   )rR   r   lock_decorator   s    	z6SSLConnectionProxyMeta.__new__.<locals>.lock_decoratorc                    s    fdd} |_ t|S )rJ   c                    s   t | j S rK   )rN   rO   )r   	property_r   r   proxy_prop_wrapper   s    zQSSLConnectionProxyMeta.__new__.<locals>.make_property.<locals>.proxy_prop_wrapper)r+   property)rX   rY   r   rW   r   make_property   s    z5SSLConnectionProxyMeta.__new__.<locals>.make_property)r+   type)
ZmclnamebasesZnmspcZproxy_methodsZproxy_propsrV   mr[   pr   rU   r   __new__   s    zSSLConnectionProxyMeta.__new__N)r+   r,   r-   r.   ra   r   r   r   r   r4      s   r4   c                   @   s   e Zd ZdZdd ZdS )SSLConnectionzA thread-safe wrapper for an ``SSL.Connection``.

    :param tuple args: the arguments to create the wrapped \
                        :py:class:`SSL.Connection(*args) \
                        <pyopenssl:OpenSSL.SSL.Connection>`
    c                 G   s   t j| | _t | _dS )z"Initialize SSLConnection instance.N)r   
ConnectionrO   	threadingRLockrL   )r   r   r   r   r   __init__   s    zSSLConnection.__init__N)r+   r,   r-   r.   rf   r   r   r   r   rb      s   rb   )	metaclassc                       s`   e Zd ZdZdZdZdZdZdZd fdd	Z	dd Z
dd Zd	d
 Zdd ZdddZ  ZS )pyOpenSSLAdapterz1A wrapper for integrating pyOpenSSL with Cheroot.Nc                    s0   t du rtdtt| |||| d| _dS )z$Initialize OpenSSL Adapter instance.Nz(You must install pyOpenSSL to use HTTPS.)r   ImportErrorr!   rh   rf   _environ)r   certificateprivate_keycertificate_chainciphersr%   r   r   rf   
  s    
zpyOpenSSLAdapter.__init__c                 C   s.   | j du r|  | _ t| j |}|  | _|S )z!Wrap and return the given socket.N)contextr5   rb   get_environrj   )r   sockconnr   r   r   r9     s
    


zpyOpenSSLAdapter.bindc                 C   s   || j  fS )z<Wrap and return the given socket, plus WSGI environ entries.)rj   copy)r   rq   r   r   r   wrap   s    zpyOpenSSLAdapter.wrapc                 C   s:   t t j}|| j | jr*|| j || j |S )z~Return an ``SSL.Context`` from self attributes.

        Ref: :py:class:`SSL.Context <pyopenssl:OpenSSL.SSL.Context>`
        )	r   ContextZSSLv23_METHODZuse_privatekey_filerl   rm   load_verify_locationsZuse_certificate_filerk   )r   cr   r   r   r5   '  s    zpyOpenSSLAdapter.get_contextc                 C   sJ  dddt jjtjjtjjtjf ttj	
 d}| jrFt| jd"}ttj| }W d   n1 sp0    Y  || | d d| fd	| ffD ]\}}t|d
d }d| }|||< |r|d}|d| ||d d  }}	|d}|d| ||d d  }}
|
r|	rd||
f }|	||< qq|S )z;Return WSGI environ entries to be merged into each request.httpsonz%s %s/%s Python/%s)zwsgi.url_schemeHTTPSZSSL_VERSION_INTERFACEZSSL_VERSION_LIBRARYrbN)ZSSL_SERVER_M_VERSIONZSSL_SERVER_M_SERIALIS   zSSL_SERVER_%s_DN=r   /zSSL_SERVER_%s_DN_%s)cheroot_serverZ
HTTPServerversionOpenSSL	__title____version__sysr   ZSSLeay_versionZSSLEAY_VERSIONdecoderk   openr   Zload_certificateZFILETYPE_PEMr8   updateget_versionZget_serial_numberZ
get_issuerZget_subjectstrrfind)r   Zssl_environ	cert_filecertprefixdnZdnstrZwsgikeyposvaluekeyr   r   r   rp   4  sF    
"




zpyOpenSSLAdapter.get_environrr   c                 C   sJ   d|v rt nt}tr8t|tr8||||}| |_|S t|||S dS )zReturn socket file object.r   N)	r0   r3   r   
isinstancessl_conn_typerG   r   r   ZCP_fileobject)r   rq   modebufsizeclsZwrapped_socketr   r   r   rD   l  s    
zpyOpenSSLAdapter.makefile)NN)r   r   )r+   r,   r-   r.   rk   rl   rm   ro   rn   rf   r9   rt   r5   rp   rD   r/   r   r   r%   r   rh      s     8rh   )r.   r   r   rd   r   ZOpenSSL.versionr   r   r   rc   r   AttributeErrorZConnectionTyperi    r   r   r   r   rD   r	   r
   r   r0   r3   r4   rb   rh   r   r   r   r   <module>   s.   4

Z8