
     hI                       d Z ddlmZmZmZ ddlmZ ddlZddlZddl	Z	ddl
Z
 e
j                  e      ZddlZddlZddlZddlZddlZerddlmZmZmZmZ n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Z ddl!Z dd
l"m#Z$ [ ddl'm(Z( ddl)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6 ddl7m8Z8m9Z9m:Z: ddlm;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZD ddlEmFZFmGZG ddlHmIZImJZJmKZK ddlLmMZM g dZNej                  dk  r.ddlmPZP dePvr# ePj                  d       ejM                  d       [P ej                   e;d      ej                        ZTg dZUd ZVd-dZWd ZX eYe$      ZZ ej                  d      Z[ G d d e\      Z] ej                  d!      j                  Z` ej                  d"      j                  Zbd#Zc G d$ d%e\      Zd G d& d'e4      Ze G d( d)e4      Zfd*e8dd+ fd,Zgy# e%$ r ejM                  d       dxZ$ZY yw xY w).z@passlib.totp -- TOTP / RFC6238 / Google Authenticator utilities.    )absolute_importdivisionprint_function)PY3N)urlparse	parse_qslquoteunquote)r	   r
   )r   r   )warn)default_backend)ciphersz=can't import 'cryptography' package, totp encryption disabled)exc)
TokenErrorMalformedTokenErrorInvalidTokenErrorUsedTokenError)
to_unicodeto_bytesconsteqgetrandbytesrngSequenceMixin	xor_bytes
getrandstr)BASE64_CHARS	b32encode	b32decode)
uunicodenative_string_typesbascii_to_str	int_types	num_typesirangebyte_elem_value	UnicodeIOsuppress_cause)hybrid_methodmemoized_property)lookup_hashcompile_hmacpbkdf2_hmac)pbkdf2_sha256)	AppWalletTOTPr   r   r   r   	TotpToken	TotpMatch)         )
uses_queryotpauthz4registered 'otpauth' scheme with urlparse.uses_queryz\s|[-=])r4         c                 z    t         D ]  }| |z  r	|c S  t         d   }d}t         D ]  }| |z  |kD  s|}| |z  } |S )zb
    helper for group_string() --
    calculates optimal size of group for given string size.
    r   )_chunk_sizes)klensizebestrems       N/var/www/html/Resume-Scraper/venv/lib/python3.12/site-packages/passlib/totp.py_get_group_sizer@   Y   s_      d{K
 ?D
C $;D+C K    c                 ~     t               }t        |      |j                   fdt        d|      D              S )z
    reformat string into (roughly) evenly-sized groups, separated by **sep**.
    useful for making tokens & keys easier to read by humans.
    c              3   .   K   | ]  }||z      y wN ).0or<   values     r?   	<genexpr>zgroup_string.<locals>.<genexpr>s   s     CE!AdFOCs   r   )lenr@   joinr$   )rH   sepr;   r<   s   `  @r?   group_stringrM   l   s6    
 u:D4 D88CVAtT-BCCCrA   c                 X   |dk(  r)t        | t              st        j                  | dd      | S t	        | d      } t
        j                  d|       j                  d      } |dk(  s|dk(  r#t        j                  | j                               S |d	k(  rt        |       S t        d
|      )zR
    internal TOTP() helper --
    decodes key according to specified format.
    rawbyteskeyparam zutf-8hexbase16base32unknown byte-encoding format: )
isinstancerP   r   ExpectedTypeErrorr   	_clean_resubencodebase64	b16decodeupperr   
ValueErrorrQ   formats     r?   _decode_bytesrd   y   s    
 #u%''We<<
 S
&C
--C
 
'
'
0C&H,		,,	8	~ vGHHrA   z(?i)^[a-z0-9][a-z0-9_.-]*$c                   l    e Zd ZdZdZdZdZdZ	 	 ddZd Z	d Z
ed        Zd	 Zedd
       Zd Zd Zy)r.   a  
    This class stores application-wide secrets that can be used
    to encrypt & decrypt TOTP keys for storage.
    It's mostly an internal detail, applications usually just need
    to pass ``secrets`` or ``secrets_path`` to :meth:`TOTP.using`.

    .. seealso::

        :ref:`totp-storing-instances` for more details on this workflow.

    Arguments
    =========
    :param secrets:
        Dict of application secrets to use when encrypting/decrypting
        stored TOTP keys.  This should include a secret to use when encrypting
        new keys, but may contain additional older secrets to decrypt
        existing stored keys.

        The dict should map tags -> secrets, so that each secret is identified
        by a unique tag.  This tag will be stored along with the encrypted
        key in order to determine which secret should be used for decryption.
        Tag should be string that starts with regex range ``[a-z0-9]``,
        and the remaining characters must be in ``[a-z0-9_.-]``.

        It is recommended to use something like a incremental counter
        ("1", "2", ...), an ISO date ("2016-01-01", "2016-05-16", ...), 
        or a timestamp ("19803495", "19813495", ...) when assigning tags.

        This mapping be provided in three formats:

        * A python dict mapping tag -> secret
        * A JSON-formatted string containing the dict
        * A multiline string with the format ``"tag: value\ntag: value\n..."``

        (This last format is mainly useful when loading from a text file via **secrets_path**)

        .. seealso:: :func:`generate_secret` to create a secret with sufficient entropy

    :param secrets_path:
        Alternately, callers can specify a separate file where the
        application-wide secrets are stored, using either of the string
        formats described in **secrets**.

    :param default_tag:
        Specifies which tag in **secrets** should be used as the default
        for encrypting new keys. If omitted, the tags will be sorted,
        and the largest tag used as the default.

        if all tags are numeric, they will be sorted numerically;
        otherwise they will be sorted alphabetically.
        this permits tags to be assigned numerically,
        or e.g. using ``YYYY-MM-DD`` dates.

    :param encrypt_cost:
        Optional time-cost factor for key encryption.
        This value corresponds to log2() of the number of PBKDF2
        rounds used.

    .. warning::

        The application secret(s) should be stored in a secure location by
        your application, and each secret should contain a large amount
        of entropy (to prevent brute-force attacks if the encrypted keys
        are leaked).

        :func:`generate_secret` is provided as a convenience helper
        to generate a new application secret of suitable size.

        Best practice is to load these values from a file via **secrets_path**,
        and then have your application give up permission to read this file
        once it's running.

    Public Methods
    ==============
    .. autoattribute:: has_secrets
    .. autoattribute:: default_tag

    Semi-Private Methods
    ====================
    The following methods are used internally by the :class:`TOTP`
    class in order to encrypt & decrypt keys using the provided application
    secrets.  They will generally not be publically useful, and may have their
    API changed periodically.

    .. automethod:: get_secret
    .. automethod:: encrypt_key
    .. automethod:: decrypt_key
          Nc                 v   |)t        |t              rt        |      }|dk\  sJ || _        |'|t	        d      t        |d      j                         }| j                  |      x}| _        |rK|| j                  |       n/t        d |D              rt        |t              }nt        |      }|| _        y y )Nr   z3'secrets' and 'secrets_path' are mutually exclusivertc              3   <   K   | ]  }|j                           y wrD   )isdigit)rF   tags     r?   rI   z%AppWallet.__init__.<locals>.<genexpr>)  s     6sS[[]6s   )rQ   )rY   r    intencrypt_cost	TypeErroropenread_parse_secrets_secrets
get_secretallmaxdefault_tag)selfsecretsrw   rn   secrets_paths        r?   __init__zAppWallet.__init__  s     #,(;<"<01$$ ,D #" UVV<.335G #'"5"5g">>$-
 &,6g66!'s3!'l*D rA   c                 `    d}t        |t              rV|j                         j                  d      rt	        j
                  |      }n!d|v rd|v rd } ||      }d}nt        d      |i S t        |t              r|j                         }n|rt        d      t         fd	|D              S )
