U
    ª}ag[4  ã                   @   sê   d dl mZ d dlmZ d dlmZmZ d dlmZm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZmZmZ d dlm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"m#Z#m$Z$ d dl%m&Z& ee'ƒZ(G dd„ deeƒZ)dS )é    )Ú	getLogger)ÚOptional)ÚrouterÚtransaction)ÚFÚQÚSumÚValue)ÚConcat)Útimezone)Úclean_expired_user_attemptsÚget_user_attemptsÚreset_user_attempts)Úsettings)ÚAxesBaseHandlerÚAbstractAxesHandler)Úget_client_session_hashÚget_client_strÚget_client_usernameÚget_credentialsÚget_failure_limitÚget_lockout_parametersÚget_query_str)Ú	AccessLogÚAccessAttemptÚAccessFailureLog)Úuser_locked_outc                   @   sÎ   e Zd ZdZddddœee ee eedœdd„Zddœee ed	œd
d„Z	ddœee ed	œdd„Z
ejdœeee edœdd„Zd ee edœdd„Zd!edœdd„Zdd„ Zdd„ Zdd„ Zdd„ ZdS )"ÚAxesDatabaseHandlera  
    Signal handler implementation that records user login attempts to database and locks users out if necessary.

    .. note:: The get_user_attempts function is called several time during the authentication and lockout
              process, caching its output can be dangerous.
    NF)Ú
ip_addressÚusernameÚip_or_username)r   r   r    Úreturnc                C   sf   t j ¡ }|r*| t|d�t|d�B ¡}n |r:|j|d�}|rJ|j|d�}| ¡ \}}t d|¡ |S )N)r   ©r   z-AXES: Reset %d access attempts from database.)r   ÚobjectsÚallÚfilterr   ÚdeleteÚlogÚinfo)Úselfr   r   r    ÚattemptsÚcountÚ_© r-   úN/var/www/html/publicvenv/lib/python3.8/site-packages/axes/handlers/database.pyÚreset_attempts'   s    
z"AxesDatabaseHandler.reset_attempts)Úage_days)r0   r!   c                C   sd   |d kr(t j ¡  ¡ \}}t d|¡ n8t ¡ tj|d� }t jj	|d� ¡ \}}t d||¡ |S )Nz-AXES: Reset all %d access logs from database.©Údays©Zattempt_time__ltez<AXES: Reset %d access logs older than %d days from database.)
r   r#   r$   r&   r'   r(   r   ÚnowÚ	timedeltar%   ©r)   r0   r+   r,   Úlimitr-   r-   r.   Ú
reset_logs=   s    ýzAxesDatabaseHandler.reset_logsc                C   sd   |d kr(t j ¡  ¡ \}}t d|¡ n8t ¡ tj|d� }t jj	|d� ¡ \}}t d||¡ |S )Nz5AXES: Reset all %d access failure logs from database.r1   r3   zDAXES: Reset %d access failure logs older than %d days from database.)
r   r#   r$   r&   r'   r(   r   r4   r5   r%   r6   r-   r-   r.   Úreset_failure_logsL   s    ýz&AxesDatabaseHandler.reset_failure_logs)r7   )r   r7   r!   c                C   sL   d}t jj|d�}| ¡ | }|dkrH|d |… D ]}| ¡  |d7 }q2|S )Nr   r"   é   )r   r#   r%   r+   r&   )r)   r   r7   r+   ZfailuresZout_of_limit_failures_logsZfailurer-   r-   r.   Ú remove_out_of_limit_failure_logs[   s    
z4AxesDatabaseHandler.remove_out_of_limit_failure_logs)Úcredentialsr!   c                 C   s    t ||ƒ}tdd„ |D ƒƒ}|S )Nc                 s   s$   | ]}|  td ƒ¡d pdV  qdS )Úfailures_since_startZfailures_since_start__sumr   N)Z	aggregater   )Ú.0r*   r-   r-   r.   Ú	<genexpr>l   s
   ûÿz3AxesDatabaseHandler.get_failures.<locals>.<genexpr>)r   Úmax)r)   Úrequestr<   Zattempts_listZattempt_countr-   r-   r.   Úget_failuresj   s
    
ù	z AxesDatabaseHandler.get_failures)r<   c                 K   sX  t  d¡ |dkr t  d¡ dS t|ƒ t||ƒ}t||j|j|j|ƒ}t	j
sr|jrr||_tjd|||jd� dS t|jƒ dd¡}t|jƒ dd¡}|  ||¡r²t  d|¡ dS t||ƒ}	|	d	gkrÚ|dkrÚt  d
¡ nÌtjt t¡d��´ tj ¡ j||j|j|||j|jd|jdœd�\}
}|�r6t  d|¡ nfd}t dt!|| ƒƒ|
_"t dt!|| ƒƒ|
_#|j|
_$|j|
_%t&dƒd |
_'|j|
_(|
 )¡  t  d|¡ W 5 Q R X |  *||¡}||_+t	j,�rü|t-||ƒk�rüt  d|¡ d|_||_tjd|||jd� t	j.�rTtjt t/¡d��8 t/jj0||j|j|j|j|j|jd� | j1|d� W 5 Q R X dS )z¾When user login fails, save AccessFailureLog record in database,
        save AccessAttempt record in database, mark request with
        lockout attribute and emit lockout signal.

        z>AXES: User login failed, running database handler for failure.NzPAXES: AxesDatabaseHandler.user_login_failed does not function without a request.Zaxes)rA   r   r   ú Z0x00z.AXES: Login failed from whitelisted client %s.r   zfAXES: Username is None and username is the only one lockout parameter, new record will NOT be created.)Úusingr:   )Úget_dataÚ	post_dataÚhttp_acceptÚ	path_infor=   Úattempt_time)r   r   Ú
