U
    ^4I                     @   s   d Z ddlZddlmZmZ ddlmZmZmZmZm	Z	m
Z
mZ ddlmZ ddlmZmZmZmZmZmZmZmZmZmZmZmZ ddlmZ dd	lmZmZm Z m!Z!m"Z"m#Z#m$Z$ dd
l%m&Z&m'Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. G dd de/Z0dS )zY
    flask_login.login_manager
    -------------------------
    The LoginManager class.
    N)datetime	timedelta)_request_ctx_stackabortcurrent_appflashredirectrequestsession   )	text_type)COOKIE_NAMECOOKIE_DURATIONCOOKIE_SECURECOOKIE_HTTPONLYLOGIN_MESSAGELOGIN_MESSAGE_CATEGORYREFRESH_MESSAGEREFRESH_MESSAGE_CATEGORYID_ATTRIBUTEAUTH_HEADER_NAMESESSION_KEYSUSE_SESSION_FOR_NEXT)AnonymousUserMixin)user_loaded_from_cookieuser_loaded_from_headeruser_loaded_from_requestuser_unauthorizeduser_needs_refreshuser_accessedsession_protected)	_get_user	login_url_create_identifier_user_context_processorencode_cookiedecode_cookiemake_next_paramexpand_login_viewc                   @   s   e Zd ZdZd*ddZd+d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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&d' Zd(d) ZdS ).LoginManagerzThis object is used to hold the settings used for logging in. Instances
    of :class:`LoginManager` are *not* bound to specific apps, so you can
    create one in the main body of your code and then bind it to your
    app in a factory function.
    NTc                 C   s~   t | _d | _i | _t| _t| _d | _t	| _
t| _d| _d | _d | _d | _d | _t| _d | _d | _t| _|d k	rz| || d S )Nbasic)r   anonymous_user
login_viewblueprint_login_viewsr   login_messager   login_message_categoryrefresh_viewr   needs_refresh_messager   needs_refresh_message_categorysession_protectionlocalize_callbackuser_callbackunauthorized_callbackneeds_refresh_callbackr   Zid_attributeheader_callbackrequest_callbackr#   _session_identifier_generatorinit_appselfappZadd_context_processor r?   B/tmp/pip-install-hrdtmzsb/flask-login/flask_login/login_manager.py__init__#   s&    zLoginManager.__init__c                 C   s   t dt | || dS )zl
        This method has been deprecated. Please use
        :meth:`LoginManager.init_app` instead.
        z5Warning setup_app is deprecated. Please use init_app.N)warningswarnDeprecationWarningr;   r<   r?   r?   r@   	setup_app_   s    zLoginManager.setup_appc                 C   s4   | |_ || j |jdd| _|r0|t dS )a  
        Configures an application. This registers an `after_request` call, and
        attaches this `LoginManager` to it as `app.login_manager`.

        :param app: The :class:`flask.Flask` object to configure.
        :type app: :class:`flask.Flask`
        :param add_context_processor: Whether to add a context processor to
            the app that adds a `current_user` variable to the template.
            Defaults to ``True``.
        :type add_context_processor: bool
        ZLOGIN_DISABLEDFN)Zlogin_managerZafter_request_update_remember_cookieconfiggetZ_login_disabledZcontext_processorr$   r<   r?   r?   r@   r;   h   s
    zLoginManager.init_appc                 C   s   t t  | jr|  S tj| jkr6| jtj }n| j}|sHt	d | j
r| jdk	rpt| | j
| jd nt| j
| jd tj}|dtrt|}t|tjtd< t|}nt|tjd}t|S )a  
        This is called when the user is required to log in. If you register a
        callback with :meth:`LoginManager.unauthorized_handler`, then it will
        be called. Otherwise, it will take the following actions:

            - Flash :attr:`LoginManager.login_message` to the user.

            - If the app is using blueprints find the login view for
              the current blueprint using `blueprint_login_views`. If the app
              is not using blueprints or the login view for the current
              blueprint is not specified use the value of `login_view`.

            - Redirect the user to the login view. (The page they were
              attempting to access will be passed in the ``next`` query
              string variable, so you can redirect there if present instead
              of the homepage. Alternatively, it will be added to the session
              as ``next`` if USE_SESSION_FOR_NEXT is set.)

        If :attr:`LoginManager.login_view` is not defined, then it will simply
        raise a HTTP 401 (Unauthorized) error instead.

        This should be returned from a view or before/after_request function,
        otherwise the redirect will have no effect.
          Ncategoryr   nextZnext_url)r   sendr   _get_current_objectr6   r	   Z	blueprintr-   r,   r   r.   r4   r   r/   rG   rH   r   r(   r'   urlr
   make_login_urlr   )r=   r,   rG   r"   redirect_urlr?   r?   r@   unauthorized|   s*    