zf
        parse 'secrets' parameter

        :returns:
            Dict[tag:str, secret:bytes]
        T)[{
:c              3      K   | j                         D ]^  }|j                         }|s|j                  d      r(|j                  dd      \  }}|j                         |j                         f ` y w)N#r      )
splitlinesstrip
startswithsplit)sourcelinerl   secrets       r?   
iter_pairsz,AppWallet._parse_secrets.<locals>.iter_pairsA  sb      & 1 1 3 >#zz|(<*.**S!*<KC"%))+v||~"==	>s   &A5A5:A5Fz"unrecognized secrets string formatz+'secrets' must be mapping, or list of itemsc              3   H   K   | ]  \  }}j                  ||        y wrD   )_parse_secret_pair)rF   rl   rH   rx   s      r?   rI   z+AppWallet._parse_secrets.<locals>.<genexpr>W  s*      ."U ++C7 .s   ")
rY   r    lstripr   jsonloadsra   dictitemsro   )rx   r   
check_typer   s   `   r?   rr   zAppWallet._parse_secrets/  s     
f12}}))*5F+C6M> $F+"
 !EFF >I%\\^F IJJ  .&,. . 	.rA   c                 &   t        |t              rn*t        |t              rt        |      }nt	        d|      t
        j                  |      st        d|      t        |t              st        |d|      }|st        d|      ||fS )Nztag must be unicode/string: z!tag contains invalid characters: zsecret rR   ztag contains empty secret: )
rY   r    rm   strro   _tag_rematchra   rP   r   )rx   rl   rH   s      r?   r   zAppWallet._parse_secret_pairZ  s    c./S!c(CEFF}}S!cKLL%'U*>?EEFFEzrA   c                     | j                   duS )z2whether at least one application secret is presentN)rw   rx   s    r?   has_secretszAppWallet.has_secretsm  s     t++rA   c                     | j                   }|st        d      	 ||   S # t        $ r t        t        d|            w xY w)zh
        resolve a secret tag to the secret (as bytes).
        throws a KeyError if not found.
        z!no application secrets configuredzunknown secret tag: )rs   KeyErrorr'   )rx   rl   ry   s      r?   rt   zAppWallet.get_secretr  sP    
 -->??	N3< 	N c*K!LMM	Ns	     !Ac                    t         t        d      t        d||d|z  d      }t        j                  t         j                  j                  |dd       t         j                  j                  |dd       t                     }|r|j                         n|j                         }|j                  |       |j                         z   S )a&  
        Internal helper for :meth:`encrypt_key` --
        handles lowlevel encryption/decryption.

        Algorithm details:

        This function uses PBKDF2-HMAC-SHA256 to generate a 32-byte AES key
        and a 16-byte IV from the application secret & random salt.
        It then uses AES-256-CTR to encrypt/decrypt the TOTP key.

        CTR mode was chosen over CBC because the main attack scenario here
        is that the attacker has stolen the database, and is trying to decrypt a TOTP key
        (the plaintext value here).  To make it hard for them, we want every password
        to decrypt to a potentially valid key -- thus need to avoid any authentication
        or padding oracle attacks.  While some random padding construction could be devised
        to make this work for CBC mode, a stream cipher mode is just plain simpler.
        OFB/CFB modes would also work here, but seeing as they have malleability
        and cyclic issues (though remote and barely relevant here),
        CTR was picked as the best overall choice.
        NzITOTP encryption requires 'cryptography' package (https://cryptography.io)sha256r   0   )saltroundskeylen    )_cg_ciphersRuntimeErrorr,   Cipher
algorithmsAESmodesCTR_cg_default_backend	decryptor	encryptorupdatefinalize)rH   r   r   costdecryptkeyivcipherctxs           r?   _cipher_aes_keyzAppWallet._cipher_aes_key  s    .   ; < <
 Hf4dTVW ##K$:$:$>$>uSbz$J$/$5$5$9$9%*$E$7$9; %,f 1A1A1Czz% 3<<>11rA   c           	      $   |st        d      t        t        | j                        }| j                  }| j
                  }|st        d      | j                  || j                  |      ||      }t        d||t        |      t        |            S )a0  
        Helper used to encrypt TOTP keys for storage.

        :param key:
            TOTP key to encrypt, as raw bytes.

        :returns:
            dict containing encrypted TOTP key & configuration parameters.
            this format should be treated as opaque, and potentially subject
            to change, though it is designed to be easily serialized/deserialized
            (e.g. via JSON).

        .. note::

            This function requires installation of the external
            `cryptography <https://cryptography.io>`_ package.

        To give some algorithm details:  This function uses AES-256-CTR to encrypt
        the provided data.  It takes the application secret and randomly generated salt,
        and uses PBKDF2-HMAC-SHA256 to combine them and generate the AES key & IV.
        zno key providedz8no application secrets configured, can't encrypt OTP keyr   )vctsk)ra   r   r   	salt_sizern   rw   ro   r   rt   r   r   )rx   rQ   r   r   rl   ckeys         r?   encrypt_keyzAppWallet.encrypt_key  s    , .//C0  VWW##C)=tTJa43)D/Yt_MMrA   c                 b   t        |t              st        d      |j                  dd      }d}|dk(  r| j                  }nt        d|      |d   }|d   } |t        |d	         | j                  |      t        |d
         |      }|| j                  k7  s|| j                  k7  rd}||fS )a  
        Helper used to decrypt TOTP keys from storage format.
        Consults configured secrets to decrypt key.

        :param source:
            source object, as returned by :meth:`encrypt_key`.

        :returns:
            ``(key, needs_recrypt)`` --

            **key** will be the decrypted key, as bytes.

            **needs_recrypt** will be a boolean flag indicating
            whether encryption cost or default tag is too old,
            and henace that key needs re-encrypting before storing.

        .. note::

            This function requires installation of the external
            `cryptography <https://cryptography.io>`_ package.
        z'enckey' must be dictionaryr   NFr   z)missing / unrecognized 'enckey' version: r   r   r   r   )rH   r   r   r   T)
