U
    !d6                     @   s  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 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dd Zd@ddZdAddZdd Zdd ZdBd d!Z d"d# Z!d$d% Z"dCd(d)Z#d*d+ Z$d,d- Z%d.d/ Z&d0d1 Z'dDd2d3Z(d4d5 Z)dEd6d7Z*d8d9 Z+d:d; Z,d<d= Z-dFd>d?Z.dS )G    Nwraps)sha512)urlparse)
urlunparse)current_app)g)has_request_context)request)session)url_for)
LocalProxy)
url_decode)
url_encode   )COOKIE_NAME)EXEMPT_METHODS)user_logged_in)user_logged_out)user_login_confirmedc                   C   s   t  S )N)	_get_user r   r   5/tmp/pip-unpacked-wheel-9qbqs8oa/flask_login/utils.py<lambda>       r   c                 C   s   |  dt | |d S )aa  
    This will encode a ``str`` value into a cookie, and sign that cookie
    with the app's secret key.

    :param payload: The value to encode, as `str`.
    :type payload: str

    :param key: The key to use when creating the cookie digest. If not
                specified, the SECRET_KEY value from app config will be used.
    :type key: str
    |key)_cookie_digestpayloadr   r   r   r   encode_cookie   s    r!   c                 C   s\   z(|  dd\}}t|dr&|d}W n tk
r>   Y dS X tt||d|rX|S dS )an  
    This decodes a cookie given by `encode_cookie`. If verification of the
    cookie fails, ``None`` will be implicitly returned.

    :param cookie: An encoded cookie.
    :type cookie: str

    :param key: The key to use when creating the cookie digest. If not
                specified, the SECRET_KEY value from app config will be used.
    :type key: str
    r   r   decodeasciiNr   )rsplithasattrr"   
ValueErrorhmaccompare_digestr   )cookier   r    digestr   r   r   decode_cookie+   s    
r+   c                 C   sR   t | }t |}|jr"|j|jkrN|jr4|j|jkrNtdd|j|j|jdfS |S )a  
    Reduces the scheme and host from a given URL so it can be passed to
    the given `login` URL more efficiently.

    :param login_url: The login URL being redirected to.
    :type login_url: str
    :param current_url: The URL to reduce.
    :type current_url: str
     )r   schemenetlocr   pathparamsquery)	login_urlZcurrent_urlZl_urlZc_urlr   r   r   make_next_paramB   s    

r3   c                 C   s   |  dr| S t| S )z
    Returns the url for the login view, expanding the view name to a url if
    needed.

    :param login_view: The name of the login view or a URL for the login view.
    :type login_view: str
    )zhttps://zhttp:///)
startswithr   )
login_viewr   r   r   expand_login_viewV   s    
r7   nextc                 C   sd   t | }|dkr|S t|}t|j}t||||< tjdpD|j}|j	|t
|ddd}t|S )a  
    Creates a URL for redirecting to a login page. If only `login_view` is
    provided, this will just return the URL for it. If `next_url` is provided,
    however, this will append a ``next=URL`` parameter to the query string
    so that the login view can redirect back to that URL. Flask-Login's default
    unauthorized handler uses this function when redirecting to your login url.
    To force the host name used, set `FORCE_HOST_FOR_REDIRECTS` to a host. This
    prevents from redirecting to external sites if request headers Host or
    X-Forwarded-For are present.

    :param login_view: The name of the login view. (Alternately, the actual
                       URL to the login view.)
    :type login_view: str
    :param next_url: The URL to give the login view for redirection.
    :type next_url: str
    :param next_field: What field to store the next URL in. (It defaults to
                       ``next``.)
    :type next_field: str
    NZFORCE_HOST_FOR_REDIRECTST)sort)r.   r1   )r7   r   r   r1   r3   r   configgetr.   _replacer   r   )r6   Znext_urlZ
next_fieldbaseparsed_resultZmdr.   r   r   r   r2   d   s    
 
