B
    ¬]BZ¤/  ã               @   s°   d 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
mZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddl	mZ G dd„ deƒZG dd„ deƒZdS )a  
    werkzeug.contrib.securecookie
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    This module implements a cookie that is not alterable from the client
    because it adds a checksum the server checks for.  You can use it as
    session replacement if all you have is a user id or something to mark
    a logged in user.

    Keep in mind that the data is still readable from the client as a
    normal cookie is.  However you don't have to store and flush the
    sessions you have at the server.

    Example usage:

    >>> from werkzeug.contrib.securecookie import SecureCookie
    >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")

    Dumping into a string so that one can store it in a cookie:

    >>> value = x.serialize()

    Loading from that string again:

    >>> x = SecureCookie.unserialize(value, "deadbeef")
    >>> x["baz"]
    (1, 2, 3)

    If someone modifies the cookie and the checksum is wrong the unserialize
    method will fail silently and return a new empty `SecureCookie` object.

    Keep in mind that the values will be visible in the cookie so do not
    store data in a cookie you don't want the user to see.

    Application Integration
    =======================

    If you are using the werkzeug request objects you could integrate the
    secure cookie into your application like this::

        from werkzeug.utils import cached_property
        from werkzeug.wrappers import BaseRequest
        from werkzeug.contrib.securecookie import SecureCookie

        # don't use this key but a different one; you could just use
        # os.urandom(20) to get something random
        SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'

        class Request(BaseRequest):

            @cached_property
            def client_session(self):
                data = self.cookies.get('session_data')
                if not data:
                    return SecureCookie(secret_key=SECRET_KEY)
                return SecureCookie.unserialize(data, SECRET_KEY)

        def application(environ, start_response):
            request = Request(environ)

            # get a response object here
            response = ...

            if request.client_session.should_save:
                session_data = request.client_session.serialize()
                response.set_cookie('session_data', session_data,
                                    httponly=True)
            return response(environ, start_response)

    A less verbose integration can be achieved by using shorthand methods::

        class Request(BaseRequest):

            @cached_property
            def client_session(self):
                return SecureCookie.load_cookie(self, secret_key=COOKIE_SECRET)

        def application(environ, start_response):
            request = Request(environ)

            # get a response object here
            response = ...

            request.client_session.save_cookie(response)
            return response(environ, start_response)

    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
    :license: BSD, see LICENSE for more details.
é    N)Únew)Útime)Úsha1)Ú	iteritemsÚ	text_typeÚto_bytes)Úurl_quote_plusÚurl_unquote_plus)Ú_date_to_unix)ÚModificationTrackingDict)Úsafe_str_cmp)Ú	to_nativec               @   s   e Zd ZdZdS )ÚUnquoteErrorz6Internal exception used to signal failures on quoting.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   ú<lib/python3.7/site-packages/werkzeug/contrib/securecookie.pyr   i   s   r   c            	   @   s„   e Zd ZdZeeƒZeZdZ	ddd„Z
dd„ Zedd	„ ƒZed
d„ ƒZedd„ ƒZddd„Zedd„ ƒZeddd„ƒZddd„ZdS )ÚSecureCookieaá  Represents a secure cookie.  You can subclass this class and provide
    an alternative mac method.  The import thing is that the mac method
    is a function with a similar interface to the hashlib.  Required
    methods are update() and digest().

    Example usage:

    >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
    >>> x["foo"]
    42
    >>> x["baz"]
    (1, 2, 3)
    >>> x["blafasel"] = 23
    >>> x.should_save
    True

    :param data: the initial data.  Either a dict, list of tuples or `None`.
    :param secret_key: the secret key.  If not set `None` or not specified
                       it has to be set before :meth:`serialize` is called.
    :param new: The initial value of the `new` flag.
    TNc             C   s2   t  | |pd¡ |d k	r"t|dƒ}|| _|| _d S )Nr   zutf-8)r   Ú__init__r   Ú
secret_keyr   )ÚselfÚdatar   r   r   r   r   r   –   s
    
zSecureCookie.__init__c             C   s"   d| j jt | ¡| jrdpdf S )Nz	<%s %s%s>Ú*Ú )Ú	__class__r   ÚdictÚ__repr__Úshould_save)r   r   r   r   r   Ÿ   s    zSecureCookie.__repr__c             C   s   | j S )z‚True if the session should be saved.  By default this is only true
        for :attr:`modified` cookies, not :attr:`new`.
        )Zmodified)r   r   r   r   r   ¦   s    zSecureCookie.should_savec             C   s8   | j dk	r| j  |¡}| jr4d t |¡ ¡ ¡ ¡ }|S )zžQuote the value for the cookie.  This can be any object supported
        by :attr:`serialization_method`.

        :param value: the value to quote.
        Nó    )Úserialization_methodÚdumpsÚquote_base64ÚjoinÚbase64Ú	b64encodeÚ
splitlinesÚstrip)ÚclsÚvaluer   r   r   Úquote­   s
    