user_agentÚdefaultszBAXES: New login failure by %s. Created new record in the database.z
---------
rE   rF   r=   zLAXES: Repeated login failure by %s. Updated existing record in the database.z3AXES: Locking out %s after repeated login failures.T)r   r   rJ   rG   rH   rI   Z
locked_outr"   )2r'   r(   Úerrorr   r   r   Úaxes_ip_addressÚaxes_user_agentÚaxes_path_infor   Z-AXES_RESET_COOL_OFF_ON_FAILURE_DURING_LOCKOUTZaxes_locked_outZaxes_credentialsr   Úsendr   ÚGETÚreplaceÚPOSTZis_whitelistedr   Úwarningr   Zatomicr   Zdb_for_writer   r#   Zselect_for_updateZget_or_createÚaxes_http_acceptÚaxes_attempt_timer
   r	   rE   rF   rG   rH   r   r=   rI   ÚsaverB   Zaxes_failures_since_startZAXES_LOCK_OUT_AT_FAILUREr   ZAXES_ENABLE_ACCESS_FAILURE_LOGr   Úcreater;   )r)   Úsenderr<   rA   Úkwargsr   Ú
client_strrE   rF   Zlockout_parametersÚattemptÚcreatedÚ	separatorr=   r-   r-   r.   Úuser_login_failedw   sÎ    
ÿ
û
ÿþü
ÿ
úüýþ
 
ÿþÿþ ÿüù	z%AxesDatabaseHandler.user_login_failedc           	   	   K   sŠ   t |ƒ | ¡ }t|ƒ}t||j|j|j|ƒ}t d|¡ t	j
shtjj||j|j|j|j|jt|ƒd� t	jr†t||ƒ}t d||¡ dS )zN
        When user logs in, update the AccessLog related to the user.
        zAXES: Successful login by %s.)r   r   rJ   rG   rH   rI   Úsession_hashz;AXES: Deleted %d failed login attempts by %s from database.N)r   Úget_usernamer   r   rM   rN   rO   r'   r(   r   ÚAXES_DISABLE_ACCESS_LOGr   r#   rX   rU   rV   r   ZAXES_RESET_ON_SUCCESSr   )	r)   rY   rA   ÚuserrZ   r   r<   r[   r+   r-   r-   r.   Úuser_logged_in  s8    û÷
ýz"AxesDatabaseHandler.user_logged_inc                 K   sh   t |ƒ |r| ¡ nd}t||j|j|j|ƒ}t d|¡ |rdtj	sdt
jj|dt|ƒd�j|jd� dS )zO
        When user logs out, update the AccessLog related to the user.
        NzAXES: Successful logout by %s.T)r   Zlogout_time__isnullr`   )Zlogout_time)r   ra   r   rM   rN   rO   r'   r(   r   rb   r   r#   r%   r   ÚupdaterV   )r)   rY   rA   rc   rZ   r   r[   r-   r-   r.   Úuser_logged_out.  s$    û
üûz#AxesDatabaseHandler.user_logged_outc                 K   s   dS )z±
        Handles the ``axes.models.AccessAttempt`` object post save signal.

        When needed, all post_save actions for this backend should be located
        here.
        Nr-   ©r)   ÚinstancerZ   r-   r-   r.   Úpost_save_access_attemptJ  s    z,AxesDatabaseHandler.post_save_access_attemptc                 K   s   dS )zµ
        Handles the ``axes.models.AccessAttempt`` object post delete signal.

        When needed, all post_delete actions for this backend should be located
        here.
        Nr-   rg   r-   r-   r.   Úpost_delete_access_attemptR  s    z.AxesDatabaseHandler.post_delete_access_attempt)N)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚstrÚboolÚintr/   r8   r9   r   Z&AXES_ACCESS_FAILURE_LOG_PER_USER_LIMITr;   ÚdictrB   r_   rd   rf   ri   rj   r-   r-   r-   r.   r      s2   
ûúüû +r   N)*Úloggingr   Útypingr   Z	django.dbr   r   Zdjango.db.modelsr   r   r   r	   Zdjango.db.models.functionsr
   Zdjango.utilsr   Zaxes.attemptsr   r   r   Z	axes.confr   Zaxes.handlers.baser   r   Zaxes.helpersr   r   r   r   r   r   r   Zaxes.modelsr   r   r   Zaxes.signalsr   rk   r'   r   r-   r-   r-   r.   Ú<module>   s   $	