zLoginManager.unauthorizedc                 C   s
   || _ |S )aB  
        This sets the callback for reloading a user from the session. The
        function you set should take a user ID (a ``unicode``) and return a
        user object, or ``None`` if the user does not exist.

        :param callback: The callback for retrieving a user object.
        :type callback: callable
        )r5   r=   callbackr?   r?   r@   user_loader   s    	zLoginManager.user_loaderc                 C   s
   || _ |S )a  
        This function has been deprecated. Please use
        :meth:`LoginManager.request_loader` instead.

        This sets the callback for loading a user from a header value.
        The function you set should take an authentication token and
        return a user object, or `None` if the user does not exist.

        :param callback: The callback for retrieving a user object.
        :type callback: callable
        )r8   rT   r?   r?   r@   header_loader   s    zLoginManager.header_loaderc                 C   s
   || _ |S )a=  
        This sets the callback for loading a user from a Flask request.
        The function you set should take Flask request object and
        return a user object, or `None` if the user does not exist.

        :param callback: The callback for retrieving a user object.
        :type callback: callable
        )r9   rT   r?   r?   r@   request_loader   s    	zLoginManager.request_loaderc                 C   s
   || _ |S )ab  
        This will set the callback for the `unauthorized` method, which among
        other things is used by `login_required`. It takes no arguments, and
        should return a response to be sent to the user instead of their
        normal view.

        :param callback: The callback for unauthorized users.
        :type callback: callable
        )r6   rT   r?   r?   r@   unauthorized_handler   s    
z!LoginManager.unauthorized_handlerc                 C   s
   || _ |S )ai  
        This will set the callback for the `needs_refresh` method, which among
        other things is used by `fresh_login_required`. It takes no arguments,
        and should return a response to be sent to the user instead of their
        normal view.

        :param callback: The callback for unauthorized users.
        :type callback: callable
        )r7   rT   r?   r?   r@   needs_refresh_handler   s    
z"LoginManager.needs_refresh_handlerc                 C   s   t t  | jr|  S | js*td | jdk	rLt| | j	| j
d nt| j	| j
d tj}|dtrt| j}t|tjtd< t| j}n| j}t|tjd}t|S )a  
        This is called when the user is logged in, but they need to be
        reauthenticated because their session is stale. If you register a
        callback with `needs_refresh_handler`, then it will be called.
        Otherwise, it will take the following actions:

            - Flash :attr:`LoginManager.needs_refresh_message` to the user.

            - Redirect the user to :attr:`LoginManager.refresh_view`. (The page
              they were attempting to access will be passed in the ``next``
              query string variable, so you can redirect there if present
              instead of the homepage.)

        If :attr:`LoginManager.refresh_view` is not defined, then it will
        simply raise a HTTP 401 (Unauthorized) error instead.

        This should be returned from a view or before/after_request function,
        otherwise the redirect will have no effect.
        rI   NrJ   r   rL   rM   )r   rN   r   rO   r7   r0   r   r4   r   r1   r2   rG   rH   r   r(   r'   r	   rP   r
   rQ   r   )r=   rG   r"   rR   r?   r?   r@   needs_refresh   s(    

zLoginManager.needs_refreshc                 C   sn   t j}|dkrdtd}|dkr,|  |_qj| jdkr>td| |}|dkr\|  |_qj||_n||_dS )a  
        This set the ctx.user with the user object loaded by your customized
        user_loader callback function, which should retrieved the user object
        with the user_id got from session.

        Syntax example:
        from flask_login import LoginManager
        @login_manager.user_loader
        def any_valid_func_name(user_id):
            # get your user object using the given user_id,
            # if you use SQLAlchemy, for example:
            user_obj = User.query.get(int(user_id))
            return user_obj

        Reason to let YOU define this self.user_callback:
            Because we won't know how/where you will load you user object.
        Nuser_idzNo user_loader has been installed for this LoginManager. Refer tohttps://flask-login.readthedocs.io/en/latest/#how-it-works for more info.)r   topr
   rH   r+   userr5   	Exception)r=   r^   ctxr\   r?   r?   r@   reload_user"  s    


