U
    PN^"-                     @   s  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mZm	Z	m
Z
mZ d dlmZmZm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 dZeeZdddZ dddZ!d ddZ"G dd deZ#G dd de$Z%G dd de%Z&G dd deZ'dd Z(dS )!    N)wraps)	Blueprintcurrent_appgrequestsession)BadDataSignatureExpiredURLSafeTimedSerializer)
BadRequest)safe_str_cmp)ValidationError)CSRF   )FlaskWTFDeprecationWarningstring_typesurlparse)generate_csrfvalidate_csrfCSRFProtectc                 C   sv   t | dtjdd} t |dddd}|tkrl|tkrJttd	 t|< t
| dd	}tt||t|  t|S )
a  Generate a CSRF token. The token is cached for a request, so multiple
    calls to this function will generate the same token.

    During testing, it might be useful to access the signed token in
    ``g.csrf_token`` and the raw token in ``session['csrf_token']``.

    :param secret_key: Used to securely sign the token. Default is
        ``WTF_CSRF_SECRET_KEY`` or ``SECRET_KEY``.
    :param token_key: Key where token is stored in session for comparision.
        Default is ``WTF_CSRF_FIELD_NAME`` or ``'csrf_token'``.
    WTF_CSRF_SECRET_KEY%A secret key is required to use CSRF.messageWTF_CSRF_FIELD_NAME
csrf_token%A field name is required to use CSRF.@   wtf-csrf-tokenZsalt)_get_configr   
secret_keyr   r   hashlibsha1osurandom	hexdigestr
   setattrdumpsget)r!   	token_key
field_names r-   5/tmp/pip-install-o1yuzyg2/flask-wtf/flask_wtf/csrf.pyr      s$        r   c                 C   s   t |dtjdd}t |dddd}t |ddd	d
}| s>td|tkrNtdt|dd}z|j| |d}W n6 tk
r   tdY n tk
r   tdY nX t	t| |stddS )a   Check if the given data is a valid CSRF token. This compares the given
    signed token to the one stored in the session.

    :param data: The signed CSRF token to be checked.
    :param secret_key: Used to securely sign the token. Default is
        ``WTF_CSRF_SECRET_KEY`` or ``SECRET_KEY``.
    :param time_limit: Number of seconds that the token is valid. Default is
        ``WTF_CSRF_TIME_LIMIT`` or 3600 seconds (60 minutes).
    :param token_key: Key where token is stored in session for comparision.
        Default is ``WTF_CSRF_FIELD_NAME`` or ``'csrf_token'``.

    :raises ValidationError: Contains the reason that validation failed.

    .. versionchanged:: 0.14
        Raises ``ValidationError`` with a specific error message rather than
        returning ``True`` or ``False``.
    r   r   r   r   r   r   WTF_CSRF_TIME_LIMIT  F)requiredzThe CSRF token is missing.z"The CSRF session token is missing.r   r   )Zmax_agezThe CSRF token has expired.zThe CSRF token is invalid.zThe CSRF tokens do not match.N)
r    r   r!   r   r   r
   loadsr	   r   r   )datar!   Z
time_limitr*   r+   r,   tokenr-   r-   r.   r   4   s>           r   TCSRF is not configured.c                 C   s.   | dkrt j||} |r*| dkr*t|| S )a  Find config value based on provided value, Flask config, and default
    value.

    :param value: already provided config value
    :param config_name: Flask ``config`` key
    :param default: default value if not provided or configured
    :param required: whether the value must not be ``None``
    :param message: error message if required config is not found
    :raises KeyError: if required config is not found
    N)r   configr)   KeyError)valueZconfig_namedefaultr1   r   r-   r-   r.   r    f   s
    r    c                       s,   e Zd Z fddZdd Zdd Z  ZS )_FlaskFormCSRFc                    s   |j | _ tt| |S N)metasuperr:   
setup_form)selfform	__class__r-   r.   r>      s    z_FlaskFormCSRF.setup_formc                 C   s   t | jj| jjdS )N)r!   r*   )r   r<   csrf_secretcsrf_field_name)r?   Zcsrf_token_fieldr-   r-   r.   generate_csrf_token   s    z"_FlaskFormCSRF.generate_csrf_tokenc              
   C   sj   t ddrd S z t|j| jj| jj| jj W n4 tk
