U
    hE                     @   s  d Z ddlmZ ddlZeeZddlZddlm	Z	 ddl
mZm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mZmZ ddgZe Z dZ!dZ"dZ#dZ$dZ%G dd deZ&e' Z(dd Z)e) Z*dd Z+e+ Z,G dd de&Z-G dd de&Z.dS )z(passlib.apache - apache password support    )with_statementN)warn)excregistry)CryptContext)ExpectedStringError)htdigest)render_bytesto_bytesis_ascii_codec)deprecated_method)
join_bytesunicodeBytesIOPY3HtpasswdFileHtdigestFile   :   #s   :
	 skippedrecordc                   @   s  e Zd ZdZdZdZdZdZdZdZ	dZ
edd Zedd Zddddd	efd
dZdd Zedd Zejdd Zedd Zdd Zd2ddZdd Zdd Zdd Zdd Zdd  Zd3d!d"Zd#d$ Zd%d& Zd'd( Zd)d* Z d+d, Z!d4d.d/Z"d0d1 Z#dS )5_CommonFilez0common framework for HtpasswdFile & HtdigestFileNFc                 K   s(   d|krt d| f |}|| |S )zcreate new object from raw string.

        :type data: unicode or bytes
        :arg data:
            database to load, as single string.

        :param \*\*kwds:
            all other keywords are the same as in the class constructor
        pathz$'path' not accepted by from_string())	TypeErrorload_string)clsdatakwdsself r   4./venv/lib/python3.8/site-packages/passlib/apache.pyfrom_stringK   s
    

z_CommonFile.from_stringc                 K   s   | f |}| | |S )zcreate new object from file, without binding object to file.

        :type path: str
        :arg path:
            local filepath to load from

        :param \*\*kwds:
            all other keywords are the same as in the class constructor
        )load)r   r   r   r   r   r   r    	from_path\   s    

