3
 [ð]3  ã               @   sà   d 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 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 ddlmZ ddlmZ ejdedd� 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: 2007 Pallets
    :license: BSD-3-Clause
é    N)Úsha1)Únew)Útimeé   )Ú	iteritems)Ú	text_type)Úto_bytes)Ú	to_native)Ú_date_to_unix)ÚModificationTrackingDict)Úsafe_str_cmp)Úurl_quote_plus)Úurl_unquote_pluszž'werkzeug.contrib.securecookie' is deprecated as of version 0.15 and will be removed in version 1.0. It has moved to https://github.com/pallets/secure-cookie.)Ú
stacklevelc               @   s   e Zd ZdZdS )ÚUnquoteErrorz6Internal exception used to signal failures on quoting.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   úA/tmp/pip-build-w1as9q70/Werkzeug/werkzeug/contrib/securecookie.pyr   u   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   sJ   t j| |pf ƒ |d k	r"t|dƒ}|| _|| _| jtkrFtjddd� d S )Nzutf-8z«The default 'SecureCookie.serialization_method' will change from pickle to json in version 1.0. To upgrade existing tokens, override 'unquote' to try pickle if json fails.r   )r   )	r   Ú__init__r   Ú
secret_keyr   Úserialization_methodÚpickleÚwarningsÚwarn)ÚselfÚdatar   r   r   r   r   r   £   s    

zSecureCookie.__init__c             C   s"   d| j jtj| ƒ| jrdn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`.
        )Úmodified)r   r   r   r   r%   ¼   s    zSecureCookie.should_savec             C   s>   | j dk	r| j j|ƒ}| jr:djtjt|dƒƒjƒ ƒjƒ }|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ó    Úutf8)	r   ÚdumpsÚquote_base64ÚjoinÚbase64Ú	b64encoder   Ú
splitlinesÚstrip)ÚclsÚvaluer   r   r   ÚquoteÃ   s    
zSecureCookie.quotec             C   sJ   y*| j rtj|ƒ}| jdk	r(| j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   )r0   r1   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| jƒ ƒD ]B\}}|jdt|ƒ| j	|ƒj
dƒf jdƒƒ |jd|d
  ƒ qDW djtj|jƒ ƒjƒ d	j|ƒ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   r2   ÚdecodeÚencodeÚupdater+   r,   r-   Údigestr/   )r   ÚexpiresÚresultÚmacÚkeyr1   r   r   r   Ú	serializeå   s    

zSecureCookie.serializec             C   s°  t |tƒr|jddƒ}t |tƒr,|jddƒ}y|jddƒ\}}W n ttfk
r^   f }Y �nFX i }t|d| jƒ}xv|jdƒD ]h}|jd| ƒ d|kržd}P |jddƒ\}}	t	|j
d	ƒƒ}yt|ƒ}W n tk
rÜ   Y nX |	||< q~W ytj|ƒ}
W n tk
�r   d }}
Y nX |dk	�r t|
|jƒ ƒ�r y*x$t|ƒD ]\}}	| j|	ƒ||< �q>W W n tk
�rv   f }Y n(X d
|k�r¤tƒ |d
 k�r˜f }n|d
= nf }| ||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Úreplacer;   r:   Nr<   r9   ó   =r8   r7   F)Ú
isinstancer   rE   ÚsplitÚ
ValueErrorÚ
IndexErrorr?   r@   rF   r   rD   r	   ÚUnicodeErrorr,   r3   Ú	TypeErrorr   rG   r   r6   r   r   )r0   Ústringr   Zbase64_hashr   rB   rJ   ÚitemrK   r1   Zclient_hashr   r   r   Úunserializeþ   sL    



zSecureCookie.unserializeÚsessionc             C   s&   |j j|ƒ}|s| |d�S | j||ƒ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   )ÚcookiesÚgetrW   )r0   ÚrequestrK   r   r   r   r   r   Úload_cookie5  s    
zSecureCookie.load_cookieú/Fc          
   C   s6   |
s
| j r2| j|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.
        )rH   Úmax_ageÚpathÚdomainÚsecureÚhttponlyN)r%   rL   Ú
set_cookie)r   ÚresponserK   rH   Zsession_expiresr^   r_   r`   ra   rb   Úforcer   r   r   r   Úsave_cookieG  s    
zSecureCookie.save_cookie)NNT)N)rX   N)	rX   NNNr]   NNFF)r   r   r   r   ÚstaticmethodÚ_default_hashr@   r   r   r*   r   r$   Úpropertyr%   Úclassmethodr2   r6   rL   rW   r\   rf   r   r   r   r   r   y   s,   

7        r   )r   r,   r   r   Úhashlibr   rh   r?   r   r   Ú_compatr   r   r   r	   Z	_internalr
   Zcontrib.sessionsr   Úsecurityr   Úurlsr   r   r   ÚDeprecationWarningr5   r   r   r   r   r   r   Ú<module>Z   s*   