r2   c                   C   s   t ddS )z>
    This returns ``True`` if the current login is fresh.
    _freshF)r   r;   r   r   r   r   login_fresh   s    r@   c                  C   sL   t j} | dt}|tjko(tddk}|rHtj| }t|}|dk	S dS )zS
    This returns ``True`` if the current login is remembered across sessions.
    REMEMBER_COOKIE_NAME	_rememberclearNF)r   r:   r;   r   r
   cookiesr   r+   )r:   cookie_nameZ
has_cookier)   user_idr   r   r   login_remembered   s    
rG   FTc              
   C   s   |s| j sdS t| tjj }|td< |td< tj td< |rdtd< |dk	rz*|j|j|j	d d	  d
  d td< W n2 t
k
r } ztd| |W 5 d}~X Y nX tj|  tjt t d dS )a  
    Logs a user in. You should pass the actual user object to this. If the
    user's `is_active` property is ``False``, they will not be logged in
    unless `force` is ``True``.

    This will return ``True`` if the log in attempt succeeds, and ``False`` if
    it fails (i.e. because the user is inactive).

    :param user: The user object to log in.
    :type user: object
    :param remember: Whether to remember the user after their session expires.
        Defaults to ``False``.
    :type remember: bool
    :param duration: The amount of time before the remember cookie expires. If
        ``None`` the value set in the settings is used. Defaults to ``None``.
    :type duration: :class:`datetime.timedelta`
    :param force: If the user is inactive, setting this to ``True`` will log
        them in regardless. Defaults to ``False``.
    :type force: bool
    :param fresh: setting this to ``False`` will log in the user with a session
        marked as not "fresh". Defaults to ``True``.
    :type fresh: bool
    F_user_idr?   _idsetrB   N   i  i@B g    .A_remember_secondsz4duration must be a datetime.timedelta, instead got: userT)Z	is_activegetattrr   login_managerZid_attributer   _session_identifier_generatormicrosecondssecondsdaysAttributeError	Exception!_update_request_context_with_userr   send_get_current_objectr   )rN   ZrememberdurationforceZfreshrF   er   r   r   
login_user   s0    
r]   c                  C   s   t  } dtkrtd dtkr*td dtkr<td tjdt}|tjkrndtd< dtkrntd t	j
t | d tj  d	S )
z
    Logs a user out. (You do not need to pass the actual user.) This will
    also clean up the remember me cookie if it exists.
    rH   r?   rI   rA   rC   rB   rL   rM   T)r   r   popr   r:   r;   r   r
   rD   r   rX   rY   rP   rW   )rN   rE   r   r   r   logout_user   s    