zSecureCookie.quotec             C   sJ   y*| j rt |¡}| jdk	r(| j |¡}|S  tk
rD   tƒ ‚Y nX dS )zœUnquote the value for the cookie.  If unquoting does not work a
        :exc:`UnquoteError` is raised.

        :param value: the value to unquote.
        N)r#   r%   Ú	b64decoder!   ÚloadsÚ	Exceptionr   )r)   r*   r   r   r   Úunquoteº   s    

zSecureCookie.unquotec             C   s¬   | j dkrtdƒ‚|r"t|ƒ| d< g }t| j d| jƒ}xRt|  ¡ ƒD ]B\}}| dt|ƒ|  	|¡ 
d¡f  d¡¡ | d|d  ¡ qDW d t | ¡ ¡ ¡ d	 |¡g¡S )
a{  Serialize the secure cookie into a string.

        If expires is provided, the session will be automatically invalidated
        after expiration when you unseralize it. This provides better
        protection against session cookie theft.

        :param expires: an optional expiration date for the cookie (a
                        :class:`datetime.datetime` object)
        Nzno secret key definedÚ_expiresz%s=%sÚasciió   |éÿÿÿÿó   ?ó   &)r   ÚRuntimeErrorr
   ÚhmacÚhash_methodÚsortedÚitemsÚappendr   r+   ÚdecodeÚencodeÚupdater$   r%   r&   Údigestr(   )r   ÚexpiresÚresultÚmacÚkeyr*   r   r   r   Ú	serializeÍ   s    

zSecureCookie.serializec          	   C   s°  t |tƒr| dd¡}t |tƒr,| dd¡}y| dd¡\}}W n ttfk
r^   d}Y nFX i }t|d| jƒ}xv| d¡D ]h}| d| ¡ d	|kržd}P | d	d¡\}}	t	| 
d
¡ƒ}yt|ƒ}W n tk
rÜ   Y nX |	||< q~W yt |¡}
W n tk
r   d }}
Y nX |dk	r t|
| ¡ ƒr y*x$t|ƒD ]\}}	|  |	¡||< q>W W n tk
rv   d}Y n(X d|kr¤tƒ |d kr˜d}n|d= nd}| ||dƒS )zèLoad the secure cookie from a serialized string.

        :param string: the cookie value to unserialize.
        :param secret_key: the secret key used to serialize the cookie.
        :return: a new :class:`SecureCookie`.
        zutf-8Úreplacer4   é   r   Nr5   r2   ó   =r1   r0   F)Ú
isinstancer   r=   ÚsplitÚ
ValueErrorÚ
IndexErrorr7   r8   r>   r	   r<   r   ÚUnicodeErrorr%   r,   Ú	TypeErrorr   r?   r   r/   r   r   )r)   Ústringr   Zbase64_hashr   r:   rB   ÚitemrC   r*   Zclient_hashr   r   r   Úunserializeè   sL    



zSecureCookie.unserializeÚsessionc             C   s&   |j  |¡}|s| |dS |  ||¡S )a  Loads a :class:`SecureCookie` from a cookie in request.  If the
        cookie is not set, a new :class:`SecureCookie` instanced is
        returned.

        :param request: a request object that has a `cookies` attribute
                        which is a dict of all cookie values.
        :param key: the name of the cookie.
        :param secret_key: the secret key used to unquote the cookie.
                           Always provide the value even though it has
                           no default!
        )r   )ZcookiesÚgetrP   )r)   ZrequestrC   r   r   r   r   r   Úload_cookie  s    
zSecureCookie.load_cookieú/Fc          
   C   s6   |
s
| j r2|  |p|¡}|j||||||||	d dS )a=  Saves the SecureCookie in a cookie on response object.  All
        parameters that are not described here are forwarded directly
        to :meth:`~BaseResponse.set_cookie`.

        :param response: a response object that has a
                         :meth:`~BaseResponse.set_cookie` method.
        :param key: the name of the cookie.
        :param session_expires: the expiration date of the secure cookie
                                stored information.  If this is not provided
                                the cookie `expires` date is used instead.
        )r@   Úmax_ageÚpathÚdomainÚsecureÚhttponlyN)r   rD   Z
set_cookie)r   ZresponserC   r@   Zsession_expiresrU   rV   rW   rX   rY   Zforcer   r   r   r   Úsave_cookie1  s
    
zSecureCookie.save_cookie)NNT)N)rQ   N)	rQ   NNNrT   NNFF)r   r   r   r   ÚstaticmethodÚ_default_hashr8   Úpickler!   r#   r   r   Úpropertyr   Úclassmethodr+   r/   rD   rP   rS   rZ   r   r   r   r   r   n   s    
	
7  r   )r   r]   r%   r7   r   r   Zhashlibr   r\   Zwerkzeug._compatr   r   r   Zwerkzeug.urlsr   r	   Zwerkzeug._internalr
   Zwerkzeug.contrib.sessionsr   Zwerkzeug.securityr   r   r.   r   r   r   r   r   r   Ú<module>Z   s   