rd } zt	
|jd   W 5 d }~X Y nX d S )N
csrf_validFr   )r   r)   r   r3   r<   rC   Zcsrf_time_limitrD   r   loggerinfoargs)r?   r@   fielder-   r-   r.   validate_csrf_token   s    z"_FlaskFormCSRF.validate_csrf_token)__name__
__module____qualname__r>   rE   rL   __classcell__r-   r-   rA   r.   r:   ~   s   r:   c                   @   sJ   e Zd 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S )r   a[  Enable CSRF protection globally for a Flask app.

    ::

        app = Flask(__name__)
        csrf = CsrfProtect(app)

    Checks the ``csrf_token`` field sent with forms, or the ``X-CSRFToken``
    header sent with JavaScript requests. Render the token in templates using
    ``{{ csrf_token() }}``.

    See the :ref:`csrf` documentation.
    Nc                 C   s"   t  | _t  | _|r| | d S r;   )set_exempt_views_exempt_blueprintsinit_appr?   appr-   r-   r.   __init__   s    zCSRFProtect.__init__c                    s    j d<  jdd  jdd t jddddd	g jd<  jd
d  jdddg  jdd  jdd t jjd<  dd   j	 fdd}d S )NZcsrfWTF_CSRF_ENABLEDTWTF_CSRF_CHECK_DEFAULTWTF_CSRF_METHODSPOSTPUTPATCHDELETEr   r   WTF_CSRF_HEADERSzX-CSRFTokenzX-CSRF-Tokenr/   r0   WTF_CSRF_SSL_STRICTc                   S   s   dt iS )Nr   )r   r-   r-   r-   r.   <lambda>       z&CSRFProtect.init_app.<locals>.<lambda>c                     s    j d sd S  j d sd S tj j d kr0d S tjs:d S  jtj} | sPd S tjjkr`d S d| j| j	f }|j
kr~d S   d S )NrX   rY   rZ   %s.%s)r6   r   methodZendpointZview_functionsr)   Z	blueprintrS   rN   rM   rR   protect)viewdestrV   r?   r-   r.   csrf_protect   s"    


z*CSRFProtect.init_app.<locals>.csrf_protect)

extensionsr6   
setdefaultrQ   r)   r   Z	jinja_envglobalsZcontext_processorZbefore_request)r?   rV   ri   r-   rh   r.   rT      s$    
 
 zCSRFProtect.init_appc                 C   sb   t jd }tjD ]$}||rtj| }|r|  S qt jd D ]}tj|}|r@|  S q@d S )Nr   r_   )r   r6   r   r@   endswithheadersr)   )r?   r+   keyr   header_namer-   r-   r.   _get_csrf_token   s    





zCSRFProtect._get_csrf_tokenc              
   C   s   t jtjd krd S zt|   W nB tk
rf } z$t|j	d  | 
|j	d  W 5 d }~X Y nX t jrtjd rt js| 
d dt j}tt j|s| 
d dt_d S )NrZ   r   r`   zThe referrer header is missing.zhttps://{0}/z%The referrer does not match the host.T)r   rd   r   r6   r   rq   r   rG   rH   rI   _error_responseZ	is_secureZreferrerformathostsame_originr   rF   )r?   rK   Zgood_referrerr-   r-   r.   re      s    "

zCSRFProtect.protectc                 C   sL   t |tr| j|j |S t |tr,|}nd|j|jf }| j| |S )a  Mark a view or blueprint to be excluded from CSRF protection.

        ::

            @app.route('/some-view', methods=['POST'])
            @csrf.exempt
            def some_view():
                ...

        ::

            bp = Blueprint(...)
            csrf.exempt(bp)

        rc   )	
isinstancer   rS   addnamer   rN   rM   rR   )r?   rf   Zview_locationr-   r-   r.   exempt	  s    

zCSRFProtect.exemptc                 C   s   t |d S r;   )	CSRFError)r?   reasonr-   r-   r.   rr   &  s    zCSRFProtect._error_responsec                    s0   t jtddd t  fdd}|| _ S )a  Register a function that will generate the response for CSRF errors.

        .. deprecated:: 0.14
            Use the standard Flask error system with
            ``@app.errorhandler(CSRFError)`` instead. This will be removed in
            version 1.0.

        The function will be passed one argument, ``reason``. By default it will
        raise a :class:`~flask_wtf.csrf.CSRFError`. ::

            @csrf.error_handler
            def csrf_error(reason):
                return render_template('error.html', reason=reason)

        Due to historical reasons, the function may either return a response
        or raise an exception with :func:`flask.abort`.
        z"@csrf.error_handler" is deprecated. Use the standard Flask error system with "@app.errorhandler(CSRFError)" instead. This will beremoved in 1.0.   
stacklevelc                    s&   t  | }t|jdd|dd S )NT)Zas_text)response)r   Zmake_responserz   get_data)r{   r   rf   r-   r.   handlerB  s    z*CSRFProtect.error_handler.<locals>.handler)warningswarnr   r   rr   )r?   rf   r   r-   r   r.   error_handler)  s    zCSRFProtect.error_handler)N)rM   rN   rO   __doc__rW   rT   rq   re   ry   rr   r   r-   r-   r-   r.   r      s   
/r   c                       s"   e Zd ZdZd fdd	Z  ZS )CsrfProtectzW
    .. deprecated:: 0.14
        Renamed to :class:`~flask_wtf.csrf.CSRFProtect`.
    Nc                    s(   t jtddd tt| j|d d S )NzU"flask_wtf.CsrfProtect" has been renamed to "CSRFProtect" and will be removed in 1.0.r|   r}   )rV   )r   r   r   r=   r   rW   rU   rA   r-   r.   rW   Q  s    zCsrfProtect.__init__)N)rM   rN   rO   r   rW   rP   r-   r-   rA   r.   r   K  s   r   c                   @   s   e Zd ZdZdZdS )rz   zRaise if the client sends invalid CSRF data with the request.

    Generates a 400 Bad Request response with the failure reason by default.
    Customize the response by registering a handler with
    :meth:`flask.Flask.errorhandler`.
    zCSRF validation failed.N)rM   rN   rO   r   descriptionr-   r-   r-   r.   rz   Y  s   rz   c                 C   s4   t | }t |}|j|jko2|j|jko2|j|jkS r;   )r   schemehostnameport)Zcurrent_uriZcompare_uricurrentcomparer-   r-   r.   ru   d  s    

ru   )NN)NNN)NTr5   ))r"   loggingr$   r   	functoolsr   Zflaskr   r   r   r   r   Zitsdangerousr   r	   r
   Zwerkzeug.exceptionsr   Zwerkzeug.securityr   Zwtformsr   Zwtforms.csrf.corer   _compatr   r   r   __all__	getLoggerrM   rG   r   r   r    r:   objectr   r   rz   ru   r-   r-   r-   r.   <module>   s2   

 
3    
 2