
     hE                     b   d Z ddlmZ ddlZ ej                  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e      Z& e'       Z(d Z) e)       Z*d Z+ e+       Z, G d de&      Z- G d de&      Z.y)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                   
   e Zd ZdZdZdZdZdZdZdZ	dZ
ed        Zed        ZdddddefdZd	 Zed
        Zej&                  d        Zed        Zd ZddZd Zd Zd Zd Zd ZddZd Zd Zd Zd Z d Z!ddZ"d Z#y)_CommonFilez0common framework for HtpasswdFile & HtdigestFileNFc                 V    d|v rt        d       | di |}|j                  |       |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selfs       P/var/www/html/Resume-Scraper/venv/lib/python3.12/site-packages/passlib/apache.pyfrom_stringz_CommonFile.from_stringK   s5     T>BCC{T{    c                 8     | di |}|j                  |       |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
        r   )load)r   r   r!   r"   s       r#   	from_pathz_CommonFile.from_path\   s     {T{		$r%   Tutf-8c                    |st        dt        d       d}d}nt        |      st        d      || _        || _        || _        || _        d| _        |st        dt        d       d	}|r|s| j                          y i | _
        g | _        y )
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   newautoloadr2   r0   r1   s          r#   __init__z_CommonFile.__init__n   s      9 $3 H"N) FGG  - 
  P#3 CIIKDMDLr%   c                     d}| j                   r|dz  }| j                  r|d| j                  z  z  }| j                  dk7  r|d| j                  z  z  }d| j                  j                  t        |       |fz  S )N z autosave=Truez path=%rr)   z encoding=%rz<%s 0x%0x%s>)r2   r3   r0   	__class____name__id)r"   tails     r#   __repr__z_CommonFile.__repr__   sr    ==$$D::J++D==G#NT]]22D!8!8"T(D IIIr%   c                     | j                   S N)r3   r"   s    r#   r   z_CommonFile.path   s    zzr%   c                 >    || j                   k7  rd| _        || _         y )Nr   )r3   r4   r"   values     r#   r   z_CommonFile.path   s    DJJDK
r%   c                     | j                   S )z7modify time when last loaded (if bound to a local file))r4   rC   s    r#   mtimez_CommonFile.mtime   s     {{r%   c                     | j                   st        d| z        | j                  r7| j                  t        j                  j                  | j                         k(  ry| j                          y)zBReload from ``self.path`` only if file has changed since last loadz%r is not bound to a local fileFT)r3   RuntimeErrorr4   osr   getmtimer'   rC   s    r#   load_if_changedz_CommonFile.load_if_changed   sN    zz@4GHH;;4;;"''*:*:4::*FF		r%   c                 6   |.t        |d      5 }d| _        | j                  |       ddd       y	|sCt        dt	        | j
                  j                        z  t        d       | j                         S | j                  r_t        | j                  d      5 }t        j                  j                  | j                        | _        | j                  |       ddd       y	t        d| j
                  j                  z        # 1 sw Y   y	xY w# 1 sw Y   y	xY w)
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)openr4   _load_linesr   dictr<   r=   r.   rM   r3   rK   r   rL   rJ   )r"   r   forcefhs       r#   r'   z_CommonFile.load   s     dD! %R  $%"   ; 4>>2234 $	3
 ''))ZZdjj$' %2 gg..tzz:  $%  S#~~66 7 8 8%" % s   DA DDDc                 t    t        || j                  d      }d| _        | j                  t	        |             y)z@Load state from unicode or bytes string, replacing current stater    r   N)r   r0   r4   rR   r   )r"   r    s     r#   r   z_CommonFile.load_string   s-    dmmV4'r%   c                    | j                   }i }g }d}t        |      D ]  \  }}|j                         }|r|j                  t              r||z  }3 |||dz         \  }	}
|	|v rt
        j                  d|	z         ||z  }d|r|j                  t        |f       d}|