rY   r   ro   getr   ra   r   rt   rn   rw   )rx   enckeyversionneeds_recrypt_cipher_keyrl   r   rQ   s           r?   decrypt_keyzAppWallet.decrypt_key  s    , &$'9::**S$'a<..KgWXXSkc{F3K(??3'6#;'	
 4$$$t/?/?(? MM!!rA   )NNNN)F)__name__
__module____qualname____doc__r   rn   rs   rw   r{   rr   r   propertyr   rt   staticmethodr   r   r   rE   rA   r?   r.   r.      s{    Wz I
 L H K
 EI"'+R).V& , ,N" #2 #2JNB("rA   r.   z>Qz>Is                   c                       e Zd ZdZdZdxZZdZej                  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
        Z	 	 	 d/ fd	Zed0d       Zed        Zed        Zed        Zej<                  d        Zed        Zej<                  d        Zed        Z ed        Z!d1dZ"ed        Z#d Z$d Z%e&d        Z'd2dZ(d Z)ed        Z*d3dZ+d2dZ,ed        Z-ed         Z.ed!        Z/ed"        Z0e	 	 d.d#       Z1ed$        Z2ed%        Z3d4d&Z4d' Z5ed(        Z6d2d)Z7ed*        Z8ed+        Z9ed,        Z:d2d-Z; xZ<S )5r/   a9  
    Helper for generating and verifying TOTP codes.

    Given a secret key and set of configuration options, this object
    offers methods for token generation, token validation, and serialization.
    It can also be used to track important persistent TOTP state,
    such as the last counter used.

    This class accepts the following options
    (only **key** and **format** may be specified as positional arguments).

    :arg str key:
        The secret key to use. By default, should be encoded as
        a base32 string (see **format** for other encodings).

        Exactly one of **key** or ``new=True`` must be specified.

    :arg str format:
        The encoding used by the **key** parameter. May be one of:
        ``"base32"`` (base32-encoded string),
        ``"hex"`` (hexadecimal string), or ``"raw"`` (raw bytes).
        Defaults to ``"base32"``.

    :param bool new:
        If ``True``, a new key will be generated using :class:`random.SystemRandom`.

        Exactly one ``new=True`` or **key** must be specified.

    :param str label:
        Label to associate with this token when generating a URI.
        Displayed to user by most OTP client applications (e.g. Google Authenticator),
        and typically has format such as ``"John Smith"`` or ``"jsmith@webservice.example.org"``.
        Defaults to ``None``.
        See :meth:`to_uri` for details.

    :param str issuer:
        String identifying the token issuer (e.g. the domain name of your service).
        Used internally by some OTP client applications (e.g. Google Authenticator) to distinguish entries
        which otherwise have the same label.
        Optional but strongly recommended if you're rendering to a URI.
        Defaults to ``None``.
        See :meth:`to_uri` for details.

    :param int size:
        Number of bytes when generating new keys. Defaults to size of hash algorithm (e.g. 20 for SHA1).

        .. warning::

            Overriding the default values for ``digits``, ``period``, or ``alg`` may
            cause problems with some OTP client programs (such as Google Authenticator),
            which may have these defaults hardcoded.

    :param int digits:
        The number of digits in the generated / accepted tokens. Defaults to ``6``.
        Must be in range [6 .. 10].

        .. rst-class:: inline-title
        .. caution::
           Due to a limitation of the HOTP algorithm, the 10th digit can only take on values 0 .. 2,
           and thus offers very little extra security.

    :param str alg:
        Name of hash algorithm to use. Defaults to ``"sha1"``.
        ``"sha256"`` and ``"sha512"`` are also accepted, per :rfc:`6238`.

    :param int period:
        The time-step period to use, in integer seconds. Defaults to ``30``.

    ..
        See the passlib documentation for a full list of attributes & methods.
    
   r   Nr7   sha1   Fc                   	 t        d| fi       		fd}| |d|      	_        | |d|      	_        | |d|      	_        | |d|      	_        |rt        di |	_        |r?t        d      |2t        |t
              st        j                  |t
        d      |	_        |6t         |       t              r
 |       d	k\  sJ d
       t        |      	_        	S )a:  
        Dynamically create subtype of :class:`!TOTP` class
        which has the specified defaults set.

        :parameters: **digits, alg, period, issuer**:

            All these options are the same as in the :class:`TOTP` constructor,
            and the resulting class will use any values you specify here
            as the default for all TOTP instances it creates.

        :param wallet:
            Optional :class:`AppWallet` that will be used for encrypting/decrypting keys.

        :param secrets, secrets_path, encrypt_cost:

            If specified, these options will be passed to the :class:`AppWallet` constructor,
            allowing you to directly specify the secret keys that should be used
            to encrypt & decrypt stored keys.

        :returns:
            subclass of :class:`!TOTP`.

        This method is useful for creating a TOTP class configured
        to use your application's secrets for encrypting & decrypting
        keys, as well as create new keys using it's desired configuration defaults.

        As an example::

            >>> # your application can create a custom class when it initializes
            >>> from passlib.totp import TOTP, generate_secret
            >>> TotpFactory = TOTP.using(secrets={"1": generate_secret()})

            >>> # subsequent TOTP objects created from this factory
            >>> # will use the specified secrets to encrypt their keys...
            >>> totp = TotpFactory.new()
            >>> totp.to_dict()
            {'enckey': {'c': 14,
              'k': 'H77SYXWORDPGVOQTFRR2HFUB3C45XXI7',
              's': 'G5DOQPIHIBUM2OOHHADQ',
              't': '1',
              'v': 1},
             'type': 'totp',
             'v': 1}

        .. seealso:: :ref:`totp-creation` and :ref:`totp-storing-instances` tutorials for a usage example
        r/   c                 X    t        t        d      }||| <    di |}t        ||       S )z
            helper which uses constructor to validate parameter value.
            it returns corresponding attribute, so we use normalized value.
            rO   rb   rE   )r   
_DUMMY_KEYgetattr)attrrH   kwdsobjsubclss       r?   
norm_paramzTOTP.using.<locals>.norm_param  s2     Ju5DDJ.4.C3%%rA   digitsalgperiodissuerz6'wallet' and 'secrets' keywords are mutually exclusivewalletr   z1now() function must return non-negative int/floatrE   )typer   r   r   r   r.   r   ro   rY   r   rZ   r#   r   now)
clsr   r   r   r   r   r   r   r   r   s
            @r?   usingz
