a fWcp@sdZddlmZmZmZmZddlZddlmZzddl m Z Wne y^ddlm Z Yn0ddl m Z mZddlZeeZddlZddlZddlmZddlmZmZmZmZdd lmZmZmZdd l m!Z!gd Z"e#d d ddddZ$ddZ%ddZ&d0ddZ'e(e)fZ*e+e,fZ-e+Z.d1ddZ/Gddde0Z1e#dddd d!Z2Gd"d#d#e1Z3d2d$d%Z4d&d'Z5Gd(d)d)e Z6e6Z7d*8D]Z9e7:e9d+e9qGd,d-d-e1Z;d3d.d/Z_z"_self_info_rate..)len TypeErrorrintvaluessumr r()sourcesizeZcountscharr0r$r$r%_self_info_rate>s    r5cCsZ|rt|t|Stj|r,t|dS|d\}}}|sNtd|ft ||S)a :param asset_path: string containing absolute path to file, or package-relative path using format ``"python.module:relative/file/path"``. :returns: filehandle opened in 'rb' mode (unless encoding explicitly specified) rb:zKasset path must be absolute file path or use 'pkg.name:sub/path' format: %r) codecs getreader_open_asset_pathospathisabsopen partition ValueError pkg_resourcesZresource_stream)r<encodingpackagesepZsubpathr$r$r%r:js   r:r2c Cst}d}z||vrWdSWnty0d}Yn0t|tsPtt|t|krz|rvz||WntytYn0dSt}t}|D]}||vr|n||qt|}d}t||krd}ddd|d|D}t||kr|d t||7}t d ||fdS) z helper for generators -- Throws ValueError if source elements aren't unique. Error message will display (abbreviated) repr of the duplicates in a string/list TF, css|]}tt|VqdSN)reprstrr)Zwordr$r$r%r+r,z!_ensure_unique..Nz, ... plus %d othersz*`%s` cannot contain duplicate elements: %s) _ensure_unique_cacher. isinstance _set_typesr-setaddsortedjoinr@) r2paramcacheZhashableseenZdupselemZtruncZdup_reprr$r$r%_ensure_uniques8      rWcspeZdZdZdZdZeZdZdfdd Ze ddZ e dd Z d d Z dd d Z ddZerhddZZS)SequenceGeneratoraY Base class used by word & phrase generators. These objects take a series of options, corresponding to those of the :func:`generate` function. They act as callables which can be used to generate a password or a list of 1+ passwords. They also expose some read-only informational attributes. Parameters ---------- :param entropy: Optionally specify the amount of entropy the resulting passwords should contain (as measured with respect to the generator itself). This will be used to auto-calculate the required password size. :param length: Optionally specify the length of password to generate, measured as count of whatever symbols the subclass uses (characters or words). Note if ``entropy`` requires a larger minimum length, that will be used instead. :param rng: Optionally provide a custom RNG source to use. Should be an instance of :class:`random.Random`, defaults to :class:`random.SystemRandom`. Attributes ---------- .. autoattribute:: length .. autoattribute:: symbol_count .. autoattribute:: entropy_per_symbol .. autoattribute:: entropy Subclassing ----------- Subclasses must implement the ``.__next__()`` method, and set ``.symbol_count`` before calling base ``__init__`` method. Nrc s|jdusJd|dus"|durr|dur0|j}t||}|dkrLtdtt||j}|dusn||krr|}||_|dkrtd||_|dur||_ |rt |t t fkrt dd|tt |jfi|dS)Nzsubclass must set .symbol_countrz!`entropy` must be positive numberrz!`length` must be positive integerzUnexpected keyword(s): %srG) symbol_countrequested_entropyentropy_aliasesgetr@r/rentropy_per_symbollengthrr&rXobjectr.rRkeyssuper__init__)selfentropyr^rkwdsZ min_length __class__r$r%rbs& zSequenceGenerator.__init__cCs t|jdS)zZ Average entropy per symbol (assuming all symbols have equal probability) r')r(rYrcr$r$r%r]sz$SequenceGenerator.entropy_per_symbolcCs |j|jS)a+ Effective entropy of generated passwords. This value will always be a multiple of :attr:`entropy_per_symbol`. If entropy is specified in constructor, :attr:`length` will be chosen so so that this value is the smallest multiple >= :attr:`requested_entropy`. )r^r]rhr$r$r%rds zSequenceGenerator.entropycCs tddS)z;main generation function, should create one password/phrasezimplement in subclassN)NotImplementedErrorrhr$r$r%__next__)szSequenceGenerator.__next__csN|durtSt|tr0fddt|DS|tur<St|dddS)zN frontend used by genword() / genphrase() to create passwords Ncsg|] }tqSr$)nextr)_rhr$r% 4r,z.SequenceGenerator.__call__..z, int, or returns)rkrMrr iterr ZExpectedTypeError)rcror$rhr%__call__-s zSequenceGenerator.__call__cCs|SrHr$rhr$r$r%__iter__:szSequenceGenerator.__iter__cCs|SrH)rjrhr$r$r%rk>szSequenceGenerator.next)NNN)N)__name__ __module__ __qualname____doc__r^rZrrYrbrr]rdrjrqrrr rk __classcell__r$r$rfr%rXs,#   rXzH0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*?/Z>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZZ2234679abcdefghjkmnpqrstuvwxyzACDEFGHJKMNPQRTUVWXYZZ0123456789abcdef)Zascii_72ascii_62Zascii_50hexcs>eZdZdZdZdZd fdd ZeddZdd Z Z S) WordGeneratora Class which generates passwords by randomly choosing from a string of unique characters. Parameters ---------- :param chars: custom character string to draw from. :param charset: predefined charset to draw from. :param \*\*kwds: all other keywords passed to the :class:`SequenceGenerator` parent class. Attributes ---------- .. autoattribute:: chars .. autoattribute:: charset .. autoattribute:: default_charsets rxNc sj|r|r,tdn|s$|j}|s$Jt|}||_t|dd}t|dd||_tt|jfi|dS)Nz,`chars` and `charset` are mutually exclusivecharsrS) r.charsetrrrWr{rarzrb)rcr{r}rerfr$r%rb~s   zWordGenerator.__init__cCs t|jSrH)r-r{rhr$r$r%rYszWordGenerator.symbol_countcCst|j|j|jSrH)rrr{r^rhr$r$r%rjszWordGenerator.__next__)NN) rsrtrurvr}r{rbrrYrjrwr$r$rfr%rz\s rzcKstf||d|}||S)a Generate one or more random passwords. This function uses :mod:`random.SystemRandom` to generate one or more passwords using various character sets. The complexity of the password can be specified by size, or by the desired amount of entropy. Usage Example:: >>> # generate a random alphanumeric string with 48 bits of entropy (the default) >>> from passlib import pwd >>> pwd.genword() 'DnBHvDjMK6' >>> # generate a random hexadecimal string with 52 bits of entropy >>> pwd.genword(entropy=52, charset="hex") '310f1a7ac793f' :param entropy: Strength of resulting password, measured in 'guessing entropy' bits. An appropriate **length** value will be calculated based on the requested entropy amount, and the size of the character set. This can be a positive integer, or one of the following preset strings: ``"weak"`` (24), ``"fair"`` (36), ``"strong"`` (48), and ``"secure"`` (56). If neither this or **length** is specified, **entropy** will default to ``"strong"`` (48). :param length: Size of resulting password, measured in characters. If omitted, the size is auto-calculated based on the **entropy** parameter. If both **entropy** and **length** are specified, the stronger value will be used. :param returns: Controls what this function returns: * If ``None`` (the default), this function will generate a single password. * If an integer, this function will return a list containing that many passwords. * If the ``iter`` constant, will return an iterator that yields passwords. :param chars: Optionally specify custom string of characters to use when randomly generating a password. This option cannot be combined with **charset**. :param charset: The predefined character set to draw from (if not specified by **chars**). There are currently four presets available: * ``"ascii_62"`` (the default) -- all digits and ascii upper & lowercase letters. Provides ~5.95 entropy per character. * ``"ascii_50"`` -- subset which excludes visually similar characters (``1IiLl0Oo5S8B``). Provides ~5.64 entropy per character. * ``"ascii_72"`` -- all digits and ascii upper & lowercase letters, as well as some punctuation. Provides ~6.17 entropy per character. * ``"hex"`` -- Lower case hexadecimal. Providers 4 bits of entropy per character. :returns: :class:`!unicode` string containing randomly generated password; or list of 1+ passwords if :samp:`returns={int}` is specified. )r^rd)rzrdr^roregenr$r$r%rsFrcCs`t|d0}dd|D}tdd|D}Wdn1s@0Ytdt|||S)a2 load wordset from compressed datafile within package data. file should be utf-8 encoded :param asset_path: string containing absolute path to wordset file, or "python.module:relative/file/path". :returns: tuple of words, as loaded from specified words file. zutf-8css|]}|VqdSrH)striprKr$r$r%r+r,z _load_wordset..css|]}|r|VqdSrHr$rKr$r$r%r+r,Nz!loaded %d-element wordset from %r)r:tupler debugr-)Z asset_pathZfhrwordsr$r$r% _load_wordsets 0rcsleZdZdZdZdZfddZddZddZd d Z d d Z e d dZ ddZ ddZddZZS) WordsetDictz Special mapping used to store dictionary of wordsets. Different from a regular dict in that some wordsets may be lazy-loaded from an asset path. Ncs&i|_i|_tt|j|i|dSrH)paths_loadedrarrb)rcargsrerfr$r%rb%szWordsetDict.__init__cCs@z |j|WStyYn0|j|}t|}|j|<|SrH)rKeyErrorrr)rckeyr<r*r$r$r% __getitem__*s   zWordsetDict.__getitem__cCs||j|<dS)z; set asset path to lazy-load wordset from. N)r)rcrr<r$r$r%set_path3szWordsetDict.set_pathcCs||j|<dSrH)r)rcrr*r$r$r% __setitem__9szWordsetDict.__setitem__cCs,||vr |j|=|j|dn|j|=dSrH)rrpoprcrr$r$r% __delitem__<szWordsetDict.__delitem__cCst|j}||j|SrH)rOrupdater)rcr`r$r$r%_keysetCs  zWordsetDict._keysetcCs t|jSrH)rprrhr$r$r%rrIszWordsetDict.__iter__cCs t|jSrH)r-rrhr$r$r%__len__LszWordsetDict.__len__cCs||jvp||jvSrH)rrrr$r$r% __contains__PszWordsetDict.__contains__)rsrtrurvrrrbrrrrpropertyrrrrrrwr$r$rfr%rs   rz%eff_long eff_short eff_prefixed bip39zpasslib:_data/wordsets/%s.txtcsBeZdZdZdZdZdZd fdd ZeddZ d d Z Z S) PhraseGeneratoraclass which generates passphrases by randomly choosing from a list of unique words. :param wordset: wordset to draw from. :param preset: name of preset wordlist to use instead of ``wordset``. :param spaces: whether to insert spaces between words in output (defaults to ``True``). :param \*\*kwds: all other keywords passed to the :class:`SequenceGenerator` parent class. .. autoattribute:: wordset Zeff_longN c s|dur|dur8tdn|dur0|j}|s0Jt|}||_t|tsPt|}t|dd||_|durp|j}t |dd}||_t t |j fi|dS)Nz,`words` and `wordset` are mutually exclusiverr|rD) r.wordsetrrM_sequence_typesrrWrrDrrarrb)rcrrrDrerfr$r%rb~s"    zPhraseGenerator.__init__cCs t|jSrH)r-rrhr$r$r%rYszPhraseGenerator.symbol_countcs$fddtjD}j|S)Nc3s|]}jjVqdSrH)rchoicerrlrhr$r%r+r,z+PhraseGenerator.__next__..)r r^rDrR)rcrr$rhr%rjszPhraseGenerator.__next__)NNN) rsrtrurvrrrDrbrrYrjrwr$r$rfr%r_s" rcKstf||d|}||S)amGenerate one or more random password / passphrases. This function uses :mod:`random.SystemRandom` to generate one or more passwords; it can be configured to generate alphanumeric passwords, or full english phrases. The complexity of the password can be specified by size, or by the desired amount of entropy. Usage Example:: >>> # generate random phrase with 48 bits of entropy >>> from passlib import pwd >>> pwd.genphrase() 'gangly robbing salt shove' >>> # generate a random phrase with 52 bits of entropy >>> # using a particular wordset >>> pwd.genword(entropy=52, wordset="bip39") 'wheat dilemma reward rescue diary' :param entropy: Strength of resulting password, measured in 'guessing entropy' bits. An appropriate **length** value will be calculated based on the requested entropy amount, and the size of the word set. This can be a positive integer, or one of the following preset strings: ``"weak"`` (24), ``"fair"`` (36), ``"strong"`` (48), and ``"secure"`` (56). If neither this or **length** is specified, **entropy** will default to ``"strong"`` (48). :param length: Length of resulting password, measured in words. If omitted, the size is auto-calculated based on the **entropy** parameter. If both **entropy** and **length** are specified, the stronger value will be used. :param returns: Controls what this function returns: * If ``None`` (the default), this function will generate a single password. * If an integer, this function will return a list containing that many passwords. * If the ``iter`` builtin, will return an iterator that yields passwords. :param words: Optionally specifies a list/set of words to use when randomly generating a passphrase. This option cannot be combined with **wordset**. :param wordset: The predefined word set to draw from (if not specified by **words**). There are currently four presets available: ``"eff_long"`` (the default) Wordset containing 7776 english words of ~7 letters. Constructed by the EFF, it offers ~12.9 bits of entropy per word. This wordset (and the other ``"eff_"`` wordsets) were `created by the EFF `_ to aid in generating passwords. See their announcement page for more details about the design & properties of these wordsets. ``"eff_short"`` Wordset containing 1296 english words of ~4.5 letters. Constructed by the EFF, it offers ~10.3 bits of entropy per word. ``"eff_prefixed"`` Wordset containing 1296 english words of ~8 letters, selected so that they each have a unique 3-character prefix. Constructed by the EFF, it offers ~10.3 bits of entropy per word. ``"bip39"`` Wordset of 2048 english words of ~5 letters, selected so that they each have a unique 4-character prefix. Published as part of Bitcoin's `BIP 39 `_, this wordset has exactly 11 bits of entropy per word. This list offers words that are typically shorter than ``"eff_long"`` (at the cost of slightly less entropy); and much shorter than ``"eff_prefixed"`` (at the cost of a longer unique prefix). :param sep: Optional separator to use when joining words. Defaults to ``" "`` (a space), but can be an empty string, a hyphen, etc. :returns: :class:`!unicode` string containing randomly generated passphrase; or list of 1+ passphrases if :samp:`returns={int}` is specified. )rdr^)rr~r$r$r%rsar)N)r2)NNN)NNN)=rvZ __future__rrrrr8 collectionsrcollections.abcr ImportErrorZmathrr r(ZloggingZ getLoggerrsrAr;Zpasslibr Zpasslib.utils.compatr r r rZ passlib.utilsrrrZpasslib.utils.decorr__all__dictr[r&r5r:listrrrO frozensetrNrLrWr_rXrrzrrrrsplitnamerrrr$r$r$r%s^     ,  .L M#> R