U
    !diN                     @   s  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 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) dd&l"m*Z* G d'd( d(Z+d)S )*    )datetime)	timedelta)abort)current_app)flash)g)has_app_context)redirect)request)session   )AUTH_HEADER_NAME)COOKIE_DURATION)COOKIE_HTTPONLY)COOKIE_NAME)COOKIE_SAMESITE)COOKIE_SECURE)ID_ATTRIBUTE)LOGIN_MESSAGE)LOGIN_MESSAGE_CATEGORY)REFRESH_MESSAGE)REFRESH_MESSAGE_CATEGORY)SESSION_KEYS)USE_SESSION_FOR_NEXT)AnonymousUserMixin)session_protected)user_accessed)user_loaded_from_cookie)user_loaded_from_request)user_needs_refresh)user_unauthorized)_create_identifier)_user_context_processor)decode_cookie)encode_cookie)expand_login_view)	login_url)make_next_paramc                   @   s   e Zd ZdZd1ddZd2ddZd3dd	Zd
d Zdd Ze	dd Z
dd Ze	dd Zdd Zdd Zdd Zdd Zd4d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e	d.d/ Zejd0d/ ZdS )5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 | _t| _d | _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unauthorized_callbackneeds_refresh_callbackr   Zid_attribute_user_callback_header_callback_request_callbackr!   _session_identifier_generatorinit_appselfappadd_context_processor r?   =/tmp/pip-unpacked-wheel-9qbqs8oa/flask_login/login_manager.py__init__1   s&    zLoginManager.__init__c                 C   s(   ddl }|jdtdd | || dS )zl
        This method has been deprecated. Please use
        :meth:`LoginManager.init_app` instead.
        r   NzY'setup_app' is deprecated and will be removed in Flask-Login 0.7. Use 'init_app' instead.   
stacklevel)warningswarnDeprecationWarningr:   )r<   r=   r>   rE   r?   r?   r@   	setup_appm   s    zLoginManager.setup_appc                 C   s$   | |_ || j |r |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
        N)Zlogin_managerZafter_request_update_remember_cookieZcontext_processorr"   r;   r?   r?   r@   r:   |   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d< 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   _idnextZnext_url)r    sendr   _get_current_objectr4   r
   Z	blueprintr,   r+   r   r-   r3   r   r.   configgetr   r%   r9   r   r'   urlmake_login_urlr	   )r<   r+   rR   r&   redirect_urlr?   r?   r@   unauthorized   s.    


zLoginManager.unauthorizedc                 C   s   || _ | jS )a>  
        This sets the callback for reloading a user from the session. The
        function you set should take a user ID (a ``str``) 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
        )r6   user_callbackr<   callbackr?   r?   r@   user_loader   s    	zLoginManager.user_loaderc                 C   s   | j S )z;Gets the user_loader callback set by user_loader decorator.)r6   r<   r?   r?   r@   rX      s    zLoginManager.user_callbackc                 C   s   || _ | j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
        )r8   request_callbackrY   r?   r?   r@   request_loader   s    	zLoginManager.request_loaderc                 C   s   | j S )zAGets the request_loader callback set by request_loader decorator.)r8   r\   r?   r?   r@   r]      s    zLoginManager.request_callbackc                 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
        )r4   rY   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
        )r5   rY   r?   r?   r@   needs_refresh_handler   s    
z"LoginManager.needs_refresh_handlerc                 C   s   t t  | jr|  S | js*td | jrb| jdk	rRt	| | j| j
d nt	| j| j
d tj}|dtrt| j}|  td< 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.
        rJ   NrK   r   rM   rN   rO   )r   rP   r   rQ   r5   r/   r   r0   r3   r   r1   rR   rS   r   r%   r9   r   r'   r
   rT   rU   r	   )r<   rR   r&   rV   r?   r?   r@   needs_refresh  s0    


zLoginManager.needs_refreshc                 C   s"   ddl }|jdtdd || _|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
        r   Nzc'header_loader' is deprecated and will be removed in Flask-Login 0.7. Use 'request_loader' instead.rB   rC   )rE   rF   rG   r7   )r<   rZ   rE   r?   r?   r@   header_loader8  s    zLoginManager.header_loaderc                 C   s   |dkr|   }|t_dS )z!Store the given user as ctx.user.N)r*   r   Z_login_user)r<   userr?   r?   r@   !_update_request_context_with_userO  s    z.LoginManager._update_request_context_with_userc           	      C   s   | j dkr| jdkrtdtt  |  r:|  S d}t	
d}|dk	rd| j dk	rd|  |}|dkrtj}|
dt}|
dt}|tjkot	
ddk}|rtj| }| |}n0| jr| t}n|tjkrtj| }| |}| |S )z;Loads user from session or remember_me cookie as applicableNznMissing user_loader or request_loader. Refer to http://flask-login.readthedocs.io/#how-it-works for more info._user_idREMEMBER_COOKIE_NAMEr   	_rememberclear)r6   r8   	Exceptionr   rP   r   rQ   _session_protection_failedrd   r   rS   rR   r   r   r
   cookies_load_user_from_remember_cookie_load_user_from_requestheaders_load_user_from_header)	r<   rc   user_idrR   cookie_nameheader_nameZ