z_CommonFile.from_pathTutf-8c                 C   s   |st dtdd d}d}nt|s,td|| _|| _|| _|| _d| _|s`t dtdd d	}|rr|sr| 	  ni | _
g | _d S )
Nz``encoding=None`` is deprecated as of Passlib 1.6, and will cause a ValueError in Passlib 1.8, use ``return_unicode=False`` instead.   
stacklevelr$   Fz'encoding must be 7-bit ascii compatibler   zp``autoload=False`` is deprecated as of Passlib 1.6, and will be removed in Passlib 1.8, use ``new=True`` insteadT)r   DeprecationWarningr   
ValueErrorencodingreturn_unicodeautosave_path_mtimer"   _records_source)r   r   newZautoloadr,   r*   r+   r   r   r    __init__n   s0      
z_CommonFile.__init__c                 C   sT   d}| j r|d7 }| jr&|d| j 7 }| jdkr>|d| j 7 }d| jjt| |f S )N z autosave=Truez path=%rr$   z encoding=%rz<%s 0x%0x%s>)r,   r-   r*   	__class____name__id)r   tailr   r   r    __repr__   s    
z_CommonFile.__repr__c                 C   s   | j S N)r-   r   r   r   r    r      s    z_CommonFile.pathc                 C   s   || j krd| _|| _ d S )Nr   )r-   r.   r   valuer   r   r    r      s    
c                 C   s   | j S )z7modify time when last loaded (if bound to a local file))r.   r:   r   r   r    mtime   s    z_CommonFile.mtimec                 C   s<   | j std|  | jr0| jtj| j kr0dS |   dS )zBReload from ``self.path`` only if file has changed since last loadz%r is not bound to a local fileFT)r-   RuntimeErrorr.   osr   getmtimer"   r:   r   r   r    load_if_changed   s    z_CommonFile.load_if_changedc              	   C   s   |dk	r0t |d}d| _| | W 5 Q R X nr|sXtdt| jjd tdd |  S | j	rt | j	d }t
j| j	| _| | W 5 Q R X ntd| jj d	S )
a  Load state from local file.
        If no path is specified, attempts to load from ``self.path``.

        :type path: str
        :arg path: local file to load from

        :type force: bool
        :param force:
            if ``force=False``, only load from ``self.path`` if file
            has changed since last load.

            .. deprecated:: 1.6
                This keyword will be removed in Passlib 1.8;
                Applications should use :meth:`load_if_changed` instead.
        Nrbr   z%(name)s.load(force=False) is deprecated as of Passlib 1.6,and will be removed in Passlib 1.8; use %(name)s.load_if_changed() instead.)namer%   r&   z2%s().path is not set, an explicit path is requiredT)openr.   _load_linesr   dictr4   r5   r(   rA   r-   r?   r   r@   r>   )r   r   forcefhr   r   r    r"      s(     z_CommonFile.loadc                 C   s&   t || jd}d| _| t| dS )z@Load state from unicode or bytes string, replacing current stater   r   N)r
   r*   r.   rE   r   )r   r   r   r   r    r      s    z_CommonFile.load_stringc                 C   s   | j }i }g }d}t|D ]\}}| }|r8|trB||7 }q|||d \}	}
|	|krttd|	  ||7 }q|r|t|f d}|
||	< |t	|	f q|
 r|t|f || _|| _dS )zload from sequence of lists       z1username occurs multiple times in source file: %rN)_parse_record	enumeratelstrip
startswith_BHASHlogZwarningappend_SKIPPED_RECORDrstripr/   r0   )r   linesparserecordssourcer   idxlineZtmpkeyr<   r   r   r    rE      s.    z_CommonFile._load_linesc                 C   s   t ddS )z)parse line of file into (key, value) pair!should be implemented in subclassNNotImplementedError)r   r   linenor   r   r    rK     s    z_CommonFile._parse_recordc                 C   s.   | j }||k}|||< |s*| jt|f |S )z
        helper for setting record which takes care of inserting source line if needed;

        :returns:
            bool if key already present
        )r/   r0   rQ   rS   )r   r[   r<   rW   existingr   r   r    _set_record  s    z_CommonFile._set_recordc                 C   s   | j r| jr|   dS )z0subclass helper to call save() after any changesN)r,   r-   saver:   r   r   r    	_autosave!  s    z_CommonFile._autosavec              	   C   sf   |dk	r.t |d}||   W 5 Q R X n4| jrR| | j tj| j| _nt	d| j
j dS )zhSave current state to file.
        If no path is specified, attempts to save to ``self.path``.
        Nwbz%%s().path is not set, cannot autosave)rD   
writelines_iter_linesr-   rb   r?   r   r@   r.   r>   r4   r5   )r   r   rH   r   r   r    rb   &  s    z_CommonFile.savec                 C   s   t |  S )z)Export current state as a string of bytes)r   rf   r:   r   r   r    	to_string4  s    z_CommonFile.to_stringc                 c   sv   | j }t|}| jD ]J\}}|tkr,|V  q|tks8t||krBq| ||| V  || q|rrtd|f dS )z#iterator yielding lines of databasez'failed to write all records: missing=%rN)r/   setr0   rR   rS   AssertionError_render_recordremove)r   rW   pendingactionZcontentr   r   r    rf   @  s    z_CommonFile._iter_linesc                 C   s   t ddS )z,given key/value pair, encode as line of filer\   Nr]   )r   r[   r<   r   r   r    rj   [  s    z_CommonFile._render_recordc                 C   s   |  |dS )z)user-specific wrapper for _encode_field()user_encode_fieldr   rn   r   r   r    _encode_userb  s    z_CommonFile._encode_userc                 C   s   |  |dS )z*realm-specific wrapper for _encode_field()realmro   r   rs   r   r   r    _encode_realmf  s    z_CommonFile._encode_realmfieldc                 C   sn   t |tr|| j}nt |ts,t||t|dkrHtd||f tdd |D rjtd||f |S )a+  convert field to internal representation.

        internal representation is always bytes. byte strings are left as-is,
        unicode strings encoding using file's default encoding (or ``utf-8``
        if no encoding has been specified).

        :raises UnicodeEncodeError:
            if unicode value cannot be encoded using default encoding.

        :raises ValueError:
            if resulting byte string contains a forbidden character,
            or is too long (>255 bytes).

        :returns:
            encoded identifer as bytes
           z%%s must be at most 255 characters: %rc                 s   s   | ]}|t kV  qd S r9   )_INVALID_FIELD_CHARS).0cr   r   r    	<genexpr>  s     z,_CommonFile._encode_field.<locals>.<genexpr>z"%s contains invalid characters: %r)	
isinstancer   encoder*   bytesr   lenr)   any)r   r<   Zparamr   r   r    rp   j  s    


z_CommonFile._encode_fieldc                 C   s,   t |tstd| jr$|| jS |S dS )aW  decode field from internal representation to format
        returns by users() method, etc.

        :raises UnicodeDecodeError:
            if unicode value cannot be decoded using default encoding.
            (usually indicates wrong encoding set for file).

        :returns:
            field as unicode or bytes, as appropriate.
        zexpected value to be bytesN)r|   r~   ri   r+   decoder*   r;   r   r   r    _decode_field  s    z_CommonFile._decode_field)NT)N)rv   )$r5   
__module____qualname____doc__r*   r+   r-   r.   r,   r/   r0   classmethodr!   r#   r   r2   r8   propertyr   setterr=   rA   r"   r   rE   rK   ra   rc   rb   rg   rf   rj   rr   ru   rp   r   r   r   r   r    r   ,   sL   

 
#


	
$*

r   c                  C   s   d } dD ]}t |r|}  q qt dr.dnd }t  |sRtdddddg t|pZdd|pf| pfd| pld|prd	d	d
}|j|d |d d |S )N)bcryptsha256_cryptr   portable_apache_24host_apache_24linux_apache_24portablehostapr_md5_cryptr   )r   portable_apache_22r   Zhost_apache_22r   Zlinux_apache_22)r   r   )r   Zhas_os_crypt_supportZhas_backend_warn_no_bcryptclearupdaterF   )Z	host_bestrC   r   defaultsr   r   r    _init_default_schemes  s4    
  
r   c                  C   sZ   dddddddg} |  t  | d d dg |  }tt| |jd	} t| td
 ddS )Nr   r   Zsha512_cryptZ	des_cryptr   Z	ldap_sha1Z	plaintext   )r[   r   Z2y)schemesdefaultZbcrypt__ident)extendr   Zget_supported_os_crypt_schemessortedrh   indexr   htpasswd_defaults)r   Z	preferredr   r   r    _init_htpasswd_context  s     r   c                       s   e Zd ZdZddef fdd	Zdd Zdd Zd	d
 Zdd Z	e
dddddd Zdd Zdd Ze
dddddd Zdd Zdd Ze
dddddd  Z  ZS )!r   a  class for reading & writing Htpasswd files.

    The class constructor accepts the following arguments:

    :type path: filepath
    :param path:

        Specifies path to htpasswd file, use to implicitly load from and save to.

        This class has two modes of operation:

        1. It can be "bound" to a local file by passing a ``path`` to the class
           constructor. In this case it will load the contents of the file when
           created, and the :meth:`load` and :meth:`save` methods will automatically
           load from and save to that file if they are called without arguments.

        2. Alternately, it can exist as an independant object, in which case
           :meth:`load` and :meth:`save` will require an explicit path to be
           provided whenever they are called. As well, ``autosave`` behavior
           will not be available.

           This feature is new in Passlib 1.6, and is the default if no
           ``path`` value is provided to the constructor.

        This is also exposed as a readonly instance attribute.

    :type new: bool
    :param new:

        Normally, if *path* is specified, :class:`HtpasswdFile` will
        immediately load the contents of the file. However, when creating
        a new htpasswd file, applications can set ``new=True`` so that
        the existing file (if any) will not be loaded.

        .. versionadded:: 1.6
            This feature was previously enabled by setting ``autoload=False``.
            That alias has been deprecated, and will be removed in Passlib 1.8

    :type autosave: bool
    :param autosave:

        Normally, any changes made to an :class:`HtpasswdFile` instance
        will not be saved until :meth:`save` is explicitly called. However,
        if ``autosave=True`` is specified, any changes made will be
        saved to disk immediately (assuming *path* has been set).

        This is also exposed as a writeable instance attribute.

    :type encoding: str
    :param encoding:

        Optionally specify character encoding used to read/write file
        and hash passwords. Defaults to ``utf-8``, though ``latin-1``
        is the only other commonly encountered encoding.

        This is also exposed as a readonly instance attribute.

    :type default_scheme: str
    :param default_scheme:
        Optionally specify default scheme to use when encoding new passwords.

        This can be any of the schemes with builtin Apache support,
        OR natively supported by the host OS's :func:`crypt.crypt` function.

        * Builtin schemes include ``"bcrypt"`` (apache 2.4+), ``"apr_md5_crypt"`,
          and ``"des_crypt"``.

        * Schemes commonly supported by Unix hosts
          include ``"bcrypt"``, ``"sha256_crypt"``, and ``"des_crypt"``.

        In order to not have to sort out what you should use,
        passlib offers a number of aliases, that will resolve
        to the most appropriate scheme based on your needs:

        * ``"portable"``, ``"portable_apache_24"`` -- pick scheme that's portable across hosts
          running apache >= 2.4. **This will be the default as of Passlib 2.0**.

        * ``"portable_apache_22"`` -- pick scheme that's portable across hosts
          running apache >= 2.4. **This is the default up to Passlib 1.9**.

        * ``"host"``, ``"host_apache_24"`` -- pick strongest scheme supported by
           apache >= 2.4 and/or host OS.

        * ``"host_apache_22"`` -- pick strongest scheme supported by
           apache >= 2.2 and/or host OS.

        .. versionadded:: 1.6
            This keyword was previously named ``default``. That alias
            has been deprecated, and will be removed in Passlib 1.8.

        .. versionchanged:: 1.6.3

            Added support for ``"bcrypt"``, ``"sha256_crypt"``, and ``"portable"`` alias.

        .. versionchanged:: 1.7

            Added apache 2.4 semantics, and additional aliases.

    :type context: :class:`~passlib.context.CryptContext`
    :param context:
        :class:`!CryptContext` instance used to create
        and verify the hashes found in the htpasswd file.
        The default value is a pre-built context which supports all
        of the hashes officially allowed in an htpasswd file.

        This is also exposed as a readonly instance attribute.

        .. warning::

            This option may be used to add support for non-standard hash
            formats to an htpasswd file. However, the resulting file
            will probably not be usable by another application,
            and particularly not by Apache.

    :param autoload:
        Set to ``False`` to prevent the constructor from automatically
        loaded the file from disk.

        .. deprecated:: 1.6
            This has been replaced by the *new* keyword.
            Instead of setting ``autoload=False``, you should use
            ``new=True``. Support for this keyword will be removed
            in Passlib 1.8.

    :param default:
        Change the default algorithm used to hash new passwords.

        .. deprecated:: 1.6
            This has been renamed to *default_scheme* for clarity.
            Support for this alias will be removed in Passlib 1.8.

    Loading & Saving
    ================
    .. automethod:: load
    .. automethod:: load_if_changed
    .. automethod:: load_string
    .. automethod:: save
    .. automethod:: to_string

    Inspection
    ================
    .. automethod:: users
    .. automethod:: check_password
    .. automethod:: get_hash

    Modification
    ================
    .. automethod:: set_password
    .. automethod:: delete

    Alternate Constructors
    ======================
    .. automethod:: from_string

    Attributes
    ==========
    .. attribute:: path

        Path to local file that will be used as the default
        for all :meth:`load` and :meth:`save` operations.
        May be written to, initialized by the *path* constructor keyword.

    .. attribute:: autosave

        Writeable flag indicating whether changes will be automatically
        written to *path*.

    Errors
    ======
    :raises ValueError:
        All of the methods in this class will raise a :exc:`ValueError` if
        any user name contains a forbidden character (one of ``:\r\n\t\x00``),
        or is longer than 255 characters.
    Nc                    sr   d|kr t dtdd |d}|rT|tkr<t d| tj t||}|j|d}|| _	t
