B
    CVvg€"  ã               @   s  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
mZmZ d dlmZ d dlmZmZ d dlmZ d d	lmZmZ e jdd
�dd„ ƒZdd„ Zd!dd„Zd"dd„Zd#dd„Zd$dd„ZeeeƒZ G dd„ dƒZ!dd„ Z"G dd„ dƒZ#G dd„ dƒZ$G dd „ d ƒZ%dS )%é    N)ÚSequenceMatcher)ÚPath)Úsettings)ÚFieldDoesNotExistÚImproperlyConfiguredÚValidationError)Úlazy)Úformat_htmlÚformat_html_join)Úimport_string)ÚgettextÚngettext)Úmaxsizec               C   s
   t tjƒS )N)Úget_password_validatorsr   ZAUTH_PASSWORD_VALIDATORS© r   r   úK/tmp/pip-install-o3oxmrkh/Django/django/contrib/auth/password_validation.pyÚget_default_password_validators   s    r   c          	   C   sh   g }x^| D ]V}yt |d ƒ}W n( tk
rF   d}t||d  ƒ‚Y nX | |f | di ¡Ž¡ q
W |S )NÚNAMEzZThe module in NAME could not be imported: %s. Check your AUTH_PASSWORD_VALIDATORS setting.ÚOPTIONS)r   ÚImportErrorr   ÚappendÚget)Zvalidator_configZ
validatorsÚ	validatorÚklassÚmsgr   r   r   r      s    
r   c             C   sn   g }|dkrt ƒ }xJ|D ]B}y| | |¡ W q tk
rX } z| |¡ W dd}~X Y qX qW |rjt|ƒ‚dS )zÈ
    Validate whether the password meets all validator requirements.

    If the password is valid, return ``None``.
    If the password is invalid, raise ValidationError with all error messages.
    N)r   Úvalidater   r   )ÚpasswordÚuserÚpassword_validatorsÚerrorsr   Úerrorr   r   r   Úvalidate_password#   s    
 r!   c             C   s:   |dkrt ƒ }x&|D ]}t|ddd„ ƒ}|| |ƒ qW dS )zy
    Inform all validators that have implemented a password_changed() method
    that the password has been changed.
    NÚpassword_changedc              W   s   d S )Nr   )Úar   r   r   Ú<lambda>>   ó    z"password_changed.<locals>.<lambda>)r   Úgetattr)r   r   r   r   r"   r   r   r   r"   6   s
    
r"   c             C   s2   g }| dkrt ƒ } x| D ]}| | ¡ ¡ qW |S )zG
    Return a list of all help texts of all configured validators.
    N)r   r   Úget_help_text)r   Ú