||	<   |j                  t        |	f        |j                         r|j                  t        |f       || _        || _        y)zload from sequence of listsr%      z1username occurs multiple times in source file: %rN)_parse_record	enumeratelstrip
startswith_BHASHlogwarningappend_SKIPPED_RECORDrstripr5   r6   )r"   linesparserecordssourcer   idxlinetmpkeyrF   s              r#   rR   z_CommonFile._load_lines   s    """5) 	*IC ++-C#..04 tSU+JC g~ORUUV4 x12 !GCLMM7C.)5	*: >>MM8W-.  r%   c                     t        d      )z)parse line of file into (key, value) pair!should be implemented in subclassNotImplementedError)r"   r   linenos      r#   rY   z_CommonFile._parse_record      !"EFFr%   c                 v    | j                   }||v }|||<   |s!| j                  j                  t        |f       |S )z
        helper for setting record which takes care of inserting source line if needed;

        :returns:
            bool if key already present
        )r5   r6   r`   rb   )r"   rk   rF   rf   existings        r#   _set_recordz_CommonFile._set_record  s=     --7NLL#/r%   c                 X    | j                   r| j                  r| j                          yyy)z0subclass helper to call save() after any changesN)r2   r3   saverC   s    r#   	_autosavez_CommonFile._autosave!  s    ==TZZIIK (=r%   c                 x   |5t        |d      5 }|j                  | j                                ddd       y| j                  rJ| j	                  | j                         t
        j                  j                  | j                        | _        yt        d| j                  j                  z        # 1 sw Y   yxY w)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)rQ   
writelines_iter_linesr3   rv   rK   r   rL   r4   rJ   r<   r=   )r"   r   rU   s      r#   rv   z_CommonFile.save&  s     dD! 2Rd..012 2ZZIIdjj!''**4::6DKF#~~66 7 8 82 2s    B00B9c                 4    t        | j                               S )z)Export current state as a string of bytes)r   r{   rC   s    r#   	to_stringz_CommonFile.to_string4  s    $**,--r%   c              #     K   | j                   }	 t        |      }| j                  D ]L  \  }}|t        k(  r| |t        k(  sJ ||vr$| j                  |||          	 |j                  |       N 	 |r
J d|       yw)z#iterator yielding lines of databasez%failed to write all records: missing=N)r5   setr6   ra   rb   _render_recordremove)r"   rf   pendingactioncontents        r#   r{   z_CommonFile._iter_lines@  s      --'lG#|| 	,OFG!((') ))'773CDDNN7+	,  VW VVws   BBc                     t        d      )z,given key/value pair, encode as line of filerm   rn   )r"   rk   rF   s      r#   r   z_CommonFile._render_record[  rq   r%   c                 &    | j                  |d      S )z)user-specific wrapper for _encode_field()user_encode_fieldr"   r   s     r#   _encode_userz_CommonFile._encode_userb  s    !!$//r%   c                 &    | j                  |d      S )z*realm-specific wrapper for _encode_field()realmr   r"   r   s     r#   _encode_realmz_CommonFile._encode_realmf  s    !!%11r%   c                    t        |t              r|j                  | j                        }nt        |t              st        ||      t        |      dkD  rt        |d|      t        d |D              rt        |d|      |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! must be at most 255 characters: c              3   ,   K   | ]  }|t         v   y wrB   )_INVALID_FIELD_CHARS).0cs     r#   	<genexpr>z,_CommonFile._encode_field.<locals>.<genexpr>  s     8Qq((8s   z contains invalid characters: )	
isinstancer   encoder0   bytesr   lenr/   any)r"   rF   params      r#   r   z_CommonFile._encode_fieldj  s    " eW%LL/EE5)%eU33u:#U, - -8%88#U- . .r%   c                     t        |t              sJ d       | j                  r|j                  | j                        S |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 bytes)r   r   r1   decoder0   rE   s     r#   _decode_fieldz_CommonFile._decode_field  s8     %'E)EE<<..Lr%   )NTrB   )field)$r=   
__module____qualname____doc__r0   r1   r3   r4   r2   r5   r6   classmethodr$   r(   r   r9   r@   propertyr   setterrH   rM   r'   r   rR   rY   rt   rw   rv   r}   r{   r   r   r   r   r   r   r%   r#   r   r   ,   s   : H N EF H H G
     " !edU!#!FJ   
[[ 
  "H((TG"
8.W6G02:r%   r   c                  R   d } dD ]  }t        j                  |      s|}  n t        j                  d      rdnd }t        j	                          |st        j                  g d       t        |xs dd|xs | xs d| xs d|xs dd      }|j                  |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   host_apache_22r   linux_apache_22r   r   )r   r   )r   has_os_crypt_supporthas_backend_warn_no_bcryptclearupdaterS   )	host_bestrP   r   defaultss       r#   _init_default_schemesr     s     I* ((.I "--h7XTF  G 	H !4_* ==o 3O 0.&H" OO./&'   Or%   c                      g d} | j                  t        j                                | d d dgz   | z   }t        t	        |       |j
                        } t        | t        d   d      S )N)r   r   sha512_crypt	des_cryptr   	ldap_sha1	plaintext   r   )rk   r   2y)schemesdefaultbcrypt__ident)extendr   get_supported_os_crypt_schemessortedr   indexr   htpasswd_defaults)r   	preferreds     r#   _init_htpasswd_contextr     sp    G0 NN8::<= //'9IS\y7G  ""67  r%   c                        e Zd ZdZddef fd	Zd Zd Zd Zd Z	 e
dd	d
      d        Zd Zd Z e
dd	d      d        Zd Zd Z e
dd	d      d        Z x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                 (   d|v r#t        dt        d       |j                  d      }|rM|t        v rt        d|z  t        j
                         t        j                  ||      }|j                  |      }|| _	        t        t        | 2  |fi | y )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   PasslibSecurityWarningr   getcopycontextsuperr   r9   )r"   r   default_schemer   r!   r<   s        r#   r9   zHtpasswdFile.__init__  s     * $3 "XXi0N0 <>LM//1 /22>>RNll>l:GlD*4848r%   c                     |j                         j                  t              }t        |      dk7  rt	        d|z        |S )Nr+   z/malformed htpasswd file (error reading line %d)rc   split_BCOLONr   r/   )r"   r   rp   results       r#   rY   zHtpasswdFile._parse_record  sA    &&w/v;!N%& ' 'r%   c                     t        d||      S )Nz%s:%s
r
   )r"   r   hashs      r#   r   zHtpasswdFile._render_record  s    ItT22r%   c                 ^    | j                   D cg c]  }| j                  |       c}S c c}w )z6
        Return list of all users in database
        )r5   r   r   s     r#   userszHtpasswdFile.users  s'     6:]]CT""4(CCCs   *c                 \    | j                   j                  |      }| 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"   r   passwordr   s       r#   set_passwordzHtpasswdFile.set_password  s)     ||  *}}T4((r%   1.61.8r   
deprecatedremovedreplacementc                 &    | j                  ||      S zset password for userr   r"   r   r   s      r#   r   zHtpasswdFile.update  s       x00r%   c                 ^    	 | j                   | j                  |         S # t        $ r Y yw xY w)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)r5   r   KeyErrorr   s     r#   get_hashzHtpasswdFile.get_hash  s3    	==!2!24!899 		s     	,,c                     t         r+t        |t              r|j                  | j                        }| j                  |      }| j                  ||      }| 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   r0   r   rt   rw   )r"   r   r   rs   s       r#   r   zHtpasswdFile.set_hash  sS     :dC(;;t}}-D  &##D$/r%   r   c                 $    | j                  |      S zreturn hash for userr   r   s     r#   findzHtpasswdFile.find1  s     }}T""r%   c                 |    	 | j                   | j                  |      = | j                          y# t        $ r Y yw xY w)zDelete user's entry.

        :returns:
            * ``True`` if user deleted.
            * ``False`` if user not found.
        FT)r5   r   r   rw   r   s     r#   deletezHtpasswdFile.delete8  sA    	d//56 	  		s   / 	;;c                 ^   | j                  |      }| j                  j                  |      }|yt        |t              r|j                  | j                        }| j                  j                  ||      \  }}|r1|/|| j                  v sJ || j                  |<   | 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)
r   r5   r   r   r   r   r0   r   verify_and_updaterw   )r"   r   r   r   oknew_hashs         r#   check_passwordzHtpasswdFile.check_passwordF  s       &}}  &<h(  t}}5H||55hEH(&4==(("*DMM$NN	r%   r   c                 &    | j                  ||      S zverify password for userr   r   s      r#   verifyzHtpasswdFile.verifye  s     ""422r%   )r=   r   r   r   htpasswd_contextr9   rY   r   r   r   r   r   r   r   r   r   r   r   __classcell__r<   s   @r#   r   r     s    mp !?O 9$3D$) %#13131$ %#-/#/#
> %#35353r%   c                        e Zd ZdZdZd fd	Zd Zd Zd Zd Z	d Z
d	 Zdd
ZdefdZ eddd      d        ZddZdefdZ eddd      d        ZddZd ZdefdZ eddd      d        Z x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                 <    || _         t        t        |   |fi | y rB   )default_realmr   r   r9   )r"   r   r  r!   r<   s       r#   r9   zHtdigestFile.__init__  s    *lD*4848r%   c                     |j                         j                  t              }t        |      dk7  rt	        d|z        |\  }}}||f|fS )Nr   z/malformed htdigest file (error reading line %d)r   )r"   r   rp   r   r   r   r   s          r#   rY   zHtdigestFile._parse_record  sW    &&w/v;!N%& ' '"eTe}d""r%   c                 (    |\  }}t        d|||      S )Nz	%s:%s:%s
r   )r"   rk   r   r   r   s        r#   r   zHtdigestFile._render_record  s    eL$t<<r%   c                 <    || j                   }|t        d      |S )NzGyou must specify a realm explicitly, or set the default_realm attribute)r  r   r   s     r#   _require_realmzHtdigestFile._require_realm  s1    =&&E} !E F Fr%   c                 H    | j                  |      }| j                  |d      S )Nr   )r
  r   r   s     r#   r   zHtdigestFile._encode_realm  s%    ##E*!!%11r%   c                 F    | j                  |      | j                  |      fS rB   )r   r   r"   r   r   s      r#   _encode_keyzHtdigestFile._encode_key#  s#      &(:(:5(AAAr%   c                     t        d | j                  D              }|D cg c]  }| j                  |       c}S c c}w )z%Return list of all realms in databasec              3   &   K   | ]	  }|d      yw)rX   Nr   )r   rk   s     r#   r   z&HtdigestFile.realms.<locals>.<genexpr>,  s     5SV5s   )r   r5   r   )r"   realmsr   s      r#   r  zHtdigestFile.realms*  s5    5t}}557=>e""5)>>>s   <c                     | j                  |      }| j                  D cg c]  }|d   |k(  r| j                  |d           c}S c c}w )zReturn list of all users in specified realm.

        * uses ``self.default_realm`` if no realm explicitly provided.
        * returns empty list if realm not found.
        rX   r   )r   r5   r   )r"   r   rk   s      r#   r   zHtdigestFile.users/  sQ     ""5)6:mm $sq6U? ""3q6* $ 	$ $s   #Ac                     |t         u rd|}}| j                  |      }t        j                  |||| j                        }| j                  |||      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r0   )_UNSETr
  r	   r   r0   r   r"   r   r   r   r   s        r#   r   zHtdigestFile.set_passwordQ  sP     v"E8E##E*}}XtUT]]K}}T5$//r%   r   r   r   r   c                 (    | j                  |||      S r   r   r"   r   r   r   s       r#   r   zHtdigestFile.updated  s       uh77r%   c                     | j                  ||      }| j                  j                  |      }|yt        r|j	                  | 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  r5   r   r   r   r0   )r"   r   r   rk   r   s        r#   r   zHtdigestFile.get_hashj  sL     tU+}}  %<;;t}}-Dr%   c                     |t         u rd|}}t        r+t        |t              r|j	                  | j
                        }| j                  ||      }| j                  ||      }| 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   r0   r  rt   rw   )r"   r   r   r   rk   rs   s         r#   r   zHtdigestFile.set_hash}  se     6>4E:dC(;;t}}-DtU+##C.r%   r   c                 &    | j                  ||      S r   r   r  s      r#   r   zHtdigestFile.find  s     }}T5))r%   c                     | j                  ||      }	 | j                  |= | j                          y# t        $ r Y yw xY w)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  r5   r   rw   )r"   r   r   rk   s       r#   r   zHtdigestFile.delete  sJ     tU+	c" 	  		s   2 	>>c                     | j                  |      }| j                  }|D cg c]  }|d   |k(  s| }}|D ]  }||=  | j                          t        |      S c c}w )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)
        rX   )r   r5   rw   r   )r"   r   rf   rk   keyss        r#   delete_realmzHtdigestFile.delete_realm  si     ""5)--&:#a&E/:: 	C	4y	 ;s
   AAc                     |t         u rd|}}| j                  |      }| j                  |      }| j                  j	                  ||f      }|yt        j                  ||||| j                        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  r   r   r5   r   r	   r   r0   r  s        r#   r   zHtdigestFile.check_password  su    $ v"E8E  &""5)}}  $u.<xtU(,7 	7r%   r   c                 (    | j                  |||      S r   r   r  s       r#   r   zHtdigestFile.verify  s     ""499r%   )NNrB   )r=   r   r   r   r  r9   rY   r   r
  r   r  r  r   r  r   r   r   r   r   r   r   r  r   r   r  r  s   @r#   r   r   r  s    B^ M
9#=2B?
$D (,f 0& %#13838& $(f 4 %#-/*/*
" *. 7: %#35:5:r%   )/r   
__future__r   logging	getLoggerr=   r^   rK   warningsr   passlibr   r   passlib.contextr   passlib.excr   passlib.hashr	   passlib.utilsr
   r   r   passlib.utils.decorr   passlib.utils.compatr   r   r   r   __all__objectr  r   r]   r   ra   rb   r   r   r   r   r   r   r  r   r   r   r%   r#   <module>r/     s    .
 & 'g''1 	  " ( + ! @ @ 1 B B  

	 &  

j& jJ %&R *+ *Z *+ X3; X3Bm:; m:r%   