t| j|f| d S )Nr   z{``default`` is deprecated as of Passlib 1.6, and will be removed in Passlib 1.8, it has been renamed to ``default_scheem``.r%   r&   zPHtpasswdFile: no bcrypt backends available, using fallback for default scheme %r)r   )r   r(   popr   r   ZPasslibSecurityWarningr   getcopycontextsuperr   r2   )r   r   Zdefault_schemer   r   r4   r   r    r2     s"     
zHtpasswdFile.__init__c                 C   s*   |  t}t|dkr&td| |S )Nr%   z/malformed htpasswd file (error reading line %d)rT   split_BCOLONr   r)   )r   r   r_   resultr   r   r    rK     s    zHtpasswdFile._parse_recordc                 C   s   t d||S )Nz%s:%s
r	   )r   rn   hashr   r   r    rj     s    zHtpasswdFile._render_recordc                    s    fdd j D S )z6
        Return list of all users in database
        c                    s   g | ]}  |qS r   r   )ry   rn   r:   r   r    
<listcomp>  s     z&HtpasswdFile.users.<locals>.<listcomp>)r/   r:   r   r:   r    users  s    zHtpasswdFile.usersc                 C   s   | j |}| ||S )a  Set password for user; adds user if needed.

        :returns:
            * ``True`` if existing user was updated.
            * ``False`` if user account was added.

        .. versionchanged:: 1.6
            This method was previously called ``update``, it was renamed
            to prevent ambiguity with the dictionary method.
            The old alias is deprecated, and will be removed in Passlib 1.8.
        )r   r   set_hash)r   rn   passwordr   r   r   r    set_password  s    zHtpasswdFile.set_password1.61.8r   Z