TOTP.using  s    p fsfb)	& &x8FM?#E3/FJ&x8FM &x8FM%--FM XYYfi0++FIxHH"FM?ceY/CEQJ DCD%c*FJrA   c                      | dddi|S )zY
        convenience alias for creating new TOTP key, same as ``TOTP(new=True)``
        newTrE   rE   )r   r   s     r?   r   zTOTP.new  s    
 $t$t$$rA   c                    t        t        | 
  di | |
r|
| _        t	        |xs | j
                        }|j                  | _        |j                  }|dk  rt        d|z        |r;|rt        d      ||}n||kD  rt        d|z        t        t        |      | _        n-|st        d      |dk(  r|| _        n|rt        ||      | _        t!        | j                        | j"                  k  r8d| j"                  z  }|rt        |      t%        |t&        j(                  d	       || j*                  }t-        |t.              st        d
t1        |      z        |dk  s|dkD  rt        d      || _        |r| j3                  |       || _        |	r| j7                  |	       |	| _        || j;                  |dd       || _        y y )Nr4   z%r hash digest too smallz+'key' and 'new=True' are mutually exclusivez+'size' should be less than digest size (%d)z4must specify either an existing 'key', or 'new=True'	encryptedz5for security purposes, secret key must be >= %d bytesr   )
stacklevelz#digits must be an integer, not a %rr7   r   zdigits must in range(6,11)r   )minvalrE   )superr/   r{   changedr*   r   namedigest_sizer   ro   ra   r   r   rQ   encrypted_keyrd   rJ   _min_key_sizer   r   PasslibSecurityWarningr   rY   r"   r   _check_labellabel_check_issuerr   _check_serialr   )rx   rQ   rc   r   r   r   r<   r   r   r   r   r   infor   msg	__class__s                  r?   r{   zTOTP.__init__  s   
 	dD"*T*"DL 3?$((+99&&?9C?@@  MNN|"# ! "(*5"6 7 7#C.DHRSS{"!$D$S&1DH txx=4--- JDL^L^^C o%S#44C >[[F&),ADLPQQA:"9:: e$DJ v& DK vx: DK rA   c                 |    t        | t              st        j                  | d|      | |k  rt	        d||fz        y)zR
        check that serial value (e.g. 'counter') is non-negative integer
        rm   z%s must be >= %dN)rY   r"   r   rZ   ra   )rH   rS   r   s      r?   r   zTOTP._check_serialO  sD    
 %+''ue<<6>/5&/ABB rA   c                 (    | rd| v rt        d      yy)zQ
        check that label doesn't contain chars forbidden by KeyURI spec
        r   zlabel may not contain ':'Nra   r   s    r?   r   zTOTP._check_labelY  s     
 SE\899 "5rA   c                 (    | rd| v rt        d      yy)zR
        check that issuer doesn't contain chars forbidden by KeyURI spec
        r   zissuer may not contain ':'Nr   )r   s    r?   r   zTOTP._check_issuera  s     
 cVm9:: $6rA   c                     | j                   S )z)
        secret key as raw bytes
        )_keyr   s    r?   rQ   zTOTP.keyp  s    
 yyrA   c                     t        |t              st        j                  |t        d      || _        d x| _        | _        y )NrQ   )rY   rP   r   rZ   r   _encrypted_key_keyed_hmac)rx   rH   s     r?   rQ   zTOTP.keyw  s<     %'''ue<<	 265d.rA   c                     | j                   }|;| j                  }|st        d      |j                  | j                        x}| _         |S )z
        secret key, encrypted using application secret.
        this match the output of :meth:`AppWallet.encrypt_key`,
        and should be treated as an opaque json serializable object.
        z6no application secrets present, can't encrypt TOTP key)r   r   ro   r   rQ   )rx   r   r   s      r?   r   zTOTP.encrypted_key  sM     $$>[[F XYY+1+=+=dhh+GGFT(rA   c                     | j                   }|st        d      |j                  |      \  | _        }|rd| _        y || _        y )Nz6no application secrets present, can't decrypt TOTP keyT)r   ro   r   rQ   r   r   )rx   rH   r   r   s       r?   r   zTOTP.encrypted_key  sE    TUU"("4"4U";-DL #(DrA   c                 n    t        t        j                  | j                              j	                         S )z:
        secret key encoded as hexadecimal string
        )r!   r^   	b16encoderQ   lowerr   s    r?   hex_keyzTOTP.hex_key  s'    
 V--dhh78>>@@rA   c                 ,    t        | j                        S )z5
        secret key encoded as base32 string
        )r   rQ   r   s    r?   
base32_keyzTOTP.base32_key  s    
 ""rA   c                     |dk(  s|dk(  r| j                   }n |dk(  r| j                  }nt        d|      |rt        ||      }|S )a  
        pretty-print the secret key.

        This is mainly useful for situations where the user cannot get the qrcode to work,
        and must enter the key manually into their TOTP client. It tries to format
        the key in a manner that is easier for humans to read.

        :param format:
            format to output secret key. ``"hex"`` and ``"base32"`` are both accepted.

        :param sep:
            separator to insert to break up key visually.
            can be any of ``"-"`` (the default), ``" "``, or ``False`` (no separator).

        :return:
            key as native string.

        Usage example::

            >>> t = TOTP('s3jdvb7qd2r7jpxx')
            >>> t.pretty_key()
            'S3JD-VB7Q-D2R7-JPXX'
        rU   rV   rW   rX   )r  r  ra   rM   )rx   rc   rL   rQ   s       r?   
pretty_keyzTOTP.pretty_key  sN    0 U?f0,,Cx//C6KLLsC(C
rA   c                    t        |t              r|S t        |t              rt        |      S |t        | j	                               S t        |d      r#t        j                  |j                               S t        j                  |dd      )as  
        Normalize time value to unix epoch seconds.

        :arg time:
            Can be ``None``, :class:`!datetime`,
            or unix epoch timestamp as :class:`!float` or :class:`!int`.
            If ``None``, uses current system time.
            Naive datetimes are treated as UTC.

        :returns:
            unix epoch timestamp as :class:`int`.
        utctimetuplezint, float, or datetimetime)rY   r"   floatrm   r   hasattrcalendartimegmr  r   rZ   )r   r  s     r?   normalize_timezTOTP.normalize_time  sv     dI&Ke$t9\swwy>!T>* ??4#4#4#677''.GPPrA   c                      || j                   z  S )zI
        convert timestamp to HOTP counter using :attr:`period`.
        r   )rx   r  s     r?   _time_to_counterzTOTP._time_to_counter  s     t{{""rA   c                      || j                   z  S )zI
        convert HOTP counter to timestamp using :attr:`period`.
        r  )rx   counters     r?   _counter_to_timezTOTP._counter_to_time  s     $$rA   c                 &   | j                   }t        |t              rt        d      ||fz  }nGt	        |d      }t
        j                  t        d      |      }|j                         st        d      t        |      |k7  rt        d|z        |S )a  
        Normalize OTP token representation:
        strips whitespace, converts integers to a zero-padded string,
        validates token content & number of digits.

        This is a hybrid method -- it can be called at the class level,
        as ``TOTP.normalize_token()``, or the instance level as ``TOTP().normalize_token()``.
        It will normalize to the instance-specific number of :attr:`~TOTP.digits`,
        or use the class default.

        :arg token:
            token as ascii bytes, unicode, or an integer.

        :raises ValueError:
            if token has wrong number of digits, or contains non-numeric characters.

        :returns:
            token as :class:`!unicode` string, containing only digits 0-9.
        %0*dtokenrR   rT   z&Token must contain only the digits 0-9z!Token must have exactly %d digits)
r   rY   r"   r   r   r[   r\   rk   r   rJ   )self_or_clsr  r   s      r?   normalize_tokenzTOTP.normalize_token   s    * ##eY'fI/EuG4EMM!B%/E==?)*RSSu:%&IF&RSSrA   c                     | j                  |      }| j                  |      }|dk  rt        d      | j                  |      }t	        | ||      S )a  
        Generate token for specified time
        (uses current time if none specified).

        :arg time:
            Can be ``None``, a :class:`!datetime`,
            or class:`!float` / :class:`!int` unix epoch timestamp.
            If ``None`` (the default), uses current system time.
            Naive datetimes are treated as UTC.

        :returns:

            A :class:`TotpToken` instance, which can be treated
            as a sequence of ``(token, expire_time)`` -- see that class
            for more details.

        Usage example::

            >>> # generate a new token, wrapped in a TotpToken instance...
            >>> otp = TOTP('s3jdvb7qd2r7jpxx')
            >>> otp.generate(1419622739)
            <TotpToken token='897212' expire_time=1419622740>

            >>> # when you just need the token...
            >>> otp.generate(1419622739).token
            '897212'
        r   ztimestamp must be >= 0)r  r  ra   	_generater0   )rx   r  r  r  s       r?   generatezTOTP.generate.  sT    8 ""4(''-Q;566w'ug..rA   c                    t        |t              sJ d       |dk\  sJ d       | j                  }|'t        | j                  | j
                        x}| _         |t        |            }|j                  j                  }t        |      |k(  sJ d       |dk\  sJ d       t        |d         d	z  }t        |||d
z          d   dz  }| j                  }d|cxk  rdk  sJ d        J d       t        d      ||fz  | d S )z
        base implementation of HOTP token generation algorithm.

        :arg counter: HOTP counter, as non-negative integer
        :returns: token as unicode string
        zcounter must be integerr   zcounter must be non-negativeNz digest_size: sanity check failed   z"digest_size: sanity check 2 failed   r4   i   zdigits: sanity check failedr  )rY   r"   r   r+   r   rQ   _pack_uint64digest_infor   rJ   r%   _unpack_uint32r   r   )rx   r  
keyed_hmacdigestr   offsetrH   r   s           r?   r  zTOTP._generateQ  s    '9-H/HH!|;;;%%
,8488,LLJ)L12 ,,886{k)M+MM b F"FF ,s2vfVAX67:ZG 6B= === ==&	VUO+fWX66rA   c                 F     | j                  |      j                  |fi |S )a  
        Convenience wrapper around :meth:`TOTP.from_source` and :meth:`TOTP.match`.

        This parses a TOTP key & configuration from the specified source,
        and tries and match the token.
        It's designed to parallel the :meth:`passlib.ifc.PasswordHash.verify` method.

        :param token:
            Token string to match.

        :param source:
            Serialized TOTP key.
            Can be anything accepted by :meth:`TOTP.from_source`.

        :param \\*\\*kwds:
            All additional keywords passed to :meth:`TOTP.match`.

        :return:
            A :class:`TotpMatch` instance, or raises a :exc:`TokenError`.
        )from_sourcer   )r   r  r   r   s       r?   verifyzTOTP.verifys  s%    , -sv&,,U;d;;rA   c                 `   | j                  |      }| j                  |d       ||z   }|d}t        || j                  ||z
              }| j                  ||z         dz   }| j	                  |||      }	|	|k\  sJ d       |	|k(  rt        |dz   | j                  z        t        | |	||      S )aP  
        Match TOTP token against specified timestamp.
        Searches within a window before & after the provided time,
        in order to account for transmission delay and small amounts of skew in the client's clock.

        :arg token:
            Token to validate.
            may be integer or string (whitespace and hyphens are ignored).

        :param time:
            Unix epoch timestamp, can be any of :class:`!float`, :class:`!int`, or :class:`!datetime`.
            if ``None`` (the default), uses current system time.
            *this should correspond to the time the token was received from the client*.

        :param int window:
            How far backward and forward in time to search for a match.
            Measured in seconds. Defaults to ``30``.  Typically only useful if set
            to multiples of :attr:`period`.

        :param int skew:
            Adjust timestamp by specified value, to account for excessive
            client clock skew. Measured in seconds. Defaults to ``0``.

            Negative skew (the common case) indicates transmission delay,
            and/or that the client clock is running behind the server.

            Positive skew indicates the client clock is running ahead of the server
            (and by enough that it cancels out any negative skew added by
            the transmission delay).

            You should ensure the server clock uses a reliable time source such as NTP,
            so that only the client clock's inaccuracy needs to be accounted for.

            This is an advanced parameter that should usually be left at ``0``;
            The **window** parameter is usually enough to account
            for any observed transmission delay.

        :param last_counter:
            Optional value of last counter value that was successfully used.
            If specified, verify will never search earlier counters,
            no matter how large the window is.

            Useful when client has previously authenticated,
            and thus should never provide a token older than previously
            verified value.

        :raises ~passlib.exc.TokenError:

            If the token is malformed, fails to match, or has already been used.

        :returns TotpMatch:

            Returns a :class:`TotpMatch` instance on successful match.
            Can be treated as tuple of ``(counter, time)``.
            Raises error if token is malformed / can't be verified.

        Usage example::

            >>> totp = TOTP('s3jdvb7qd2r7jpxx')

            >>> # valid token for this time period
            >>> totp.match('897212', 1419622729)
            <TotpMatch counter=47320757 time=1419622729 cache_seconds=60>

            >>> # token from counter step 30 sec ago (within allowed window)
            >>> totp.match('000492', 1419622729)
            <TotpMatch counter=47320756 time=1419622729 cache_seconds=60>

            >>> # invalid token -- token from 60 sec ago (outside of window)
            >>> totp.match('760389', 1419622729)
            Traceback:
                ...
            InvalidTokenError: Token did not match
        windowr"  r   z*sanity check failed: counter went backward)expire_time)r  r   rv   r  _find_matchr   r   r1   )
rx   r  r  r/  skewlast_counterclient_timestartendr  s
             r?   r   z
TOTP.match  s    V ""4(68,TkLL$"7"7f8L"MN##K&$89A= ""5%5,&T(TTl" lQ.>$++-MNN wf55rA   c                     | j                  |      }|dk  rd}||k  r
t               | j                  }|||k  st        | ||            r|S |}||k  rt        | ||            r|S |dz  }||k  rt               )aw  
        helper for verify() --
        returns counter value within specified range that matches token.

        :arg token:
            token value to match (will be normalized internally)

        :arg start:
            starting counter value to check

        :arg end:
            check up to (but not including) this counter value

        :arg expected:
            optional expected value where search should start,
            to help speed up searches.

        :raises ~passlib.exc.TokenError:
            If the token is malformed, or fails to verify.

        :returns:
            counter value that matched
        r   r   )r  r   r  r   )rx   r  r5  r6  expectedr  r  s          r?   r1  zTOTP._find_match  s    0 $$U+19E%<#%%>> Hu$4'%RZI[:\O muhw/0qLG m  !!rA   c                 >   t        |t              r-| j                  |j                  k(  r|S |j                  d      }t        |t              r| j                  |      S t        |d      }|j                  d      r| j                  |      S | j                  |      S )a  
        Load / create a TOTP object from a serialized source.
        This acts as a wrapper for the various deserialization methods:

        * TOTP URIs are handed off to :meth:`from_uri`
        * Any other strings are handed off to :meth:`from_json`
        * Dicts are handed off to :meth:`from_dict`

        :param source:
            Serialized TOTP object.

        :raises ValueError:
            If the key has been encrypted, but the application secret isn't available;
            or if the string cannot be recognized, parsed, or decoded.

            See :meth:`TOTP.using()` for how to configure application secrets.

        :returns:
            a :class:`TOTP` instance.
        Fencryptztotp sourcerR   z
otpauth://)
rY   r/   r   to_dictr   	from_dictr   r   from_uri	from_jsonr   r   s     r?   r,  zTOTP.from_source%  s    , fd# zzV]]*^^E^2Ffd#==((F-8\*<<''==((rA   c                     t        |d      j                         }t        |      }|j                  dk7  r| j	                  d      | j                  |j                         | j                  |      S )a<  
        create an OTP instance from a URI (such as returned by :meth:`to_uri`).

        :returns:
            :class:`TOTP` instance.

        :raises ValueError:
            if the uri cannot be parsed or contains errors.

        .. seealso:: :ref:`totp-configuring-clients` tutorial for a usage example
        urirR   r6   zwrong uri scheme)r   r   r   scheme_uri_parse_error_check_otp_typenetloc_from_parsed_uri)r   rB  results      r?   r>  zTOTP.from_uriM  se     E*002#==I%&&'9:: 	FMM*##F++rA   c                 J    |dk(  ry|dk(  rt        d      t        d|z        )zg
        validate otp URI type is supported.
        returns True or raises appropriate error.
        totpThotpzHOTP not supportedzunknown otp type: %r)NotImplementedErrorra   )r   r   s     r?   rE  zTOTP._check_otp_typed  s2     6>6>%&:;;/$677rA   c           	      >   |j                   }|j                  d      rt        |      dkD  rt        |dd       }n| j	                  d      d|v r	 |j                  d      \  }}nd}|r|j                         xs d}t        |      }t        |j                        D ]"  \  }}||v r| j	                  d|z        |||<   $ |r#d	|vr||d	<   n|d	   |k7  r| j	                  d
       | di  | j                  di |S # t        $ r | j	                  d      w xY w)z
        internal from_uri() helper --
        handles parsing a validated TOTP URI

        :param result:
            a urlparse() instance

        :returns:
            cls instance
        /r   Nzmissing labelr   zmalformed labelr   zduplicate parameter (%r)r   zconflicting issuer identifiersrE   )pathr   rJ   r
   rD  r   ra   r   r   r   query_adapt_uri_params)r   rH  r   r   paramsr   r   s          r?   rG  zTOTP._from_parsed_urip  sI    C SZ!^E!"I&E&&77 %<> %C 0 FKKM)TE E"fll+ 	DAqF{**+E+IJJF1I	 v%#)x !V+**+KLL 5*S**4V455/  >**+<==>s   D Dc                    |sJ d       |s| j                  d      t        |||d      }|r| j                  |d      |d<   |r||d<   |r| j                  |d      |d<   |rt        | d|t        j
                         |S )	zY
        from_uri() helper --
        converts uri params into constructor args.
        z"from_uri() failed to provide labelzmissing 'secret' parameterrW   )r   r   rQ   rc   r   r   r   z0: unexpected parameters encountered in otp uri: )rD  r   _uri_parse_intr   r   PasslibRuntimeWarning)	r   r   r   r   r   	algorithmr   extrar   s	            r?   rQ  zTOTP._adapt_uri_params  s     :::&&'CDD%F8L //ADN#DK //ADN u"88:rA   c                     t        d|       S )z8uri parsing helper -- creates preformatted error messagezInvalid otpauth uri: r   reasons    r?   rD  zTOTP._uri_parse_error  s     v?@@rA   c                 \    	 t        |      S # t        $ r | j                  d|z        w xY w)z#uri parsing helper -- int() wrapperzMalformed %r parameter)rm   ra   rD  )r   r   rS   s      r?   rT  zTOTP._uri_parse_int  s:    	Iv; 	I&&'?%'GHH	Is   
 +c                    || j                   }|st        d      | j                  |       t        |d      }| j	                         }|| j
                  }|r5| j                  |       t        |d      d|}|j                  d|f       t        d      j                  d |D              }|sJ d       t        d      ||fz  S )	a  
        Serialize key and configuration into a URI, per
        Google Auth's `KeyUriFormat <http://code.google.com/p/google-authenticator/wiki/KeyUriFormat>`_.

        :param str label:
            Label to associate with this token when generating a URI.
            Displayed to user by most OTP client applications (e.g. Google Authenticator),
            and typically has format such as ``"John Smith"`` or ``"jsmith@webservice.example.org"``.

            Defaults to **label** constructor argument. Must be provided in one or the other location.
            May not contain ``:``.

        :param str issuer:
            String identifying the token issuer (e.g. the domain or canonical name of your service).
            Optional but strongly recommended if you're rendering to a URI.
            Used internally by some OTP client applications (e.g. Google Authenticator) to distinguish entries
            which otherwise have the same label.

            Defaults to **issuer** constructor argument, or ``None``.
            May not contain ``:``.

        :raises ValueError:
            * if a label was not provided either as an argument, or in the constructor.
            * if the label or issuer contains invalid characters.

        :returns:
            all the configuration information for this OTP token generator,
            encoded into a URI.

        These URIs are frequently converted to a QRCode for transferring
        to a TOTP client application such as Google Auth.
        Usage example::

            >>> from passlib.totp import TOTP
            >>> tp = TOTP('s3jdvb7qd2r7jpxx')
            >>> uri = tp.to_uri("user@example.org", "myservice.another-example.org")
            >>> uri
            'otpauth://totp/user@example.org?secret=S3JDVB7QD2R7JPXX&issuer=myservice.another-example.org'

        .. versionchanged:: 1.7.2

            This method now prepends the issuer URI label.  This is recommended by the KeyURI
            specification, for compatibility with older clients.
        z<a label must be specified as argument, or in the constructor@r   r   &c              3   V   K   | ]!  \  }}t        d       |t        |d      fz   # yw)z%s=%srT   N)r   r	   )rF   rQ   rH   s      r?   rI   zTOTP.to_uri.<locals>.<genexpr>  s)     ^e'
c53C-D D^s   ')zparam_str should never be emptyzotpauth://totp/%s?%s)
r   ra   r   r	   _to_uri_paramsr   r   appendr   rK   )rx   r   r   rR  	param_strs        r?   to_urizTOTP.to_uri  s    \ =JJE[\\%  eS! $$&>[[Fv&
  %VS159EMM8V,- cFKK^W]^^	;;; '(E9+===rA   c                 l   d| j                   fg}| j                  dk7  r+|j                  d| j                  j                         f       | j                  dk7  r&|j                  dt        | j                        f       | j                  dk7  r&|j                  dt        | j                        f       |S )z+return list of (key, param) entries for URIr   r   rV  r7   r   r   r   )r  r   ra  r`   r   r   r   rx   argss     r?   r`  zTOTP._to_uri_params  s    4??+,88vKKdhhnn&678;;!KK3t{{#345;;"KK3t{{#345rA   c                 d    t        |d      }| j                  t        j                  |            S )an  
        Load / create an OTP object from a serialized json string
        (as generated by :meth:`to_json`).

        :arg json:
            Serialized output from :meth:`to_json`, as unicode or ascii bytes.

        :raises ValueError:
            If the key has been encrypted, but the application secret isn't available;
            or if the string cannot be recognized, parsed, or decoded.

            See :meth:`TOTP.using()` for how to configure application secrets.

        :returns:
            a :class:`TOTP` instance.

        .. seealso:: :ref:`totp-storing-instances` tutorial for a usage example
        zjson sourcerR   )r   r=  r   r   r@  s     r?   r?  zTOTP.from_json&  s(    ( F-8}}TZZ/00rA   c                 V    | j                  |      }t        j                  |dd      S )a  
        Serialize configuration & internal state to a json string,
        mainly useful for persisting client-specific state in a database.
        All keywords passed to :meth:`to_dict`.

        :returns:
            json string containing serializes configuration & state.
        r:  T),r   )	sort_keys
separators)r<  r   dumps)rx   r;  states      r?   to_jsonzTOTP.to_json=  s'     W-zz%4JGGrA   c           	      |    t        |t              rd|vr| j                  d       | di  | j                  di |S )aU  
        Load / create a TOTP object from a dictionary
        (as generated by :meth:`to_dict`)

        :param source:
            dict containing serialized TOTP key & configuration.

        :raises ValueError:
            If the key has been encrypted, but the application secret isn't available;
            or if the dict cannot be recognized, parsed, or decoded.

            See :meth:`TOTP.using()` for how to configure application secrets.

        :returns:
            A :class:`TOTP` instance.

        .. seealso:: :ref:`totp-storing-instances` tutorial for a usage example
        r   zunrecognized formatrE   )rY   r   _dict_parse_error_adapt_dict_kwdsr@  s     r?   r=  zTOTP.from_dictM  sF    ( &$'6+?''(=>>4)S))3F344rA   c                    | j                  |      sJ |j                  dd      }|r|| j                  k  s|| j                  kD  r| j	                  d|d      || j                  k7  rd|d<   d|v r)d|vsJ |j                  |j                  d      d	
       nd|vr| j	                  d      |j                  dd       |S )zt
        Internal helper for .from_json() --
        Adapts serialized json dict into constructor keywords.
        r   Nzmissing/unsupported version ()Tr   r   rQ   r   rb   zmissing 'enckey' / 'key'r3  )rE  popmin_json_versionjson_versionrp  r   )r   r   r   vers       r?   rq  zTOTP._adapt_dict_kwdse  s     ""4((hhsD!cC000C#:J:J4J''c(STTC$$$"DOt $$KKDHHX.{KC$''(BCC 	&rA   c                     t        d|       S )z9dict parsing helper -- creates preformatted error messagezInvalid totp data: r   rY  s    r?   rp  zTOTP._dict_parse_error  s     V=>>rA   c                    t        | j                  d      }| j                  dk7  r| j                  |d<   | j                  dk7  r| j                  |d<   | j                  dk7  r| j                  |d<   | j
                  r| j
                  |d	<   | j                  }|r|t        |       j                  k7  r||d
<   || j                  }|xr |j                  }|r| j                  |d<   |S | j                  |d<   |S )aw  
        Serialize configuration & internal state to a dict,
        mainly useful for persisting client-specific state in a database.

        :param encrypt:
            Whether to output should be encrypted.

            * ``None`` (the default) -- uses encrypted key if application
              secrets are available, otherwise uses plaintext key.
            * ``True`` -- uses encrypted key, or raises TypeError
              if application secret wasn't provided to OTP constructor.
            * ``False`` -- uses raw key.

        :returns:
            dictionary, containing basic (json serializable) datatypes.
        rJ  )r   r   r   r   r7   r   r   r   r   r   r   rQ   )r   rv  r   r   r   r   r   r   r   r   r   r  )rx   r;  rm  r   r   s        r?   r<  zTOTP.to_dict  s    & t((v688v88E%L;;!"kkE(O;;""kkE(O::!ZZE'NfT
 1 11$E(O?[[F3!3!3G"00E(O   ??E%L
 rA   )NNNNNN)
NrW   FNNNNNNF)r   )rW   -rD   )Nr   r   N)NN)=r   r   r   r   r   ru  rv  r   _timer  r   r   r   r   r   r   r   r   r   r   classmethodr   r   r{   r   r   r   r   r   rQ   setterr   r  r  r	  r  r  r  r(   r  r  r  r-  r   r1  r,  r>  rE  rG  rQ  rD  rT  rc  r`  r?  rn  r=  rq  rp  r<  __classcell__)r   s   @r?   r/   r/     s   FZ M '('| F **C D N
 K F C E F
 F G
 15,0b bP % % )1EI27G!Z C C : : ; ;   	ZZ6 6   
( 
(  A A # # L Q Q6#%  Z!/F7D < <.`6D*"p ") ")N , ,, 	8 	8 .6 .6` ?C>B 0 A A I IK>Z	 1 1,
H  5 5.  < ? ?,rA   r/   c                   n    e Zd ZdZdZdZdZd Zed        Z	ed        Z
ed        Zed        Zd Zd	 Zy)
r0   a@  
    Object returned by :meth:`TOTP.generate`.
    It can be treated as a sequence of ``(token, expire_time)``,
    or accessed via the following attributes:

    .. autoattribute:: token
    .. autoattribute:: expire_time
    .. autoattribute:: counter
    .. autoattribute:: remaining
    .. autoattribute:: valid
    Nc                 .    || _         || _        || _        yzu
        .. warning::
            the constructor signature is an internal detail, and is subject to change.
        N)rJ  r  r  )rx   rJ  r  r  s       r?   r{   zTotpToken.__init__  s    
 	
rA   c                 L    | j                   j                  | j                        S )z9Timestamp marking beginning of period when token is validrJ  r  r  r   s    r?   
start_timezTotpToken.start_time  s     yy))$,,77rA   c                 R    | j                   j                  | j                  dz         S z3Timestamp marking end of period when token is validr   r  r   s    r?   r0  zTotpToken.expire_time  "     yy))$,,*:;;rA   c                 d    t        d| j                  | j                  j                         z
        S )z.number of (float) seconds before token expiresr   )rv   r0  rJ  r   r   s    r?   	remainingzTotpToken.remaining  s&     1d&&899rA   c                 ,    t        | j                        S )zwhether token is still valid)boolr  r   s    r?   validzTotpToken.valid  s     DNN##rA   c                 2    | j                   | j                  fS rD   )r  r0  r   s    r?   	_as_tuplezTotpToken._as_tuple  s    zz4++++rA   c                 Z    | j                   rdnd}d| j                  | j                  |fz  S )NrT   z expiredz'<TotpToken token='%s' expire_time=%d%s>)r  r  r0  )rx   expireds     r?   __repr__zTotpToken.__repr__  s0    "J8

D,,g67 	7rA   )r   r   r   r   rJ  r  r  r{   r)   r  r0  r   r  r  r  r  rE   rA   r?   r0   r0     s{    
 D E G 8 8 < < : : $ $,7rA   r0   c                       e Zd ZdZdZdZdZdZddZe	d        Z
e	d        Ze	d        Ze	d	        Ze	d
        Zd Zd Zy)r1   a  
    Object returned by :meth:`TOTP.match` and :meth:`TOTP.verify` on a successful match.

    It can be treated as a sequence of ``(counter, time)``,
    or accessed via the following attributes:

    .. autoattribute:: counter
        :annotation: = 0

    .. autoattribute:: time
        :annotation: = 0

    .. autoattribute:: expected_counter
        :annotation: = 0

    .. autoattribute:: skipped
        :annotation: = 0

    .. autoattribute:: expire_time
        :annotation: = 0

    .. autoattribute:: cache_seconds
        :annotation: = 60

    .. autoattribute:: cache_time
        :annotation: = 0

    This object will always have a ``True`` boolean value.
    Nr   r   c                 <    || _         || _        || _        || _        yr  )rJ  r  r  r/  )rx   rJ  r  r  r/  s        r?   r{   zTotpMatch.__init__&  s     
 		rA   c                 L    | j                   j                  | j                        S )z7
        Counter value expected for timestamp.
        )rJ  r  r  r   s    r?   expected_counterzTotpMatch.expected_counter0  s    
 yy))$))44rA   c                 4    | j                   | j                  z
  S )z
        How many steps were skipped between expected and actual matched counter
        value (may be positive, zero, or negative).
        )r  r  r   s    r?   skippedzTotpMatch.skipped7  s     ||d3333rA   c                 R    | j                   j                  | j                  dz         S r  r  r   s    r?   r0  zTotpMatch.expire_timeD  r  rA   c                 H    | j                   j                  | j                  z   S )z
        Number of seconds counter should be cached
        before it's guaranteed to have passed outside of verification window.
        )rJ  r   r/  r   s    r?   cache_secondszTotpMatch.cache_secondsI  s     yy$++--rA   c                 4    | j                   | j                  z   S )z[
        Timestamp marking when counter has passed outside of verification window.
        )r0  r/  r   s    r?   
cache_timezTotpMatch.cache_timeS  s    
 $++--rA   c                 2    | j                   | j                  fS rD   )r  r  r   s    r?   r  zTotpMatch._as_tupleZ  s    ||TYY&&rA   c                 R    | j                   | j                  | j                  f}d|z  S )Nz/<TotpMatch counter=%d time=%d cache_seconds=%d>)r  r  r  re  s     r?   r  zTotpMatch.__repr__]  s'    dii););<@4GGrA   )r   )r   r   r   r   rJ  r  r  r/  r{   r)   r  r  r0  r  r  r  r  rE   rA   r?   r1   r1     s    > D
 G D F 5 5 4 4 < < . . . .'HrA   r1      c                     | dkD  sJ t        |      dkD  sJ t        t        j                  | t        j                  dt        |            z              }t        t        ||      S )z
    generate a random string suitable for use as an
    :class:`AppWallet` application secret.

    :param entropy:
        number of bits of entropy (controls size/complexity of password).
    r   r   r2   )rJ   rm   mathceillogr   r   )entropycharsetcounts      r?   generate_secretr  e  sS     Q;w<!		'DHHQG$==>?Ec7E**rA   )rz  )hr   
__future__r   r   r   passlib.utils.compatr   r^   r  r   logging	getLoggerr   r  r  structsysr  r{  reurllib.parser   r   r	   r
   urllibwarningsr   cryptography.hazmat.backendsr   r   1cryptography.hazmat.primitives.ciphers.algorithmscryptography,cryptography.hazmat.primitives.ciphers.modescryptography.hazmat.primitivesr   r   ImportErrordebugpasslibr   passlib.excr   r   r   r   passlib.utilsr   r   r   r   r   r   r   r   passlib.utils.binaryr   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   passlib.utils.decorr(   r)   passlib.crypto.digestr*   r+   r,   passlib.hashr-   __all__version_infor5   ra  compileUr[   r:   r@   rM   rd   r  AES_SUPPORTr   objectr.   Structpackr%  unpackr'  r   r/   r0   r1   r  rE   rA   r?   <module>r     s   F A @ $    'g''1   
  	@@%, 	-S<7E
  Z ZT T T C CV V V @ H H &. g#
"
)$		HI BJJq}bdd+	&DI4 ; "**1
2Z" Z"J v}}T"'' t$++ 
p6 pr%87 87vfH fHX  cr): +M:  -IIMN(,,K%-s   /G   G>=G>