r_   c                   C   s(   dt d< tj t d< tt  dS )zq
    This sets the current session as fresh. Sessions become stale when they
    are reloaded from a cookie.
    Tr?   rI   N)r   r   rP   rQ   r   rX   rY   r   r   r   r   confirm_login   s    r`   c                    s   t   fdd}|S )al  
    If you decorate a view with this, it will ensure that the current user is
    logged in and authenticated before calling the actual view. (If they are
    not, it calls the :attr:`LoginManager.unauthorized` callback.) For
    example::

        @app.route('/post')
        @login_required
        def post():
            pass

    If there are only certain times you need to require that your user is
    logged in, you can do so with::

        if not current_user.is_authenticated:
            return current_app.login_manager.unauthorized()

    ...which is essentially the code that this function adds to your views.

    It can be convenient to globally turn off authentication when unit testing.
    To enable this, if the application configuration variable `LOGIN_DISABLED`
    is set to `True`, this decorator will be ignored.

    .. Note ::

        Per `W3 guidelines for CORS preflight requests
        <http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0>`_,
        HTTP ``OPTIONS`` requests are exempt from login checks.

    :param func: The view function to decorate.
    :type func: function
    c                     sR   t jtks(tjdrntjs(tj	 S t
ttdd rHt | |S  | |S )NLOGIN_DISABLEDensure_sync)r
   methodr   r   r:   r;   current_useris_authenticatedrP   unauthorizedcallablerO   rb   argskwargsfuncr   r   decorated_view  s    
z&login_required.<locals>.decorated_viewr   rl   rm   r   rk   r   login_required   s    "ro   c                    s   t   fdd}|S )a  
    If you decorate a view with this, it will ensure that the current user's
    login is fresh - i.e. their session was not restored from a 'remember me'
    cookie. Sensitive operations, like changing a password or e-mail, should
    be protected with this, to impede the efforts of cookie thieves.

    If the user is not authenticated, :meth:`LoginManager.unauthorized` is
    called as normal. If they are authenticated, but their session is not
    fresh, it will call :meth:`LoginManager.needs_refresh` instead. (In that
    case, you will need to provide a :attr:`LoginManager.refresh_view`.)

    Behaves identically to the :func:`login_required` decorator with respect
    to configuration variables.

    .. Note ::

        Per `W3 guidelines for CORS preflight requests
        <http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0>`_,
        HTTP ``OPTIONS`` requests are exempt from login checks.

    :param func: The view function to decorate.
    :type func: function
    c                     sn   t jtks8tjdrn tjs(tj	 S t
 s8tj S zt | |W S  tk
rh    | | Y S X d S )Nra   )r
   rc   r   r   r:   r;   rd   re   rP   rf   r@   Zneeds_refreshrb   rU   rh   rk   r   r   rm   A  s    

z,fresh_login_required.<locals>.decorated_viewr   rn   r   rk   r   fresh_login_required(  s    rp   c                 C   sh   t tjj}|dk	s|dkr\| tjj|j< tjjdk	rRdtjjkrRtjjtjjd< dtj_n| tj_dS )ao  
    Sets the login view for the app or blueprint. If a blueprint is passed,
    the login view is set for this blueprint on ``blueprint_login_views``.

    :param login_view: The user object to log in.
    :type login_view: str
    :param blueprint: The blueprint which this login view should be set on.
        Defaults to ``None``.
    :type blueprint: object
    Nr   )lenr   rP   Zblueprint_login_viewsnamer6   )r6   Z	blueprintZnum_login_viewsr   r   r   set_login_viewR  s    



rs   c                   C   s"   t  rdtkrtj  tjS d S )N_login_user)r	   r   r   rP   Z
_load_userrt   r   r   r   r   r   q  s
    
r   c                 C   s    t |}t|| dt S )Nutf-8)_secret_keyr'   newencoder   	hexdigestr   r   r   r   r   {  s    r   c                  C   s4   t jdt j} | d k	r0| ddd  } | S )NzX-Forwarded-Forru      ,r   )r
   headersr;   Zremote_addrrx   splitstrip)addressr   r   r   _get_remote_addr  s    r   c                  C   sb   t jd} | d k	r| d} t  d|  }ttkrDt|ddd}t }||d |	 S )Nz
User-Agentru   r   replace)errorsutf8)
r
   r{   r;   rx   r   strbytesr   updatery   )
user_agentr=   hr   r   r   _create_identifier  s    
r   c                   C   s   t t dS )N)rd   )dictr   r   r   r   r   _user_context_processor  s    r   c                 C   s*   | d krt jd } t| tr&| d} | S )NZ
SECRET_KEYlatin1)r   r:   
isinstancer   rx   r   r   r   r   rv     s
    


rv   )N)N)Nr8   )FNFT)N)N)N)/r'   	functoolsr   hashlibr   urllib.parser   r   Zflaskr   r   r	   r
   r   r   Zwerkzeug.localr   Zwerkzeug.urlsr   r   r:   r   r   Zsignalsr   r   r   rd   r!   r+   r3   r7   r2   r@   rG   r]   r_   r`   ro   rp   rs   r   r   r   r   r   rv   r   r   r   r   <module>   sL   


#
3
2*


	