U
    (Q^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   C/tmp/pip-install-bd4o36v9/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 | |pd |d k	r"t|d}|| _|| _| jtkrFtjddd d S )Nr   utf-8zThe 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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 )zTrue if the session should be saved.  By default this is only true
        for :attr:`modified` cookies, not :attr:`new`.
        )modifiedr(   r   r   r   r'      s    zSecureCookie.should_savec                 C   s>   | j dk	r| j |}| jr:dtt|d  }|S )zQuote 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   sL   z,| j rt|}| jdk	r(| j|}|W S  tk
rF   t Y nX dS )zUnquote 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   r3   r   r   r   unquote   s    

zSecureCookie.unquotec                 C   s   | j dkrtd|r"t|| d< g }t| j d| j}t|  D ]B\}}|dt|| 	|
df d |d|d   qBd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   r6   decodeencodeupdater.   r/   r0   digestr2   )r    expiresresultmackeyr5   r   r   r   	serialize   s    

zSecureCookie.serializec              	   C   s  t |tr|dd}t |tr,|dd}z|dd\}}W n ttfk
r^   d}Y n@X i }t|d| j}|dD ]j}|d|  d	|krd} q|d	d\}}	t	|
d
}zt|}W n tk
r   Y nX |	||< q|zt|}
W n tk
r   d }}
Y nX |dk	rt|
| rz&t|D ]\}}	| |	||< q:W n tk
rp   d}Y n(X d|krt |d krd}n|d= nd}| ||dS )zLoad 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`.
        r   replacer?      r   Nr@   r=      =r<   r;   F)
isinstancer   rH   split
ValueError
IndexErrorrB   rC   rI   r   rG   r	   UnicodeErrorr/   r7   	TypeErrorr   rJ   r   r:   r   r   )r4   stringr   Zbase64_hashr!   rE   rM   itemrN   r5   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   )cookiesgetr[   )r4   requestrN   r   r!   r   r   r   load_cookie5  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.
        )rK   max_agepathdomainsecurehttponlyN)r'   rO   
set_cookie)r    responserN   rK   Zsession_expiresrb   rc   rd   re   rf   forcer!   r   r   r   save_cookieG  s    
zSecureCookie.save_cookie)NNT)N)r\   N)	r\   NNNra   NNFF)r   r   r   r   staticmethod_default_hashrC   r   r   r-   r   r&   propertyr'   classmethodr6   r:   rO   r[   r`   rj   r   r   r   r   r   y   s6   





6         r   )r   r/   r   r   hashlibr   rl   rB   r   r   _compatr   r   r   r	   	_internalr
   Zcontrib.sessionsr   securityr   urlsr   r   r   DeprecationWarningr9   r   r   r   r   r   r   <module>   s,   Y	