deprecatedZremovedZreplacementc                 C   s   |  ||S zset password for userr   r   rn   r   r   r   r    r     s    zHtpasswdFile.updatec                 C   s.   z| j | | W S  tk
r(   Y dS X dS )a  Return hash stored for user, or ``None`` if user not found.

        .. versionchanged:: 1.6
            This method was previously named ``find``, it was renamed
            for clarity. The old name is deprecated, and will be removed
            in Passlib 1.8.
        N)r/   rr   KeyErrorrq   r   r   r    get_hash  s    zHtpasswdFile.get_hashc                 C   s<   t rt|tr|| j}| |}| ||}|   |S )z
        semi-private helper which allows writing a hash directly;
        adds user if needed.

        .. warning::
            does not (currently) do any validation of the hash string

        .. versionadded:: 1.7
        )r   r|   strr}   r*   rr   ra   rc   )r   rn   r   r`   r   r   r    r     s    
zHtpasswdFile.set_hashr   c                 C   s
   |  |S zreturn hash for userr   rq   r   r   r    find1  s    zHtpasswdFile.findc                 C   s6   z| j | |= W n tk
r(   Y dS X |   dS )zDelete user's entry.

        :returns:
            * ``True`` if user deleted.
            * ``False`` if user not found.
        FT)r/   rr   r   rc   rq   r   r   r    delete8  s    zHtpasswdFile.deletec                 C   sz   |  |}| j|}|dkr"dS t|tr8|| j}| j||\}}|rv|dk	rv|| jksdt	|| j|< | 
  |S )aM  
        Verify password for specified user.
        If algorithm marked as deprecated by CryptContext, will automatically be re-hashed.

        :returns:
            * ``None`` if user not found.
            * ``False`` if user found, but password does not match.
            * ``True`` if user found and password matches.

        .. versionchanged:: 1.6
            This method was previously called ``verify``, it was renamed
            to prevent ambiguity with the :class:`!CryptContext` method.
            The old alias is deprecated, and will be removed in Passlib 1.8.
        N)rr   r/   r   r|   r   r}   r*   r   Zverify_and_updateri   rc   )r   rn   r   r   okZnew_hashr   r   r    check_passwordF  s    


zHtpasswdFile.check_passwordr   c                 C   s   |  ||S zverify password for userr   r   r   r   r    verifye  s    zHtpasswdFile.verify)r5   r   r   r   htpasswd_contextr2   rK   rj   r   r   r   r   r   r   r   r   r   r   __classcell__r   r   r   r    r     s.    9

c                       s   e Zd ZdZdZd+ f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efddZedddddd Zd-ddZdefddZeddddd d! Zd.d"d#Zd$d% Zdefd&d'Zeddd(dd)d* Z  ZS )/r   a  class for reading & writing Htdigest files.

    The class constructor accepts the following arguments:

    :type path: filepath
    :param path:

        Specifies path to htdigest file, use to implicitly load from and save to.

        This class has two modes of operation:

        1. It can be "bound" to a local file by passing a ``path`` to the class
           constructor. In this case it will load the contents of the file when
           created, and the :meth:`load` and :meth:`save` methods will automatically
           load from and save to that file if they are called without arguments.

        2. Alternately, it can exist as an independant object, in which case
           :meth:`load` and :meth:`save` will require an explicit path to be
           provided whenever they are called. As well, ``autosave`` behavior
           will not be available.

           This feature is new in Passlib 1.6, and is the default if no
           ``path`` value is provided to the constructor.

        This is also exposed as a readonly instance attribute.

    :type default_realm: str
    :param default_realm:

        If ``default_realm`` is set, all the :class:`HtdigestFile`
        methods that require a realm will use this value if one is not
        provided explicitly. If unset, they will raise an error stating
        that an explicit realm is required.

        This is also exposed as a writeable instance attribute.

        .. versionadded:: 1.6

    :type new: bool
    :param new:

        Normally, if *path* is specified, :class:`HtdigestFile` will
        immediately load the contents of the file. However, when creating
        a new htpasswd file, applications can set ``new=True`` so that
        the existing file (if any) will not be loaded.

        .. versionadded:: 1.6
            This feature was previously enabled by setting ``autoload=False``.
            That alias has been deprecated, and will be removed in Passlib 1.8

    :type autosave: bool
    :param autosave:

        Normally, any changes made to an :class:`HtdigestFile` instance
        will not be saved until :meth:`save` is explicitly called. However,
        if ``autosave=True`` is specified, any changes made will be
        saved to disk immediately (assuming *path* has been set).

        This is also exposed as a writeable instance attribute.

    :type encoding: str
    :param encoding:

        Optionally specify character encoding used to read/write file
        and hash passwords. Defaults to ``utf-8``, though ``latin-1``
        is the only other commonly encountered encoding.

        This is also exposed as a readonly instance attribute.

    :param autoload:
        Set to ``False`` to prevent the constructor from automatically
        loaded the file from disk.

        .. deprecated:: 1.6
            This has been replaced by the *new* keyword.
            Instead of setting ``autoload=False``, you should use
            ``new=True``. Support for this keyword will be removed
            in Passlib 1.8.

    Loading & Saving
    ================
    .. automethod:: load
    .. automethod:: load_if_changed
    .. automethod:: load_string
    .. automethod:: save
    .. automethod:: to_string

    Inspection
    ==========
    .. automethod:: realms
    .. automethod:: users
    .. automethod:: check_password(user[, realm], password)
    .. automethod:: get_hash

    Modification
    ============
    .. automethod:: set_password(user[, realm], password)
    .. automethod:: delete
    .. automethod:: delete_realm

    Alternate Constructors
    ======================
    .. automethod:: from_string

    Attributes
    ==========
    .. attribute:: default_realm

        The default realm that will be used if one is not provided
        to methods that require it. By default this is ``None``,
        in which case an explicit realm must be provided for every
        method call. Can be written to.

    .. attribute:: path

        Path to local file that will be used as the default
        for all :meth:`load` and :meth:`save` operations.
        May be written to, initialized by the *path* constructor keyword.

    .. attribute:: autosave

        Writeable flag indicating whether changes will be automatically
        written to *path*.

    Errors
    ======
    :raises ValueError:
        All of the methods in this class will raise a :exc:`ValueError` if
        any user name or realm contains a forbidden character (one of ``:\r\n\t\x00``),
        or is longer than 255 characters.
    Nc                    s   || _ tt| j|f| d S r9   )default_realmr   r   r2   )r   r   r   r   r   r   r    r2     s    zHtdigestFile.__init__c                 C   s<   |  t}t|dkr&td| |\}}}||f|fS )Nr   z/malformed htdigest file (error reading line %d)r   )r   r   r_   r   rn   rs   r   r   r   r    rK     s    
zHtdigestFile._parse_recordc                 C   s   |\}}t d|||S )Nz	%s:%s:%s
r   )r   r[   r   rn   rs   r   r   r    rj     s    zHtdigestFile._render_recordc                 C   s"   |d kr| j }|d krtd|S )NzGyou must specify a realm explicitly, or set the default_realm attribute)r   r   rt   r   r   r    _require_realm  s
    zHtdigestFile._require_realmc                 C   s   |  |}| |dS )Nrs   )r   rp   rt   r   r   r    ru     s    
zHtdigestFile._encode_realmc                 C   s   |  || |fS r9   )rr   ru   r   rn   rs   r   r   r    _encode_key#  s    zHtdigestFile._encode_keyc                    s&   t dd  jD } fdd|D S )z%Return list of all realms in databasec                 s   s   | ]}|d  V  qdS )rJ   Nr   ry   r[   r   r   r    r{   ,  s     z&HtdigestFile.realms.<locals>.<genexpr>c                    s   g | ]}  |qS r   r   )ry   rs   r:   r   r    r   -  s     z'HtdigestFile.realms.<locals>.<listcomp>)rh   r/   )r   realmsr   r:   r    r   *  s    zHtdigestFile.realmsc                    s        fddjD S )zReturn list of all users in specified realm.

        * uses ``self.default_realm`` if no realm explicitly provided.
        * returns empty list if realm not found.
        c                    s&   g | ]}|d   kr |d qS )rJ   r   r   r   rs   r   r   r    r   6  s    z&HtdigestFile.users.<locals>.<listcomp>)ru   r/   rt   r   r   r    r   /  s    
zHtdigestFile.usersc                 C   s>   |t krd| }}| |}tj|||| jd}| |||S )a  Set password for user; adds user & realm if needed.

        If ``self.default_realm`` has been set, this may be called
        with the syntax ``set_password(user, password)``,
        otherwise it must be called with all three arguments:
        ``set_password(user, realm, password)``.

        :returns:
            * ``True`` if existing user was updated
            * ``False`` if user account added.
        Nr*   )_UNSETr   r   r   r*   r   r   rn   rs   r   r   r   r   r    r   Q  s
    

zHtdigestFile.set_passwordr   r   r   r   c                 C   s   |  |||S r   r   r   rn   rs   r   r   r   r    r   d  s    zHtdigestFile.updatec                 C   s8   |  ||}| j|}|dkr$dS tr4|| j}|S )a  Return :class:`~passlib.hash.htdigest` hash stored for user.

        * uses ``self.default_realm`` if no realm explicitly provided.
        * returns ``None`` if user or realm not found.

        .. versionchanged:: 1.6
            This method was previously named ``find``, it was renamed
            for clarity. The old name is deprecated, and will be removed
            in Passlib 1.8.
        N)r   r/   r   r   r   r*   )r   rn   rs   r[   r   r   r   r    r   j  s    zHtdigestFile.get_hashc                 C   sP   |t krd| }}tr,t|tr,|| j}| ||}| ||}|   |S )a  
        semi-private helper which allows writing a hash directly;
        adds user & realm if needed.

        If ``self.default_realm`` has been set, this may be called
        with the syntax ``set_hash(user, hash)``,
        otherwise it must be called with all three arguments:
        ``set_hash(user, realm, hash)``.

        .. warning::
            does not (currently) do any validation of the hash string

        .. versionadded:: 1.7
        N)	r   r   r|   r   r}   r*   r   ra   rc   )r   rn   rs   r   r[   r`   r   r   r    r   }  s    
