U
    d$                     @   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mZ d dlmZmZ d dlmZ d d	lmZ d d
l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)cached_property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-unpacked-wheel-7vj2equ7/django/contrib/auth/password_validation.pyget_default_password_validators   s    r   c              	   C   sd   g }| D ]V}zt |d }W n( tk
rD   d}t||d  Y nX ||f |di  q|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   sj   g }|dkrt  }|D ]B}z|| | W q tk
rV } z|| W 5 d}~X Y qX q|rft|dS )z
    Validate that 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   s6   |dkrt  }|D ]}t|ddd }|| | q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 r   r   )ar   r   r   <lambda>D       z"password_changed.<locals>.<lambda>)r   getattr)r   r   r    r   r$   r   r   r   r$   <   s
    r$   c                 C   s.   g }| dkrt  } | D ]}||  q|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_textsH   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 r   r   ).0	help_textr   r   r   	<genexpr>[   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_htmlT   s      r0   c                   @   s,   e Zd ZdZd
ddZdddZdd	 ZdS )MinimumLengthValidatorz<
    Validate that the password is of a minimum length.
       c                 C   s
   || _ d S r   )
min_length)selfr3   r   r   r   __init__h   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_shortr3   codeparams)lenr3   r   r   r4   r   r   r   r   r   r   k   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.r3   )r   r3   r4   r   r   r   r)   y   s    z$MinimumLengthValidator.get_help_text)r2   )N)__name__
__module____qualname____doc__r5   r   r)   r   r   r   r   r1   c   s   

r1   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.
       
   )r9   )r   max_similarityvalueZpwd_lenZlength_bound_similarityZ	value_lenr   r   r   exceeds_maximum_length_ratio   s    rD   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 that 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
ValueErrorrB   )r4   rI   rB   r   r   r   r5      s    z)UserAttributeSimilarityValidator.__init__Nc           	   
   C   s   |sd S |  }| jD ]}t||d }|rt|ts6q|  }td||g }|D ]p}t|| j|rhqTt	||d
 | jkrTzt|j|j}W n tk
r   |}Y nX ttddd|idqTqd S )Nz\W+)r%   bz4The password is too similar to the %(verbose_name)s.Zpassword_too_similarverbose_namer6   )lowerrI   r(   
isinstancestrresplitrD   rB   r   Zquick_ratioZ_meta	get_fieldrL   r   r   _)	r4   r   r   Zattribute_namerC   Zvalue_lowerZvalue_partsZ
value_partrL   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.rS   r;   r   r   r   r)      s    z.UserAttributeSimilarityValidator.get_help_text)N)r<   r=   r>   r?   ZDEFAULT_USER_ATTRIBUTESr5   r   r)   r   r   r   r   rE      s
   
 rE   c                   @   s:   e Zd ZdZedd ZefddZdddZd	d
 ZdS )CommonPasswordValidatora  
    Validate that the password is not 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().
    c                 C   s   t t jd S )Nzcommon-passwords.txt.gz)r   __file__resolveparentr;   r   r   r   DEFAULT_PASSWORD_LIST_PATH   s    z2CommonPasswordValidator.DEFAULT_PASSWORD_LIST_PATHc                 C   s~   |t jkr| j}z0tj|ddd}dd |D | _W 5 Q R X W n8 tk
rx   t|}dd |D | _W 5 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   r\   r^   r   r   r   r`      s     )rU   rY   gzipopen	passwordsOSError)r4   Zpassword_list_pathfr   r   r   r5      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r7   )rM   r]   rc   r   rS   r:   r   r   r   r      s
    z CommonPasswordValidator.validatec                 C   s   t dS )Nu2   Your password can’t be a commonly used password.rT   r;   r   r   r   r)      s    z%CommonPasswordValidator.get_help_text)N)	r<   r=   r>   r?   r   rY   r5   r   r)   r   r   r   r   rU      s   



rU   c                   @   s"   e Zd ZdZdddZdd ZdS )NumericPasswordValidatorz=
    Validate that the password is not entirely numeric.
    Nc                 C   s   |  rttdddd S )Nz"This password is entirely numeric.Zpassword_entirely_numericrf   )isdigitr   rS   r:   r   r   r   r     s
    z!NumericPasswordValidator.validatec                 C   s   t dS )Nu*   Your password can’t be entirely numeric.rT   r;   r   r   r   r)   	  s    z&NumericPasswordValidator.get_help_text)N)r<   r=   r>   r?   r   r)   r   r   r   r   rg      s   
rg   )NN)NN)N)N)'	functoolsra   rP   difflibr   pathlibr   Zdjango.confr   Zdjango.core.exceptionsr   r   r   Zdjango.utils.functionalr   r	   Zdjango.utils.htmlr
   r   Zdjango.utils.module_loadingr   Zdjango.utils.translationr   rS   r   	lru_cacher   r   r#   r$   r+   r0   rO   Z"password_validators_help_text_htmlr1   rD   rE   rU   rg   r   r   r   r   <module>   s0   






:$