help_textsr   r   r   r   Úpassword_validators_help_textsB   s    
r)   c             C   s0   t | ƒ}tdddd„ |D ƒƒ}|r,td|ƒS dS )z`
    Return an HTML string with all help texts of all configured validators
    in an <ul>.
    Ú z<li>{}</li>c             s   s   | ]}|fV  qd S )Nr   )Ú.0Ú	help_textr   r   r   ú	<genexpr>T   s    z6_password_validators_help_text_html.<locals>.<genexpr>z<ul>{}</ul>)r)   r
   r	   )r   r(   Z
help_itemsr   r   r   Ú#_password_validators_help_text_htmlN   s    r.   c               @   s,   e Zd ZdZd
dd„Zddd„Zdd	„ ZdS )ÚMinimumLengthValidatorz?
    Validate whether the password is of a minimum length.
    é   c             C   s
   || _ d S )N)Ú
min_length)Úselfr1   r   r   r   Ú__init___   s    zMinimumLengthValidator.__init__Nc             C   s0   t |ƒ| jk r,ttdd| jƒdd| jid�‚d S )NzNThis password is too short. It must contain at least %(min_length)d character.zOThis password is too short. It must contain at least %(min_length)d characters.Zpassword_too_shortr1   )ÚcodeÚparams)Úlenr1   r   r   )r2   r   r   r   r   r   r   b   s    zMinimumLengthValidator.validatec             C   s   t dd| jƒd| ji S )Nz=Your password must contain at least %(min_length)d character.z>Your password must contain at least %(min_length)d characters.r1   )r   r1   )r2   r   r   r   r'   n   s
    z$MinimumLengthValidator.get_help_text)r0   )N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r3   r   r'   r   r   r   r   r/   [   s   

r/   c             C   s0   t | ƒ}|d | }t |ƒ}|d| ko.||k S )a½  
    Test that value is within a reasonable range of password.

    The following ratio calculations are based on testing SequenceMatcher like
    this:

    for i in range(0,6):
      print(10**i, SequenceMatcher(a='A', b='A'*(10**i)).quick_ratio())

    which yields:

    1 1.0
    10 0.18181818181818182
    100 0.019801980198019802
    1000 0.001998001998001998
    10000 0.00019998000199980003
    100000 1.999980000199998e-05

    This means a length_ratio of 10 should never yield a similarity higher than
    0.2, for 100 this is down to 0.02 and for 1000 it is 0.002. This can be
    calculated via 2 / length_ratio. As a result we avoid the potentially
    expensive sequence matching.
    é   é
   )r6   )r   Úmax_similarityÚvalueZpwd_lenZlength_bound_similarityZ	value_lenr   r   r   Úexceeds_maximum_length_ratiov   s    r?   c               @   s4   e Zd ZdZdZedfdd„Zddd„Zd	d
„ ZdS )Ú UserAttributeSimilarityValidatora²  
    Validate whether the password is sufficiently different from the user's
    attributes.

    If no specific attributes are provided, look at a sensible list of
    defaults. Attributes that don't exist are ignored. Comparison is made to
    not only the full attribute value, but also its components, so that, for
    example, a password is validated against either part of an email address,
    as well as the full address.
    )ÚusernameZ
first_nameÚ	last_nameÚemailgffffffæ?c             C   s    || _ |dk rtdƒ‚|| _d S )Ngš™™™™™¹?z#max_similarity must be at least 0.1)Úuser_attributesÚ
ValueErrorr=   )r2   rD   r=   r   r   r   r3   ¡   s    z)UserAttributeSimilarityValidator.__init__Nc       	   
   C   sÔ   |sd S |  ¡ }x¾| jD ]´}t||d ƒ}|rt|tƒs8q|  ¡ }t d|¡|g }xx|D ]p}t|| j|ƒrlqXt	||d� 
¡ | jkrXyt|j |¡jƒ}W n tk
r°   |}Y nX ttdƒdd|id�‚qXW qW d S )Nz\W+)r#   Úbz4The password is too similar to the %(verbose_name)s.Zpassword_too_similarÚverbose_name)r4   r5   )ÚlowerrD   r&   Ú
isinstanceÚstrÚreÚsplitr?   r=   r   Zquick_ratioZ_metaÚ	get_fieldrG   r   r   Ú_)	r2   r   r   Zattribute_namer>   Zvalue_lowerZvalue_partsZ
value_partrG   r   r   r   r   §   s*    

z)UserAttributeSimilarityValidator.validatec             C   s   t dƒS )NuH   Your password canâ€™t be too similar to your other personal information.)rN   )r2   r   r   r   r'   À   s    z.UserAttributeSimilarityValidator.get_help_text)N)r7   r8   r9   r:   ZDEFAULT_USER_ATTRIBUTESr3   r   r'   r   r   r   r   r@   ”   s
   

r@   c               @   s@   e Zd ZdZeeƒ ¡ jd Zefdd„Z	d
dd„Z
dd	„ ZdS )ÚCommonPasswordValidatora·  
    Validate whether the password is a common password.

    The password is rejected if it occurs in a provided list of passwords,
    which may be gzipped. The list Django ships with contains 20000 common
    passwords (lowercased and deduplicated), created by Royce Williams:
    https://gist.github.com/roycewilliams/281ce539915a947a23db17137d91aeb7
    The password list must be lowercased to match the comparison in validate().
    zcommon-passwords.txt.gzc             C   sn   y0t j|ddd��}dd„ |D ƒ| _W d Q R X W n8 tk
rh   t|ƒ�}dd„ |D ƒ| _W d Q R X Y nX d S )NÚrtzutf-8)Úencodingc             S   s   h | ]}|  ¡ ’qS r   )Ústrip)r+   Úxr   r   r   ú	<setcomp>Ó   s    z3CommonPasswordValidator.__init__.<locals>.<setcomp>c             S   s   h | ]}|  ¡ ’qS r   )rR   )r+   rS   r   r   r   rT   Ö   s    )ÚgzipÚopenÚ	passwordsÚOSError)r2   Zpassword_list_pathÚfr   r   r   r3   Ð   s    
z CommonPasswordValidator.__init__Nc             C   s&   |  ¡  ¡ | jkr"ttdƒdd�‚d S )NzThis password is too common.Zpassword_too_common)r4   )rH   rR   rW   r   rN   )r2   r   r   r   r   r   r   Ø   s    z CommonPasswordValidator.validatec             C   s   t dƒS )Nu2   Your password canâ€™t be a commonly used password.)rN   )r2   r   r   r   r'   ß   s    z%CommonPasswordValidator.get_help_text)N)r7   r8   r9   r:   r   Ú__file__ÚresolveÚparentZDEFAULT_PASSWORD_LIST_PATHr3   r   r'   r   r   r   r   rO   Ä   s
   	
rO   c               @   s"   e Zd ZdZddd„Zdd„ ZdS )ÚNumericPasswordValidatorz8
    Validate whether the password is alphanumeric.
    Nc             C   s   |  ¡ rttdƒdd�‚d S )Nz"This password is entirely numeric.Zpassword_entirely_numeric)r4   )Úisdigitr   rN   )r2   r   r   r   r   r   r   ç   s    z!NumericPasswordValidator.validatec             C   s   t dƒS )Nu*   Your password canâ€™t be entirely numeric.)rN   )r2   r   r   r   r'   î   s    z&NumericPasswordValidator.get_help_text)N)r7   r8   r9   r:   r   r'   r   r   r   r   r]   ã   s   
r]   )NN)NN)N)N)&Ú	functoolsrU   rK   Údifflibr   Zpathlibr   Zdjango.confr   Zdjango.core.exceptionsr   r   r   Zdjango.utils.functionalr   Zdjango.utils.htmlr	   r
   Zdjango.utils.module_loadingr   Zdjango.utils.translationr   rN   r   Ú	lru_cacher   r   r!   r"   r)   r.   rJ   Z"password_validators_help_text_htmlr/   r?   r@   rO   r]   r   r   r   r   Ú<module>   s,   





0