zHtdigestFile.set_hashr   c                 C   s   |  ||S r   r   r   r   r   r    r     s    zHtdigestFile.findc                 C   s<   |  ||}z| j|= W n tk
r.   Y dS X |   dS )zDelete user's entry for specified realm.

        if realm is not specified, uses ``self.default_realm``.

        :returns:
            * ``True`` if user deleted,
            * ``False`` if user not found in realm.
        FT)r   r/   r   rc   )r   rn   rs   r[   r   r   r    r     s    	zHtdigestFile.deletec                    sB   |    | j} fdd|D }|D ]
}||= q&|   t|S )zDelete all users for specified realm.

        if realm is not specified, uses ``self.default_realm``.

        :returns: number of users deleted (0 if realm not found)
        c                    s   g | ]}|d   kr|qS )rJ   r   r   rs   r   r    r     s      z-HtdigestFile.delete_realm.<locals>.<listcomp>)ru   r/   rc   r   )r   rs   rW   keysr[   r   r   r    delete_realm  s    
zHtdigestFile.delete_realmc                 C   sX   |t krd| }}| |}| |}| j||f}|dkrBdS tj||||| jdS )a  Verify password for specified user + realm.

        If ``self.default_realm`` has been set, this may be called
        with the syntax ``check_password(user, password)``,
        otherwise it must be called with all three arguments:
        ``check_password(user, realm, password)``.

        :returns:
            * ``None`` if user or realm not found.
            * ``False`` if user found, but password does not match.
            * ``True`` if user found and password matches.

        .. versionchanged:: 1.6
            This method was previously called ``verify``, it was renamed
            to prevent ambiguity with the :class:`!CryptContext` method.
            The old alias is deprecated, and will be removed in Passlib 1.8.
        Nr   )r   rr   ru   r/   r   r   r   r*   r   r   r   r    r     s    


zHtdigestFile.check_passwordr   c                 C   s   |  |||S r   r   r   r   r   r    r     s    zHtdigestFile.verify)NN)N)N)N)r5   r   r   r   r   r2   rK   rj   r   ru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   r  s:    
"



)/r   Z
__future__r   ZloggingZ	getLoggerr5   rP   r?   warningsr   Zpasslibr   r   Zpasslib.contextr   Zpasslib.excr   Zpasslib.hashr   Zpasslib.utilsr	   r
   r   Zpasslib.utils.decorr   Zpasslib.utils.compatr   r   r   r   __all__objectr   r   rO   rx   rR   rS   r   rh   r   r   r   r   r   r   r   r   r   r   r    <module>   sD    
   )-  c