a fWc@sFdZddlmZddlmZmZmZddlm Z m Z zddl m Z ddl m Z Wn*eyzddlm Z ddlm Z Yn0ddlmZddlmZdd lZdd lZdd lZeeZdd lZdd lZdd lZdd lZdd lZerz dd l Z Wney d Z d Z!Yn0ndd l Z dd l"Z"e r.dd l#Z#z dd l$Z$WneyRd Z$Yn0dd l%Z%dd l&Z&dd l'm(Z(dd l)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6dd l7m8Z8m9Z9m:Z:m;Z;mZ>m?Z?ddlm@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPgdZQeReeFr>ejSnejTddZUgdZVddgZWddl=mXZXdZYeGdZZeGdZ[eRej\]dpdZ^Gddde_Z`eFrejajbZcedecejajegZfddZgnd dZgdd"d#Zhd$d%Zid&d'ZjejZkzdd(llmmZjWneyYn0dd*d+Zndd-d.Zoe d ur@dd/d.Zod0d1ZpeFr`d2d3Zqd4d5Zrn dd6lmsZsmtZtd7d3Zqd8d5Zre@eqd9e@erd:d;d<Zud=d>Zvd?d@ZwdAZxeGdBZyddCdDZzdEdFZ{dGZ|e|}dHZ~dIdJZdKdLZdMZeGdNZdOdPZddRdSZddTdUZeFr"ddVdWZn ddXdWZe@edYe8dZd[d\dd]d^Zedd_Zedd`ZedddagZddcddZdedfZzddglmZWn0eyd Zd!Zd!Zd!Zd ZdhdiZYn0djZdBZe$rePrdkejkrdlkrnne$ZdjZnddmlmZeZd!ZeGdnZeFrhdjZzedodpWn"eyRd!ZYn Yn0dqdiZn djZdrdiZe@edsdtduZe%jZeZdvdwZzedxdjZWneyd!ZYn0ddydzZereZn eeZd{d|Zd}d~ZdZe8d[ddddefddZdZddZdZddZddZddZd S)z4passlib.utils -- helpers for writing password hashes)JYTHON) b2a_base64 a2b_base64Error) b64encode b64decode)Sequence)Iterable)lookup)update_wrapperNznot present under Jython)warn) BASE64_CHARS AB64_CHARS HASH64_CHARS BCRYPT_CHARS Base64EngineLazyBase64Engineh64h64bigbcrypt64 ab64_encode ab64_decode b64s_encode b64s_decode)deprecated_functiondeprecated_methodmemoized_property classproperty hybrid_method)ExpectedStringErrorExpectedTypeError)add_doc join_bytesjoin_byte_valuesjoin_byte_elemsirangeimapPY3u join_unicodeunicodebyte_elem_value nextgetterunicode_or_strunicode_or_bytes_typesget_method_functionsuppress_causePYPY)rsys_bitsunix_crypt_schemesrounds_cost_valuesconsteqsaslprep xor_bytes render_bytes is_same_codec is_ascii_safeto_bytes to_unicode to_native_str has_crypt test_crypt safe_crypttickrng getrandbytes getrandstrgenerate_passwordis_crypt_handleris_crypt_contexthas_rounds_info has_salt_infog?)Z sha512_cryptZ sha256_cryptZ sha1_cryptZbcryptZ md5_cryptZ bsdi_cryptZ des_cryptZlinearZlog2)MissingBackendError ZPASSLIB_MAX_PASSWORD_SIZEic@sHeZdZdZddZddZddZdd Zd d Zd d Z ddZ dS) SequenceMixinz helper which lets result object act like a fixed-length sequence. subclass just needs to provide :meth:`_as_tuple()`. cCs tddS)Nzimplement in subclass)NotImplementedErrorselfrS:/usr/lib/python3.9/site-packages/passlib/utils/__init__.py _as_tupleszSequenceMixin._as_tuplecCs t|SN)reprrUrQrSrSrT__repr__szSequenceMixin.__repr__cCs ||SrVrU)rRidxrSrSrT __getitem__szSequenceMixin.__getitem__cCs t|SrV)iterrUrQrSrSrT__iter__szSequenceMixin.__iter__cCs t|SrV)lenrUrQrSrSrT__len__szSequenceMixin.__len__cCs ||kSrVrYrRotherrSrSrT__eq__szSequenceMixin.__eq__cCs || SrV)rbr`rSrSrT__ne__szSequenceMixin.__ne__N) __name__ __module__ __qualname____doc__rUrXr[r]r_rbrcrSrSrSrTrOsrOcCsJtt|j}|sdS||}|r4|jtvr4dS|t|djtkS)*test if function accepts specified keywordFT) inspectZ signaturer/ parametersgetkind _VAR_ANY_SETlist _VAR_KEYWORD)funckeyparamsargrSrSrTaccepts_keywords rucCs"tt|}||jvp |jduS)rhN)rjZ getargspecr/argskeywords)rqrrspecrSrSrTrusFc s8t|tr|g}t|j}|rXt|tr.|g}|D]$|rD|vrDq2|vr2|q2|r$|D]tfdd|Dr~qb|rt|D](\}} t| rq|rt| |rqqt|}nX|rtt |D]:\} } t| |rt|| }||d| ksJqqd}nd}| |qb|s4t ||_dS)a helper to update mixin classes installed in target class. :param target: target class whose bases will be modified. :param add: class / classes to install into target's base class list. :param remove: class / classes to remove from target's base class list. :param append: by default, prepends mixins to front of list. if True, appends to end of list instead. :param after: optionally make sure all mixins are inserted after this class / classes. :param before: optionally make sure all mixins are inserted before this class / classes. :param dryrun: optionally perform all calculations / raise errors, but don't actually modify the class. c3s|]}t|VqdSrV) issubclass).0baseZmixinrSrT rLz'update_mixin_classes..rN) isinstancetypero __bases__removeany enumerateryr^reversedinserttuple) targetaddrappendbeforeZafterZdryrunbasesrZr{Zend_idxrSr|rTupdate_mixin_classessB         rccs|dkrtdt|trLt|}d}||kr||}|||V|}q&n^t|trt|}t||}z t|}Wnt yYqYn0t |f|Vq^nt ddS)z8 split iterable into chunks of elements. r~zsize must be positive integerrzsource must be iterableN) ValueErrorrrr^r r\ itertoolsislicenext StopIterationchain TypeError)sourcesizeendinitrZ chunk_itrfirstrSrSrTbatchs$      rcCst|tr"t|tstdd}n*t|trDt|ts>tdt}ntdt|t|k}|rh|}d}|st|}d}|rt||D]\}}|||AO}qn(t||D]\}}|t|t|AO}q|dkS)aCheck two strings/bytes for equality. This function uses an approach designed to prevent timing analysis, making it appropriate for cryptography. a and b must both be of the same type: either str (ASCII only), or any type that supports the buffer protocol (e.g. bytes). Note: If a and b are of different lengths, or if an error occurs, a timing attack could theoretically reveal information about the types and lengths of a and b--but not their values. z)inputs must be both unicode or both bytesFrr~)rr*rbytesr'r^zipord)leftrightZ is_py3_bytesZ same_sizetmpresultlrrSrSrTr5;s,    r5)compare_digest,cCs:|}||r|dd}|s&gSdd||DS)zRsplit comma-separated string into list of elements, stripping whitespace. NricSsg|] }|qSrS)striprzelemrSrSrT rLzsplitcomma..)rendswithsplit)rseprSrSrT splitcommas   rvaluecst|tstdt|ftjtjtfdd|D}t d|}|sTt Stj }||dr||ds~t d|tj }n|}tj}tj}tj}tj}tj} tj} tj} tj} tj} |D]}|rJd|rJd ||rt d |||rt d |||r(t d |||r>t d || |rTt d|| |rjt d|| |rt d|| |rt d|| |rt d|||rt d|q|S)aNormalizes unicode strings using SASLPrep stringprep profile. The SASLPrep profile is defined in :rfc:`4013`. It provides a uniform scheme for normalizing unicode usernames and passwords before performing byte-value sensitive operations such as hashing. Among other things, it normalizes diacritic representations, removes non-printing characters, and forbids invalid characters such as ``\n``. Properly internationalized applications should run user passwords through this function before hashing. :arg source: unicode string to normalize & validate :param param: Optional noun identifying source parameter in error messages (Defaults to the string ``"value"``). This is mainly useful to make the caller's error messages make more sense contextually. :raises ValueError: if any characters forbidden by the SASLPrep profile are encountered. :raises TypeError: if input is not :class:`!unicode` :returns: normalized unicode string .. note:: This function is not available under Jython, as the Jython stdlib is missing the :mod:`!stringprep` module (`Jython issue 1758320 `_). .. versionadded:: 1.6 z$input must be unicode string, not %sc3s&|]}|s|rtn|VqdSrV)_USPACErzc in_table_b1 in_table_c12rSrTr}szsaslprep..NFKCrrizmalformed bidi sequence in z$failed to strip B.1 in mapping stagez(failed to replace C.1.2 in mapping stagez$unassigned code points forbidden in z control characters forbidden in z$private use characters forbidden in z"non-char code points forbidden in zsurrogate codes forbidden in z!non-plaintext chars forbidden in z!non-canonical chars forbidden in z1display-modifying / deprecated chars forbidden inztagged characters forbidden in zforbidden bidi character in )rr*rr stringpreprrr) unicodedata normalize_UEMPTYZ in_table_d1rZ in_table_d2 in_table_a1in_table_c21_c22 in_table_c3 in_table_c4 in_table_c5 in_table_c6 in_table_c7 in_table_c8 in_table_c9)rparamdataZ is_ral_charZis_forbidden_bidi_charrrrrrrrrrrrSrrTr6sj,                      r6cCstdtdS)zstub for saslprep()z>saslprep() support requires the 'stringprep' module, which is N)rP_stringprep_missing_reason)rrrSrSrTr6scGs4t|tr|d}|tdd|D}|dS)aPeform ``%`` formating using bytes in a uniform manner across Python 2/3. This function is motivated by the fact that :class:`bytes` instances do not support ``%`` or ``{}`` formatting under Python 3. This function is an attempt to provide a replacement: it converts everything to unicode (decoding bytes instances as ``latin-1``), performs the required formatting, then encodes the result to ``latin-1``. Calling ``render_bytes(source, *args)`` should function roughly the same as ``source % args`` under Python 2. .. todo:: python >= 3.5 added back limited support for bytes %, can revisit when 3.3/3.4 is dropped. latin-1css&|]}t|tr|dn|VqdS)rN)rrdecode)rzrtrSrSrTr},szrender_bytes..)rrrrencode)rrvrrSrSrTr8s     r8cCs t|dSNZbig)int from_bytesrrSrSrT bytes_to_int2srcCs ||dSr)r;rcountrSrSrT int_to_bytes4sr)hexlify unhexlifycCstt|dS)N)rrrrSrSrTr9scCstd|d>|S)Nz%%0%dxr~)rrrSrSrTr;sz/decode byte string as single big-endian integerz/encode integer as single big-endian byte stringcCstt|t|At|S)z;Perform bitwise-xor of two byte strings (must be same size))rrr^rrrSrSrTr7Asr7cCs$d|dt|}||d|S)zE repeat or truncate string, so it has length r~N)r^rrZmultrSrSrT repeat_stringEsrcCs"d|dt|}t|||S)zN variant of repeat_string() which truncates to nearest UTF8 boundary. r~)r^ utf8_truncaterrSrSrTutf8_repeat_stringMsrcCsJt|}||kr:|dur*t|tr&tnt}||||S|d|SdS)z>right-pad or truncate string, so it has length N)r^rr*_UNULL_BNULL)rrZpadZcurrSrSrTright_pad_stringXs rcsttsttdt}|dkr4td||}||kr@St|d|}||krvt|d@dkrlq|d7}qN||ksJd|fdd }|sJS) a helper to truncate UTF8 byte string to nearest character boundary ON OR AFTER . returned prefix will always have length of at least , and will stop on the first byte that's not a UTF8 continuation byte (128 - 191 inclusive). since utf8 should never take more than 4 bytes to encode known unicode values, we can stop after ``index+3`` is reached. :param bytes source: :param int index: :rtype: bytes rrr~Ncs<zd}Wnty"YdS0|ds8JdS)Nutf-8T)rUnicodeDecodeError startswith)textrrrSrT sanity_checks  z#utf8_truncate..sanity_check)rrr r^maxminr+)rindexrrrSrrTrcs"      rs aA:#!asciicCst|tkS)zRTest if codec is compatible with 7-bit ascii (e.g. latin-1, utf-8; but not utf-16))_ASCII_TEST_UNICODEr_ASCII_TEST_BYTES)codecrSrSrTis_ascii_codecsrcCs,||kr dS|r|sdSt|jt|jkS)z3Check if two codec names are aliases for same codecTF) _lookup_codecnamerrSrSrTr9s r9r€cs(t|trtnttfdd|DS)z.)rr_B80_U80all)rrSrrTr:sr:rcCsX|sJt|tr6|r0t||s0|||S|Snt|trJ||St||dS)aHelper to normalize input to bytes. :arg source: Source bytes/unicode to process. :arg encoding: Target encoding (defaults to ``"utf-8"``). :param param: Optional name of variable/noun to reference when raising errors :param source_encoding: If this is specified, and the source is bytes, the source will be transcoded from *source_encoding* to *encoding* (via unicode). :raises TypeError: if source is not unicode or bytes. :returns: * unicode strings will be encoded using *encoding*, and returned. * if *source_encoding* is not specified, byte strings will be returned unchanged. * if *source_encoding* is specified, byte strings will be transcoded to *encoding*. N)rrr9rrr*r)rencodingrZsource_encodingrSrSrTr;s   r;cCs8|sJt|tr|St|tr*||St||dS)aHelper to normalize input to unicode. :arg source: source bytes/unicode to process. :arg encoding: encoding to use when decoding bytes instances. :param param: optional name of variable/noun to reference when raising errors. :raises TypeError: if source is not unicode or bytes. :returns: * returns unicode strings unchanged. * returns bytes strings decoded using *encoding* N)rr*rrrrrrrSrSrTr<s    r<cCs0t|tr||St|tr"|St||dSrV)rrrr*rrrSrSrTr=s    r=cCs0t|tr|St|tr"||St||dSrV)rrr*rrrrSrSrTr=s    a>Take in unicode or bytes, return native string. Python 2: encodes unicode using specified encoding, leaves bytes alone. Python 3: leaves unicode alone, decodes bytes using specified encoding. :raises TypeError: if source is not unicode or bytes. :arg source: source unicode or bytes string. :arg encoding: encoding to use when encoding unicode or decoding bytes. this defaults to ``"utf-8"``. :param param: optional name of variable/noun to reference when raising errors. :returns: :class:`str` instance z1.6z1.7) deprecatedremovedcCst||ddS)z'deprecated, use to_native_str() insteadhash)r)r=)rrrSrSrT to_hash_str$srz true t yes y on 1 enable enabledz#false f no n off 0 disable disablednonebooleancCs~|dvs Jt|trX|}|tvr.dS|tvr:dS|tvrF|Std||fn"t|trf|S|durr|St|SdS)z\ helper to convert value to boolean. recognizes strings such as "true", "false" )TFNTFzunrecognized %s value: %rN) rr.lowerr _true_set _false_set _none_setrbool)rrrZcleanrSrSrTas_bool-s    rcCs<tst|tsdSz|dWdSty6YdS0dS)z UT helper -- test if value is safe to pass to crypt.crypt(); under PY3, can't pass non-UTF8 bytes to crypt.crypt. TrFN)crypt_accepts_bytesrrrrrrSrSrTis_safe_crypt_inputGs  r)cryptcCsdSrVrSsecretrrSrSrTr@]sr@T)rJr)r rr) nullcontextz*:!xxcCs$tr>t|tr|d}t|vr(tdt|tr|d}nlt|tr|}z|d}WntynYdS0|d|ksJdt |vrtdt|tr|d}z2t t ||}Wdn1s0YWnt yYdS0t|tr|d}|r|dt vr dS|S)Nrnull character in secretrz"utf-8 spec says this can't happen!r)rrr*rrrrrr_NULL_safe_crypt_lock_cryptOSError_invalid_prefixes)r rZorigrrSrSrTr@s<        ,   cCst|tr|d}t|vr$tdt|tr8|d}tt||}Wdn1s\0Y|sndS|d}|dtvrdS|S)Nrrrr) rr*rrrrrrr)r rrrSrSrTr@s    (  aWrapper around stdlib's crypt. This is a wrapper around stdlib's :func:`!crypt.crypt`, which attempts to provide uniform behavior across Python 2 and 3. :arg secret: password, as bytes or unicode (unicode will be encoded as ``utf-8``). :arg hash: hash or config string, as ascii bytes or unicode. :returns: resulting hash as ascii unicode; or ``None`` if the password couldn't be hashed due to one of the issues: * :func:`crypt()` not available on platform. * Under Python 3, if *secret* is specified as bytes, it must be use ``utf-8`` or it can't be passed to :func:`crypt()`. * Some OSes will return ``None`` if they don't recognize the algorithm being used (though most will simply fall back to des-crypt). * Some OSes will return an error string if the input config is recognized but malformed; current code converts these to ``None`` as well. cCs4t|tsJdt||s&Jdt|||kS)zcheck if :func:`crypt.crypt` supports specific hash :arg secret: password to test :arg hash: known hash of password to use as reference :returns: True or False z#hash must be unicode_or_str, got %szhash must be non-empty)rr-rr@r rSrSrTr?s   r?cCs2td|}|r.tdd|ddDSdS)zhelper to parse version stringz(\d+(?:\.\d+)+)css|]}t|VqdSrV)rrrSrSrTr}rLz parse_version..r~.N)researchrgroupr)rmrSrSrT parse_versions rr~c Csddlm}t|drJt|drJz |}WntyH|d}Yn0td|ttdrdtndt t t t t rtd d ndf}t||d d S) z.generate prng seed value from system resourcesr)sha512getstate getrandbitsiz%s %s %s %.15f %.15f %sgetpidN rrr)ZhashlibrhasattrrrPrr(osridobjecttimerA has_urandomurandomrrr hexdigest)rrrrSrSrTgenseeds   r(cs stSfdd}t|S)z]return byte-string containing *count* number of randomly generated bytes, using specified rngc3s:d>}d}|kr6|d@V|dL}|d7}qdS)Nrrr~)rrrrrBrSrThelperMs  zgetrandbytes..helper)_BEMPTYr#)rBrr,rSr+rTrCBs rCcsldkrtdtdkr(tddkr8Sfdd}ttr^t|St|SdS)z|return string containing *count* number of chars/bytes, whose elements are drawn from specified charset, using specified rngrzcount must be >= 0zalphabet must not be emptyr~c3s@d}d}|kr<|V|}|d7}qdS)Nrr~)Z randranger*charsetrZlettersrBrSrTr,fs zgetrandstr..helperN)rr^rr*r)r$)rBr/rr,rSr.rTrDWs  rDZ42346789ABCDEFGHJKMNPQRTUVWXYZabcdefghjkmnpqrstuvwxyzz2.0z/passlib.pwd.genword() / passlib.pwd.genphrase())rrZ replacement cCs tt||S)awgenerate random password using given length & charset :param size: size of password. :param charset: optional string specified set of characters to draw from. the default charset contains all normal alphanumeric characters, except for the characters ``1IiLl0OoS5``, which were omitted due to their visual similarity. :returns: :class:`!str` containing randomly generated password. .. note:: Using the default character set, on a OS with :class:`!SystemRandom` support, this function should generate passwords with 5.7 bits of entropy per character. )rDrB)rr/rSrSrTrEvsrE)r setting_kwdsZ context_kwdsverifyridentifycstfddtDS)z4check if object follows the :ref:`password-hash-api`c3s|]}t|VqdSrVr rzrobjrSrTr}rLz#is_crypt_handler..)r_handler_attrsr6rSr6rTrFsrF)Z needs_updateZ genconfigZgenhashr2Zencryptr3cstfddtDS)zOcheck if object appears to be a :class:`~passlib.context.CryptContext` instancec3s|]}t|VqdSrVr4r5r6rSrTr}rLz#is_crypt_context..)r_context_attrsr6rSr6rTrGsrGcCsd|jvot|ddduS)z_check if handler provides the optional :ref:`rounds information ` attributesroundsZ min_roundsNr1getattrZhandlerrSrSrTrHs rHcCsd|jvot|ddduS)z[check if handler provides the optional :ref:`salt information ` attributesZsaltZ min_salt_sizeNr;r=rSrSrTrIs rI)NNFNNF)r)r)r)N)rrN)rr)rr)rr)r)Nr)N)rgZpasslib.utils.compatrZbinasciirrrZ_BinAsciiErrorbase64rrcollections.abcrr ImportError collectionscodecsr r functoolsr rrjZloggingZ getLoggerrdlogZmathr!sysZrandomrrrr$r threadingZtimeittypeswarningsr Zpasslib.utils.binaryr rrrrrrrrrrrrZpasslib.utils.decorrrrrrZ passlib.excrr r!r"r#r$r%r&r'r(r)r*r+r,r-r.r/r0r1__all__rmaxsizeZmaxintr2r3r4rKr-rrenvironrlZMAX_PASSWORD_SIZEr#rOZ ParameterZ VAR_KEYWORDrpsetZVAR_POSITIONALrnrurrr5Z str_consteqZhmacrrr6r8rrrrr7rrrrrrrrrrr9rrr:r;r<r=rrrrrrrrrr>rZcrypt_needs_lockrr@rZpypy_version_infoLockr rrr?Z default_timerZtimerrArr&r%rPr(Z SystemRandomrBZRandomrCrDZ _52charsetrEr8rFr9rGrHrIrSrSrSrTsH           <L."    W>       F  %         *  /    !