zLoginManager.reload_userc                 C   s   t t  tj}|d| jr6|  }|r6|  S dt	k}|r|dt
}|dt}|tjkopt	ddk}|r| tj| S | jr| tS |tjkr| tj| S |  S )z;Loads user from session or remember_me cookie as applicableSESSION_PROTECTIONr\   REMEMBER_COOKIE_NAMEr   rememberclear)r   rN   r   rO   rG   rH   r3   _session_protectionra   r
   r   r   r	   cookies_load_from_cookier9   _load_from_requestheaders_load_from_header)r=   rG   ZdeletedZis_missing_user_idcookie_nameheader_nameZ
has_cookier?   r?   r@   
_load_userI  s(    


zLoginManager._load_userc                 C   s   t  }|  }t }|jd| j}|r||dd kr|dksJ|jr`d|d< t	| dS |dkrt
D ]}||d  qld|d< t	| d	S dS )
Nrb   Z_idr*   F_freshstrongre   rd   T)r
   rO   r:   r   rG   rH   r3   Z	permanentr    rN   r   pop)r=   sessidentr>   modekr?   r?   r@   rf   i  s     

z LoginManager._session_protectionc                 C   sP   t |}|d k	r |td< dtd< |   tjjd k	rLt }tj	|t
 d d S )Nr\   Fro   r^   )r&   r
   ra   r   r]   r^   r   rO   r   rN   r!   )r=   cookier\   r>   r?   r?   r@   rh     s    zLoginManager._load_from_cookiec                 C   sN   d }| j r|  |}|d k	rB| j|d t }tj|t d n|   d S Nrv   )r8   ra   r   rO   r   rN   r!   )r=   headerr^   r>   r?   r?   r@   rk     s    
zLoginManager._load_from_headerc                 C   sN   d }| j r|  |}|d k	rB| j|d t }tj|t d n|   d S rx   )r9   ra   r   rO   r   rN   r!   )r=   r	   r^   r>   r?   r?   r@   ri     s    
zLoginManager._load_from_requestc                 C   sb   dt krtjdrdt d< dt kr^t dd }|dkrLdt krL| | n|dkr^| | |S )Nrd   Z$REMEMBER_COOKIE_REFRESH_EACH_REQUESTsetr\   re   )r
   r   rG   rH   rq   _set_cookie_clear_cookie)r=   responseZ	operationr?   r?   r@   rF     s    

z$LoginManager._update_remember_cookiec              	   C   s   t j}|dt}|d}|dd}|dt}|dt}dtkrXttd d}n|d	t}t	t
td
 }	t|trt|d}zt | }
W n& tk
r   tdd| Y nX |j||	|
||||d d S )Nrc   REMEMBER_COOKIE_DOMAINREMEMBER_COOKIE_PATH/ZREMEMBER_COOKIE_SECUREZREMEMBER_COOKIE_HTTPONLYZremember_seconds)secondsZREMEMBER_COOKIE_DURATIONr\   z#REMEMBER_COOKIE_DURATION must be a z$datetime.timedelta, instead got: {0})valueexpiresdomainpathsecurehttponly)r   rG   rH   r   r   r   r
   r   r   r%   r   
isinstanceintr   utcnow	TypeErrorr_   format
set_cookie)r=   r}   rG   rl   r   r   r   r   durationdatar   r?   r?   r@   r{     s8    


zLoginManager._set_cookiec                 C   s<   t j}|dt}|d}|dd}|j|||d d S )Nrc   r~   r   r   )r   r   )r   rG   rH   r   Zdelete_cookie)r=   r}   rG   rl   r   r   r?   r?   r@   r|     s
    
zLoginManager._clear_cookie)NT)T)T)N)__name__
__module____qualname____doc__rA   rE   r;   rS   rV   rW   rX   rY   rZ   r[   ra   rn   rf   rh   rk   ri   rF   r{   r|   r?   r?   r?   r@   r)      s(   
<
	
7.
' %r)   )1r   rB   r   r   Zflaskr   r   r   r   r   r	   r
   _compatr   rG   r   r   r   r   r   r   r   r   r   r   r   r   Zmixinsr   Zsignalsr   r   r   r   r   r   r    utilsr!   r"   rQ   r#   r$   r%   r&   r'   r(   objectr)   r?   r?   r?   r@   <module>   s   $8$(