has_cookiecookieheaderr?   r?   r@   
_load_userW  s4    





zLoginManager._load_userc                 C   s   t  }|  }t }|jd| j}|r4|dkr8dS |r||dd kr|dksZ|jr~|ddk	rpd|d< t	| dS |dkrt
D ]}||d  qd|d	< t	| d
S dS )NZSESSION_PROTECTION)r)   strongFrM   r)   _freshrv   rh   rg   T)r   rQ   r9   r   rR   rS   r2   Z	permanentr   rP   r   pop)r<   sessidentr=   modekr?   r?   r@   rj     s&    

z'LoginManager._session_protection_failedc                 C   sZ   t |}|d k	rV|td< dtd< d }| jr4| |}|d k	rVt }tj||d |S d S )Nre   Frw   rc   )r#   r   r6   r   rQ   r   rP   )r<   rs   rp   rc   r=   r?   r?   r@   rl     s    
z,LoginManager._load_user_from_remember_cookiec                 C   sB   | j r>|  |}|d k	r>t }ddlm} |j||d |S d S )Nr   )_user_loaded_from_headerr}   )r7   r   rQ   signalsr~   rP   )r<   rt   rc   r=   r~   r?   r?   r@   ro     s    
z#LoginManager._load_user_from_headerc                 C   s6   | j r2|  |}|d k	r2t }tj||d |S d S )Nr}   )r8   r   rQ   r   rP   )r<   r
   rc   r=   r?   r?   r@   rm     s    
z$LoginManager._load_user_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 )Nrg   Z$REMEMBER_COOKIE_REFRESH_EACH_REQUESTsetre   rh   )r   r   rR   rS   rx   _set_cookie_clear_cookie)r<   responseZ	operationr?   r?   r@   rI     s    
z$LoginManager._update_remember_cookiec              
   C   s   t j}|dt}|d}|dd}|dt}|dt}|dt}dtkrdttd d	}	n|d
t	}	t
ttd }
t|	trt|	d	}	zt |	 }W n2 tk
r } ztd|	 |W 5 d }~X Y nX |j||
||||||d d S )Nrf   REMEMBER_COOKIE_DOMAINREMEMBER_COOKIE_PATH/ZREMEMBER_COOKIE_SECUREZREMEMBER_COOKIE_HTTPONLYZREMEMBER_COOKIE_SAMESITEZ_remember_seconds)secondsZREMEMBER_COOKIE_DURATIONre   zDREMEMBER_COOKIE_DURATION must be a datetime.timedelta, instead got: )valueexpiresdomainpathsecurehttponlysamesite)r   rR   rS   r   r   r   r   r   r   r   r$   str
isinstanceintr   utcnow	TypeErrorri   
set_cookie)r<   r   rR   rq   r   r   r   r   r   durationdatar   er?   r?   r@   r     s>    


zLoginManager._set_cookiec                 C   s<   t j}|dt}|d}|dd}|j|||d d S )Nrf   r   r   r   )r   r   )r   rR   rS   r   Zdelete_cookie)r<   r   rR   rq   r   r   r?   r?   r@   r     s
    
zLoginManager._clear_cookiec                 C   s0   ddl }|jdtdd t r,tjddS dS )z:Legacy property, use app.config['LOGIN_DISABLED'] instead.r   Nu'_login_disabled' is deprecated and will be removed in Flask-Login 0.7. Use 'LOGIN_DISABLED' in 'app.config' instead.rB   rC   LOGIN_DISABLEDF)rE   rF   rG   r   r   rR   rS   )r<   rE   r?   r?   r@   _login_disabled  s    zLoginManager._login_disabledc                 C   s&   ddl }|jdtdd |tjd< dS )zALegacy property setter, use app.config['LOGIN_DISABLED'] instead.r   Nr   rB   rC   r   )rE   rF   rG   r   rR   )r<   ZnewvaluerE   r?   r?   r@   r     s    )NT)T)T)N)__name__
__module____qualname____doc__rA   rH   r:   rW   r[   propertyrX   r^   r]   r_   r`   ra   rb   rd   ru   rj   rl   ro   rm   rI   r   r   r   setterr?   r?   r?   r@   r(   *   s8   
<

:

4
*	*
r(   N),r   r   Zflaskr   r   r   r   r   r	   r
   r   rR   r   r   r   r   r   r   r   r   r   r   r   r   r   Zmixinsr   r   r   r   r   r   r   r    utilsr!   r"   r#   r$   r%   r&   rU   r'   r(   r?   r?   r?   r@   <module>   sJ   